diff options
author | Christoph Bumiller <e0425955@student.tuwien.ac.at> | 2010-09-02 18:31:49 +0200 |
---|---|---|
committer | Christoph Bumiller <e0425955@student.tuwien.ac.at> | 2010-09-02 18:31:49 +0200 |
commit | 222d2f2ac2c7d93cbc0643082c78278ad2c8cfce (patch) | |
tree | b79152c238022b2a901201c22e5809ac520732bf /src | |
parent | 443abc80db9e1a288ce770e76cccd43664348098 (diff) | |
parent | e73c5501b2fe20290d1b691c85a5d82ac3a0431c (diff) |
Merge remote branch 'origin/master' into nv50-compiler
Conflicts:
src/gallium/drivers/nv50/nv50_program.c
Diffstat (limited to 'src')
1047 files changed, 115776 insertions, 47945 deletions
diff --git a/src/SConscript b/src/SConscript index 2b46186f98..c3e34be6f7 100644 --- a/src/SConscript +++ b/src/SConscript @@ -5,6 +5,9 @@ if 'egl' in env['statetrackers']: SConscript('egl/main/SConscript') if 'mesa' in env['statetrackers']: + if platform == 'windows': + SConscript('talloc/SConscript') + SConscript('glsl/SConscript') SConscript('mapi/glapi/SConscript') SConscript('mesa/SConscript') diff --git a/src/egl/docs/EGL_MESA_screen_surface b/src/egl/docs/EGL_MESA_screen_surface index 6beb4ce88e..698a240578 100644 --- a/src/egl/docs/EGL_MESA_screen_surface +++ b/src/egl/docs/EGL_MESA_screen_surface @@ -14,7 +14,7 @@ Contact Status - Preliminary - totally subject to change. + Obsolete. Version diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index efb93bcf06..2b78bcc763 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -836,6 +836,7 @@ dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp, goto cleanup_configs; } + disp->Extensions.MESA_drm_image = EGL_TRUE; disp->Extensions.KHR_image_base = EGL_TRUE; disp->Extensions.KHR_image_pixmap = EGL_TRUE; disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE; @@ -994,6 +995,7 @@ dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp, for (i = 0; dri2_dpy->driver_configs[i]; i++) dri2_add_config(disp, dri2_dpy->driver_configs[i], i + 1, 0, 0); + disp->Extensions.MESA_drm_image = EGL_TRUE; disp->Extensions.KHR_image_base = EGL_TRUE; disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE; disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE; @@ -1621,6 +1623,96 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx, } static _EGLImage * +dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx, + EGLClientBuffer buffer, const EGLint *attr_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + struct dri2_egl_image *dri2_img; + EGLint width, height, format, name, stride, pitch, i, err; + + name = (EGLint) buffer; + + err = EGL_SUCCESS; + width = 0; + height = 0; + format = 0; + stride = 0; + + for (i = 0; attr_list[i] != EGL_NONE; i++) { + EGLint attr = attr_list[i++]; + EGLint val = attr_list[i]; + + switch (attr) { + case EGL_WIDTH: + width = val; + break; + case EGL_HEIGHT: + height = val; + break; + case EGL_DRM_BUFFER_FORMAT_MESA: + format = val; + break; + case EGL_DRM_BUFFER_STRIDE_MESA: + stride = val; + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_WARNING, "bad image attribute 0x%04x", attr); + return NULL; + } + } + + if (width <= 0 || height <= 0 || stride <= 0) { + _eglError(EGL_BAD_PARAMETER, + "bad width, height or stride"); + return NULL; + } + + switch (format) { + case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: + format = __DRI_IMAGE_FORMAT_ARGB8888; + pitch = stride; + break; + default: + _eglError(EGL_BAD_PARAMETER, + "dri2_create_image_khr: unsupported pixmap depth"); + return NULL; + } + + dri2_img = malloc(sizeof *dri2_img); + if (!dri2_img) { + _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm"); + return NULL; + } + + if (!_eglInitImage(&dri2_img->base, disp, attr_list)) { + free(dri2_img); + return NULL; + } + + dri2_img->dri_image = + dri2_dpy->image->createImageFromName(dri2_ctx->dri_context, + width, + height, + format, + name, + pitch, + dri2_img); + if (dri2_img->dri_image == NULL) { + free(dri2_img); + _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm"); + return NULL; + } + + return &dri2_img->base; +} + +static _EGLImage * dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attr_list) @@ -1630,6 +1722,8 @@ dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list); case EGL_GL_RENDERBUFFER_KHR: return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list); + case EGL_DRM_BUFFER_MESA: + return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list); default: _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); return EGL_NO_IMAGE_KHR; @@ -1648,6 +1742,133 @@ dri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image) return EGL_TRUE; } +static _EGLImage * +dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, + const EGLint *attr_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img; + int width, height, format, i; + unsigned int use, dri_use, valid_mask; + EGLint err = EGL_SUCCESS; + + dri2_img = malloc(sizeof *dri2_img); + if (!dri2_img) { + _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + + if (!attr_list) { + err = EGL_BAD_PARAMETER; + goto cleanup_img; + } + + if (!_eglInitImage(&dri2_img->base, disp, attr_list)) { + err = EGL_BAD_PARAMETER; + goto cleanup_img; + } + + width = 0; + height = 0; + format = 0; + use = 0; + for (i = 0; attr_list[i] != EGL_NONE; i++) { + EGLint attr = attr_list[i++]; + EGLint val = attr_list[i]; + + switch (attr) { + case EGL_WIDTH: + width = val; + break; + case EGL_HEIGHT: + height = val; + break; + case EGL_DRM_BUFFER_FORMAT_MESA: + format = val; + break; + case EGL_DRM_BUFFER_USE_MESA: + use = val; + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_WARNING, "bad image attribute 0x%04x", attr); + goto cleanup_img; + } + } + + if (width <= 0 || height <= 0) { + _eglLog(_EGL_WARNING, "bad width or height (%dx%d)", width, height); + goto cleanup_img; + } + + switch (format) { + case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: + format = __DRI_IMAGE_FORMAT_ARGB8888; + break; + default: + _eglLog(_EGL_WARNING, "bad image format value 0x%04x", format); + goto cleanup_img; + } + + valid_mask = + EGL_DRM_BUFFER_USE_SCANOUT_MESA | + EGL_DRM_BUFFER_USE_SHARE_MESA; + if (use & ~valid_mask) { + _eglLog(_EGL_WARNING, "bad image use bit 0x%04x", use & ~valid_mask); + goto cleanup_img; + } + + dri_use = 0; + if (use & EGL_DRM_BUFFER_USE_SHARE_MESA) + dri_use |= __DRI_IMAGE_USE_SHARE; + if (use & EGL_DRM_BUFFER_USE_SCANOUT_MESA) + dri_use |= __DRI_IMAGE_USE_SCANOUT; + + dri2_img->dri_image = + dri2_dpy->image->createImage(dri2_dpy->dri_screen, + width, height, format, dri_use, dri2_img); + if (dri2_img->dri_image == NULL) { + err = EGL_BAD_ALLOC; + goto cleanup_img; + } + + return &dri2_img->base; + + cleanup_img: + free(dri2_img); + _eglError(err, "dri2_create_drm_image_mesa"); + + return EGL_NO_IMAGE_KHR; +} + +static EGLBoolean +dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, + EGLint *name, EGLint *handle, EGLint *stride) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img = dri2_egl_image(img); + + if (name && !dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_NAME, name)) { + _eglError(EGL_BAD_ALLOC, "dri2_export_drm_image_mesa"); + return EGL_FALSE; + } + + if (handle) + dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_HANDLE, handle); + + if (stride) + dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_STRIDE, stride); + + return EGL_TRUE; +} + /** * This is the main entrypoint into the driver, called by libEGL. * Create a new _EGLDriver object and init its dispatch table. @@ -1681,6 +1902,8 @@ _eglMain(const char *args) dri2_drv->base.API.CreateImageKHR = dri2_create_image_khr; dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr; dri2_drv->base.API.SwapBuffersRegionNOK = dri2_swap_buffers_region; + dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa; + dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa; dri2_drv->base.Name = "DRI2"; dri2_drv->base.Unload = dri2_unload; diff --git a/src/egl/main/Makefile b/src/egl/main/Makefile index 41d301fc14..d92fbf6d9a 100644 --- a/src/egl/main/Makefile +++ b/src/egl/main/Makefile @@ -26,7 +26,8 @@ HEADERS = \ eglmutex.h \ eglscreen.h \ eglstring.h \ - eglsurface.h + eglsurface.h \ + eglsync.h SOURCES = \ eglapi.c \ @@ -44,7 +45,8 @@ SOURCES = \ eglmode.c \ eglscreen.c \ eglstring.c \ - eglsurface.c + eglsurface.c \ + eglsync.c OBJECTS = $(SOURCES:.c=.o) diff --git a/src/egl/main/SConscript b/src/egl/main/SConscript index 3d7ae3a8e4..06846475ba 100644 --- a/src/egl/main/SConscript +++ b/src/egl/main/SConscript @@ -12,6 +12,7 @@ if env['platform'] != 'winddk': '_EGL_NATIVE_PLATFORM=_EGL_PLATFORM_WINDOWS', '_EGL_DRIVER_SEARCH_DIR=\\"\\"', '_EGL_OS_WINDOWS', + '_EGL_GET_CORE_ADDRESSES', 'KHRONOS_DLL_EXPORTS', ]) @@ -36,11 +37,12 @@ if env['platform'] != 'winddk': 'eglscreen.c', 'eglstring.c', 'eglsurface.c', + 'eglsync.c', ] egl = env.SharedLibrary( target = 'libEGL', - source = egl_sources, + source = egl_sources + ['egl.def'], ) env.InstallSharedLibrary(egl, version=(1, 4, 0)) diff --git a/src/egl/main/egl.def b/src/egl/main/egl.def new file mode 100644 index 0000000000..0cfe920e0e --- /dev/null +++ b/src/egl/main/egl.def @@ -0,0 +1,35 @@ +EXPORTS + eglBindAPI + eglBindTexImage + eglChooseConfig + eglCopyBuffers + eglCreateContext + eglCreatePbufferFromClientBuffer + eglCreatePbufferSurface + eglCreatePixmapSurface + eglCreateWindowSurface + eglDestroyContext + eglDestroySurface + eglGetConfigAttrib + eglGetConfigs + eglGetCurrentContext + eglGetCurrentDisplay + eglGetCurrentSurface + eglGetDisplay + eglGetError + eglGetProcAddress + eglInitialize + eglMakeCurrent + eglQueryAPI + eglQueryContext + eglQueryString + eglQuerySurface + eglReleaseTexImage + eglReleaseThread + eglSurfaceAttrib + eglSwapBuffers + eglSwapInterval + eglTerminate + eglWaitClient + eglWaitGL + eglWaitNative diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 4dc8707cfb..31c5419bbc 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -68,6 +68,7 @@ #include "eglscreen.h" #include "eglmode.h" #include "eglimage.h" +#include "eglsync.h" /** @@ -126,6 +127,8 @@ #define _EGL_CHECK_MODE(disp, m, ret, drv) \ _EGL_CHECK_OBJECT(disp, Mode, m, ret, drv) +#define _EGL_CHECK_SYNC(disp, s, ret, drv) \ + _EGL_CHECK_OBJECT(disp, Sync, s, ret, drv) static INLINE _EGLDriver * @@ -185,6 +188,26 @@ _eglCheckConfig(_EGLDisplay *disp, _EGLConfig *conf, const char *msg) } +#ifdef EGL_KHR_reusable_sync + + +static INLINE _EGLDriver * +_eglCheckSync(_EGLDisplay *disp, _EGLSync *s, const char *msg) +{ + _EGLDriver *drv = _eglCheckDisplay(disp, msg); + if (!drv) + return NULL; + if (!s) { + _eglError(EGL_BAD_PARAMETER, msg); + return NULL; + } + return drv; +} + + +#endif /* EGL_KHR_reusable_sync */ + + #ifdef EGL_MESA_screen_surface @@ -809,7 +832,44 @@ eglGetProcAddress(const char *procname) const char *name; _EGLProc function; } egl_functions[] = { - /* extensions only */ + /* core functions should not be queryable, but, well... */ +#ifdef _EGL_GET_CORE_ADDRESSES + /* alphabetical order */ + { "eglBindAPI", (_EGLProc) eglBindAPI }, + { "eglBindTexImage", (_EGLProc) eglBindTexImage }, + { "eglChooseConfig", (_EGLProc) eglChooseConfig }, + { "eglCopyBuffers", (_EGLProc) eglCopyBuffers }, + { "eglCreateContext", (_EGLProc) eglCreateContext }, + { "eglCreatePbufferFromClientBuffer", (_EGLProc) eglCreatePbufferFromClientBuffer }, + { "eglCreatePbufferSurface", (_EGLProc) eglCreatePbufferSurface }, + { "eglCreatePixmapSurface", (_EGLProc) eglCreatePixmapSurface }, + { "eglCreateWindowSurface", (_EGLProc) eglCreateWindowSurface }, + { "eglDestroyContext", (_EGLProc) eglDestroyContext }, + { "eglDestroySurface", (_EGLProc) eglDestroySurface }, + { "eglGetConfigAttrib", (_EGLProc) eglGetConfigAttrib }, + { "eglGetConfigs", (_EGLProc) eglGetConfigs }, + { "eglGetCurrentContext", (_EGLProc) eglGetCurrentContext }, + { "eglGetCurrentDisplay", (_EGLProc) eglGetCurrentDisplay }, + { "eglGetCurrentSurface", (_EGLProc) eglGetCurrentSurface }, + { "eglGetDisplay", (_EGLProc) eglGetDisplay }, + { "eglGetError", (_EGLProc) eglGetError }, + { "eglGetProcAddress", (_EGLProc) eglGetProcAddress }, + { "eglInitialize", (_EGLProc) eglInitialize }, + { "eglMakeCurrent", (_EGLProc) eglMakeCurrent }, + { "eglQueryAPI", (_EGLProc) eglQueryAPI }, + { "eglQueryContext", (_EGLProc) eglQueryContext }, + { "eglQueryString", (_EGLProc) eglQueryString }, + { "eglQuerySurface", (_EGLProc) eglQuerySurface }, + { "eglReleaseTexImage", (_EGLProc) eglReleaseTexImage }, + { "eglReleaseThread", (_EGLProc) eglReleaseThread }, + { "eglSurfaceAttrib", (_EGLProc) eglSurfaceAttrib }, + { "eglSwapBuffers", (_EGLProc) eglSwapBuffers }, + { "eglSwapInterval", (_EGLProc) eglSwapInterval }, + { "eglTerminate", (_EGLProc) eglTerminate }, + { "eglWaitClient", (_EGLProc) eglWaitClient }, + { "eglWaitGL", (_EGLProc) eglWaitGL }, + { "eglWaitNative", (_EGLProc) eglWaitNative }, +#endif /* _EGL_GET_CORE_ADDRESSES */ #ifdef EGL_MESA_screen_surface { "eglChooseModeMESA", (_EGLProc) eglChooseModeMESA }, { "eglGetModesMESA", (_EGLProc) eglGetModesMESA }, @@ -834,6 +894,10 @@ eglGetProcAddress(const char *procname) #ifdef EGL_NOK_swap_region { "eglSwapBuffersRegionNOK", (_EGLProc) eglSwapBuffersRegionNOK }, #endif +#ifdef EGL_MESA_drm_image + { "eglCreateDRMImageMESA", (_EGLProc) eglCreateDRMImageMESA }, + { "eglExportDRMImageMESA", (_EGLProc) eglExportDRMImageMESA }, +#endif { NULL, NULL } }; EGLint i; @@ -1245,6 +1309,90 @@ eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) #endif /* EGL_KHR_image_base */ +#ifdef EGL_KHR_reusable_sync + + +EGLSyncKHR EGLAPIENTRY +eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLDriver *drv; + _EGLSync *sync; + EGLSyncKHR ret; + + _EGL_CHECK_DISPLAY(disp, EGL_NO_SYNC_KHR, drv); + + sync = drv->API.CreateSyncKHR(drv, disp, type, attrib_list); + ret = (sync) ? _eglLinkSync(sync, disp) : EGL_NO_SYNC_KHR; + + RETURN_EGL_EVAL(disp, ret); +} + + +EGLBoolean EGLAPIENTRY +eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv); + _eglUnlinkSync(s); + ret = drv->API.DestroySyncKHR(drv, disp, s); + + RETURN_EGL_EVAL(disp, ret); +} + + +EGLint EGLAPIENTRY +eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGLDriver *drv; + EGLint ret; + + _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv); + ret = drv->API.ClientWaitSyncKHR(drv, disp, s, flags, timeout); + + RETURN_EGL_EVAL(disp, ret); +} + + +EGLBoolean EGLAPIENTRY +eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv); + ret = drv->API.SignalSyncKHR(drv, disp, s, mode); + + RETURN_EGL_EVAL(disp, ret); +} + + +EGLBoolean EGLAPIENTRY +eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLSync *s = _eglLookupSync(sync, disp); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv); + ret = drv->API.GetSyncAttribKHR(drv, disp, s, attribute, value); + + RETURN_EGL_EVAL(disp, ret); +} + + +#endif /* EGL_KHR_reusable_sync */ + + #ifdef EGL_NOK_swap_region EGLBoolean EGLAPIENTRY @@ -1272,3 +1420,42 @@ eglSwapBuffersRegionNOK(EGLDisplay dpy, EGLSurface surface, } #endif /* EGL_NOK_swap_region */ + + +#ifdef EGL_MESA_drm_image + +EGLImageKHR EGLAPIENTRY +eglCreateDRMImageMESA(EGLDisplay dpy, const EGLint *attr_list) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLDriver *drv; + _EGLImage *img; + EGLImageKHR ret; + + _EGL_CHECK_DISPLAY(disp, EGL_NO_IMAGE_KHR, drv); + + img = drv->API.CreateDRMImageMESA(drv, disp, attr_list); + ret = (img) ? _eglLinkImage(img, disp) : EGL_NO_IMAGE_KHR; + + RETURN_EGL_EVAL(disp, ret); +} + +EGLBoolean EGLAPIENTRY +eglExportDRMImageMESA(EGLDisplay dpy, EGLImageKHR image, + EGLint *name, EGLint *handle, EGLint *stride) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLImage *img = _eglLookupImage(image, disp); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); + if (!img) + RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE); + + ret = drv->API.ExportDRMImageMESA(drv, disp, img, name, handle, stride); + + RETURN_EGL_EVAL(disp, ret); +} + +#endif diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h index d8c8b49a49..127becc9ac 100644 --- a/src/egl/main/eglapi.h +++ b/src/egl/main/eglapi.h @@ -76,10 +76,25 @@ typedef _EGLImage *(*CreateImageKHR_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLCo typedef EGLBoolean (*DestroyImageKHR_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *image); #endif /* EGL_KHR_image_base */ + +#ifdef EGL_KHR_reusable_sync +typedef _EGLSync *(*CreateSyncKHR_t)(_EGLDriver *drv, _EGLDisplay *dpy, EGLenum type, const EGLint *attrib_list); +typedef EGLBoolean (*DestroySyncKHR_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync); +typedef EGLint (*ClientWaitSyncKHR_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, EGLint flags, EGLTimeKHR timeout); +typedef EGLBoolean (*SignalSyncKHR_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, EGLenum mode); +typedef EGLBoolean (*GetSyncAttribKHR_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, EGLint attribute, EGLint *value); +#endif /* EGL_KHR_reusable_sync */ + + #ifdef EGL_NOK_swap_region typedef EGLBoolean (*SwapBuffersRegionNOK_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, EGLint numRects, const EGLint *rects); #endif +#ifdef EGL_MESA_drm_image +typedef _EGLImage *(*CreateDRMImageMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attr_list); +typedef EGLBoolean (*ExportDRMImageMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, EGLint *name, EGLint *handle, EGLint *stride); +#endif + /** * The API dispatcher jumps through these functions */ @@ -138,9 +153,22 @@ struct _egl_api DestroyImageKHR_t DestroyImageKHR; #endif /* EGL_KHR_image_base */ +#ifdef EGL_KHR_reusable_sync + CreateSyncKHR_t CreateSyncKHR; + DestroySyncKHR_t DestroySyncKHR; + ClientWaitSyncKHR_t ClientWaitSyncKHR; + SignalSyncKHR_t SignalSyncKHR; + GetSyncAttribKHR_t GetSyncAttribKHR; +#endif /* EGL_KHR_reusable_sync */ + #ifdef EGL_NOK_swap_region SwapBuffersRegionNOK_t SwapBuffersRegionNOK; #endif + +#ifdef EGL_MESA_drm_image + CreateDRMImageMESA_t CreateDRMImageMESA; + ExportDRMImageMESA_t ExportDRMImageMESA; +#endif }; #endif /* EGLAPI_INCLUDED */ diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c index ea8e47d02b..01e7144d40 100644 --- a/src/egl/main/eglconfig.c +++ b/src/egl/main/eglconfig.c @@ -460,11 +460,14 @@ _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria) } if (!matched) { -#ifdef DEBUG +#ifndef DEBUG + /* only print the common errors when DEBUG is not defined */ + if (attr != EGL_RENDERABLE_TYPE) + break; +#endif _eglLog(_EGL_DEBUG, "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)", val, attr, cmp); -#endif break; } } diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c index 9fc529613e..e72664c23c 100644 --- a/src/egl/main/eglcontext.c +++ b/src/egl/main/eglcontext.c @@ -83,15 +83,6 @@ _eglParseContextAttribList(_EGLContext *ctx, const EGLint *attrib_list) } } - if (err == EGL_SUCCESS && ctx->Config) { - EGLint renderable_type, api_bit; - - renderable_type = GET_CONFIG_ATTRIB(ctx->Config, EGL_RENDERABLE_TYPE); - api_bit = _eglGetContextAPIBit(ctx); - if (!(renderable_type & api_bit)) - err = EGL_BAD_CONFIG; - } - return err; } @@ -121,6 +112,17 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf, ctx->ClientVersion = 1; /* the default, per EGL spec */ err = _eglParseContextAttribList(ctx, attrib_list); + if (err == EGL_SUCCESS && ctx->Config) { + EGLint renderable_type, api_bit; + + renderable_type = GET_CONFIG_ATTRIB(ctx->Config, EGL_RENDERABLE_TYPE); + api_bit = _eglGetContextAPIBit(ctx); + if (!(renderable_type & api_bit)) { + _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x", + api_bit, renderable_type); + err = EGL_BAD_CONFIG; + } + } if (err != EGL_SUCCESS) return _eglError(err, "eglCreateContext"); diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h index a2cee08bf6..3863cce010 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -24,6 +24,7 @@ enum _egl_resource_type { _EGL_RESOURCE_CONTEXT, _EGL_RESOURCE_SURFACE, _EGL_RESOURCE_IMAGE, + _EGL_RESOURCE_SYNC, _EGL_NUM_RESOURCES }; @@ -53,6 +54,8 @@ struct _egl_extensions EGLBoolean MESA_screen_surface; EGLBoolean MESA_copy_context; EGLBoolean MESA_drm_display; + EGLBoolean MESA_drm_image; + EGLBoolean KHR_image_base; EGLBoolean KHR_image_pixmap; EGLBoolean KHR_vg_parent_image; @@ -60,9 +63,14 @@ struct _egl_extensions EGLBoolean KHR_gl_texture_cubemap_image; EGLBoolean KHR_gl_texture_3D_image; EGLBoolean KHR_gl_renderbuffer_image; + + EGLBoolean KHR_reusable_sync; + EGLBoolean KHR_fence_sync; + EGLBoolean KHR_surfaceless_gles1; EGLBoolean KHR_surfaceless_gles2; EGLBoolean KHR_surfaceless_opengl; + EGLBoolean NOK_swap_region; EGLBoolean NOK_texture_from_pixmap; diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c index 8fc9e792b0..67f1d3dbaa 100644 --- a/src/egl/main/egldriver.c +++ b/src/egl/main/egldriver.c @@ -21,6 +21,7 @@ #include "eglstring.h" #include "eglsurface.h" #include "eglimage.h" +#include "eglsync.h" #include "eglmutex.h" #if defined(_EGL_OS_UNIX) @@ -722,6 +723,14 @@ _eglInitDriverFallbacks(_EGLDriver *drv) drv->API.CreateImageKHR = _eglCreateImageKHR; drv->API.DestroyImageKHR = _eglDestroyImageKHR; #endif /* EGL_KHR_image_base */ + +#ifdef EGL_KHR_reusable_sync + drv->API.CreateSyncKHR = _eglCreateSyncKHR; + drv->API.DestroySyncKHR = _eglDestroySyncKHR; + drv->API.ClientWaitSyncKHR = _eglClientWaitSyncKHR; + drv->API.SignalSyncKHR = _eglSignalSyncKHR; + drv->API.GetSyncAttribKHR = _eglGetSyncAttribKHR; +#endif /* EGL_KHR_reusable_sync */ } diff --git a/src/egl/main/eglmisc.c b/src/egl/main/eglmisc.c index 985d1e0069..eb3dde1fb4 100644 --- a/src/egl/main/eglmisc.c +++ b/src/egl/main/eglmisc.c @@ -85,6 +85,7 @@ _eglUpdateExtensionsString(_EGLDisplay *dpy) _EGL_CHECK_EXTENSION(MESA_screen_surface); _EGL_CHECK_EXTENSION(MESA_copy_context); _EGL_CHECK_EXTENSION(MESA_drm_display); + _EGL_CHECK_EXTENSION(MESA_drm_image); _EGL_CHECK_EXTENSION(KHR_image_base); _EGL_CHECK_EXTENSION(KHR_image_pixmap); @@ -97,6 +98,9 @@ _eglUpdateExtensionsString(_EGLDisplay *dpy) _EGL_CHECK_EXTENSION(KHR_gl_texture_3D_image); _EGL_CHECK_EXTENSION(KHR_gl_renderbuffer_image); + _EGL_CHECK_EXTENSION(KHR_reusable_sync); + _EGL_CHECK_EXTENSION(KHR_fence_sync); + _EGL_CHECK_EXTENSION(KHR_surfaceless_gles1); _EGL_CHECK_EXTENSION(KHR_surfaceless_gles2); _EGL_CHECK_EXTENSION(KHR_surfaceless_opengl); diff --git a/src/egl/main/eglsync.c b/src/egl/main/eglsync.c new file mode 100644 index 0000000000..b6c62d0087 --- /dev/null +++ b/src/egl/main/eglsync.c @@ -0,0 +1,128 @@ +#include <string.h> + +#include "eglsync.h" +#include "eglcurrent.h" +#include "egllog.h" + + +#ifdef EGL_KHR_reusable_sync + + +/** + * Parse the list of sync attributes and return the proper error code. + */ +static EGLint +_eglParseSyncAttribList(_EGLSync *sync, const EGLint *attrib_list) +{ + EGLint i, err = EGL_SUCCESS; + + if (!attrib_list) + return EGL_SUCCESS; + + for (i = 0; attrib_list[i] != EGL_NONE; i++) { + EGLint attr = attrib_list[i++]; + EGLint val = attrib_list[i]; + + switch (attr) { + default: + (void) val; + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_DEBUG, "bad sync attribute 0x%04x", attr); + break; + } + } + + return err; +} + + +EGLBoolean +_eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type, + const EGLint *attrib_list) +{ + EGLint err; + + if (!(type == EGL_SYNC_REUSABLE_KHR && dpy->Extensions.KHR_reusable_sync) && + !(type == EGL_SYNC_FENCE_KHR && dpy->Extensions.KHR_fence_sync)) + return _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR"); + + memset(sync, 0, sizeof(*sync)); + + sync->Resource.Display = dpy; + + sync->Type = type; + sync->SyncStatus = EGL_UNSIGNALED_KHR; + sync->SyncCondition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; + + err = _eglParseSyncAttribList(sync, attrib_list); + if (err != EGL_SUCCESS) + return _eglError(err, "eglCreateSyncKHR"); + + return EGL_TRUE; +} + + +_EGLSync * +_eglCreateSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, + EGLenum type, const EGLint *attrib_list) +{ + return NULL; +} + + +EGLBoolean +_eglDestroySyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) +{ + return EGL_TRUE; +} + + +EGLint +_eglClientWaitSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLint flags, EGLTimeKHR timeout) +{ + return EGL_FALSE; +} + + +EGLBoolean +_eglSignalSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLenum mode) +{ + return EGL_FALSE; +} + + +EGLBoolean +_eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLint attribute, EGLint *value) +{ + if (!value) + return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs"); + + switch (attribute) { + case EGL_SYNC_TYPE_KHR: + *value = sync->Type; + break; + case EGL_SYNC_STATUS_KHR: + *value = sync->SyncStatus; + break; + case EGL_SYNC_CONDITION_KHR: + if (sync->Type != EGL_SYNC_FENCE_KHR) + return _eglError(EGL_BAD_ATTRIBUTE, "eglGetSyncAttribKHR"); + *value = sync->SyncCondition; + break; + default: + return _eglError(EGL_BAD_ATTRIBUTE, "eglGetSyncAttribKHR"); + break; + } + + return EGL_TRUE; +} + + +#endif /* EGL_KHR_reusable_sync */ diff --git a/src/egl/main/eglsync.h b/src/egl/main/eglsync.h new file mode 100644 index 0000000000..25c467175e --- /dev/null +++ b/src/egl/main/eglsync.h @@ -0,0 +1,120 @@ +#ifndef EGLSYNC_INCLUDED +#define EGLSYNC_INCLUDED + + +#include "egltypedefs.h" +#include "egldisplay.h" + + +#ifdef EGL_KHR_reusable_sync + + +/** + * "Base" class for device driver syncs. + */ +struct _egl_sync +{ + /* A sync is a display resource */ + _EGLResource Resource; + + EGLenum Type; + EGLenum SyncStatus; + EGLenum SyncCondition; +}; + + +PUBLIC EGLBoolean +_eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type, + const EGLint *attrib_list); + + +extern _EGLSync * +_eglCreateSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, + EGLenum type, const EGLint *attrib_list); + + +extern EGLBoolean +_eglDestroySyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync); + + +extern EGLint +_eglClientWaitSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLint flags, EGLTimeKHR timeout); + + +extern EGLBoolean +_eglSignalSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLenum mode); + + +extern EGLBoolean +_eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLint attribute, EGLint *value); + + +/** + * Link a sync to a display and return the handle of the link. + * The handle can be passed to client directly. + */ +static INLINE EGLSyncKHR +_eglLinkSync(_EGLSync *sync, _EGLDisplay *dpy) +{ + _eglLinkResource(&sync->Resource, _EGL_RESOURCE_SYNC, dpy); + return (EGLSyncKHR) sync; +} + + +/** + * Unlink a linked sync from its display. + */ +static INLINE void +_eglUnlinkSync(_EGLSync *sync) +{ + _eglUnlinkResource(&sync->Resource, _EGL_RESOURCE_SYNC); +} + + +/** + * Lookup a handle to find the linked sync. + * Return NULL if the handle has no corresponding linked sync. + */ +static INLINE _EGLSync * +_eglLookupSync(EGLSyncKHR handle, _EGLDisplay *dpy) +{ + _EGLSync *sync = (_EGLSync *) handle; + if (!dpy || !_eglCheckResource((void *) sync, _EGL_RESOURCE_SYNC, dpy)) + sync = NULL; + return sync; +} + + +/** + * Return the handle of a linked sync, or EGL_NO_SYNC_KHR. + */ +static INLINE EGLSyncKHR +_eglGetSyncHandle(_EGLSync *sync) +{ + _EGLResource *res = (_EGLResource *) sync; + return (res && _eglIsResourceLinked(res)) ? + (EGLSyncKHR) sync : EGL_NO_SYNC_KHR; +} + + +/** + * Return true if the sync is linked to a display. + * + * The link is considered a reference to the sync (the display is owning the + * sync). Drivers should not destroy a sync when it is linked. + */ +static INLINE EGLBoolean +_eglIsSyncLinked(_EGLSync *sync) +{ + _EGLResource *res = (_EGLResource *) sync; + return (res && _eglIsResourceLinked(res)); +} + + +#endif /* EGL_KHR_reusable_sync */ + + +#endif /* EGLSYNC_INCLUDED */ diff --git a/src/egl/main/egltypedefs.h b/src/egl/main/egltypedefs.h index 0e29e9aa47..b65f3b72ae 100644 --- a/src/egl/main/egltypedefs.h +++ b/src/egl/main/egltypedefs.h @@ -32,6 +32,8 @@ typedef struct _egl_screen _EGLScreen; typedef struct _egl_surface _EGLSurface; +typedef struct _egl_sync _EGLSync; + typedef struct _egl_thread_info _EGLThreadInfo; #endif /* EGLTYPEDEFS_INCLUDED */ diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile index 9544e90a96..eb86d83d2a 100644 --- a/src/gallium/auxiliary/Makefile +++ b/src/gallium/auxiliary/Makefile @@ -4,8 +4,8 @@ include $(TOP)/configs/current LIBNAME = gallium C_SOURCES = \ - cso_cache/cso_context.c \ cso_cache/cso_cache.c \ + cso_cache/cso_context.c \ cso_cache/cso_hash.c \ draw/draw_context.c \ draw/draw_gs.c \ @@ -26,7 +26,6 @@ C_SOURCES = \ draw/draw_pipe_wide_line.c \ draw/draw_pipe_wide_point.c \ draw/draw_pt.c \ - draw/draw_pt_elts.c \ draw/draw_pt_emit.c \ draw/draw_pt_fetch.c \ draw/draw_pt_fetch_emit.c \ @@ -35,24 +34,24 @@ C_SOURCES = \ draw/draw_pt_post_vs.c \ draw/draw_pt_so_emit.c \ draw/draw_pt_util.c \ - draw/draw_pt_varray.c \ - draw/draw_pt_vcache.c \ + draw/draw_pt_vsplit.c \ draw/draw_vertex.c \ draw/draw_vs.c \ - draw/draw_vs_varient.c \ draw/draw_vs_aos.c \ draw/draw_vs_aos_io.c \ draw/draw_vs_aos_machine.c \ draw/draw_vs_exec.c \ draw/draw_vs_ppc.c \ draw/draw_vs_sse.c \ + draw/draw_vs_varient.c \ indices/u_indices_gen.c \ indices/u_unfilled_gen.c \ os/os_misc.c \ + os/os_stream.c \ os/os_stream_log.c \ + os/os_stream_null.c \ os/os_stream_stdc.c \ os/os_stream_str.c \ - os/os_stream_null.c \ os/os_time.c \ pipebuffer/pb_buffer_fenced.c \ pipebuffer/pb_buffer_malloc.c \ @@ -65,17 +64,16 @@ C_SOURCES = \ pipebuffer/pb_bufmgr_slab.c \ pipebuffer/pb_validate.c \ rbug/rbug_connection.c \ + rbug/rbug_context.c \ rbug/rbug_core.c \ + rbug/rbug_demarshal.c \ rbug/rbug_texture.c \ - rbug/rbug_context.c \ rbug/rbug_shader.c \ - rbug/rbug_demarshal.c \ rtasm/rtasm_cpu.c \ rtasm/rtasm_execmem.c \ - rtasm/rtasm_x86sse.c \ rtasm/rtasm_ppc.c \ rtasm/rtasm_ppc_spe.c \ - tgsi/tgsi_sanity.c \ + rtasm/rtasm_x86sse.c \ tgsi/tgsi_build.c \ tgsi/tgsi_dump.c \ tgsi/tgsi_exec.c \ @@ -83,19 +81,22 @@ C_SOURCES = \ tgsi/tgsi_iterate.c \ tgsi/tgsi_parse.c \ tgsi/tgsi_ppc.c \ + tgsi/tgsi_sanity.c \ tgsi/tgsi_scan.c \ tgsi/tgsi_sse2.c \ tgsi/tgsi_text.c \ tgsi/tgsi_transform.c \ tgsi/tgsi_ureg.c \ tgsi/tgsi_util.c \ - translate/translate_generic.c \ - translate/translate_sse.c \ translate/translate.c \ translate/translate_cache.c \ + translate/translate_generic.c \ + translate/translate_sse.c \ util/u_debug.c \ - util/u_debug_symbol.c \ + util/u_debug_describe.c \ + util/u_debug_refcnt.c \ util/u_debug_stack.c \ + util/u_debug_symbol.c \ util/u_dump_defines.c \ util/u_dump_state.c \ util/u_bitmask.c \ @@ -118,10 +119,11 @@ C_SOURCES = \ util/u_gen_mipmap.c \ util/u_half.c \ util/u_handle_table.c \ - util/u_hash_table.c \ util/u_hash.c \ + util/u_hash_table.c \ util/u_keymap.c \ util/u_linear.c \ + util/u_linkage.c \ util/u_network.c \ util/u_math.c \ util/u_mempool.c \ @@ -172,10 +174,10 @@ GALLIVM_SOURCES = \ gallivm/lp_bld_tgsi_soa.c \ gallivm/lp_bld_type.c \ draw/draw_llvm.c \ - draw/draw_vs_llvm.c \ - draw/draw_pt_fetch_shade_pipeline_llvm.c \ + draw/draw_llvm_sample.c \ draw/draw_llvm_translate.c \ - draw/draw_llvm_sample.c + draw/draw_vs_llvm.c \ + draw/draw_pt_fetch_shade_pipeline_llvm.c GALLIVM_CPP_SOURCES = \ gallivm/lp_bld_misc.cpp diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript index 3124e20ce8..6210ada990 100644 --- a/src/gallium/auxiliary/SConscript +++ b/src/gallium/auxiliary/SConscript @@ -50,10 +50,11 @@ env.Depends('util/u_format_table.c', [ ]) source = [ - 'cso_cache/cso_context.c', 'cso_cache/cso_cache.c', + 'cso_cache/cso_context.c', 'cso_cache/cso_hash.c', 'draw/draw_context.c', + 'draw/draw_gs.c', 'draw/draw_pipe.c', 'draw/draw_pipe_aaline.c', 'draw/draw_pipe_aapoint.c', @@ -71,7 +72,6 @@ source = [ 'draw/draw_pipe_wide_line.c', 'draw/draw_pipe_wide_point.c', 'draw/draw_pt.c', - 'draw/draw_pt_elts.c', 'draw/draw_pt_emit.c', 'draw/draw_pt_fetch.c', 'draw/draw_pt_fetch_emit.c', @@ -80,8 +80,7 @@ source = [ 'draw/draw_pt_post_vs.c', 'draw/draw_pt_so_emit.c', 'draw/draw_pt_util.c', - 'draw/draw_pt_varray.c', - 'draw/draw_pt_vcache.c', + 'draw/draw_pt_vsplit.c', 'draw/draw_vertex.c', 'draw/draw_vs.c', 'draw/draw_vs_aos.c', @@ -91,16 +90,16 @@ source = [ 'draw/draw_vs_ppc.c', 'draw/draw_vs_sse.c', 'draw/draw_vs_varient.c', - 'draw/draw_gs.c', #'indices/u_indices.c', #'indices/u_unfilled_indices.c', 'indices/u_indices_gen.c', 'indices/u_unfilled_gen.c', 'os/os_misc.c', + 'os/os_stream.c', 'os/os_stream_log.c', + 'os/os_stream_null.c', 'os/os_stream_stdc.c', 'os/os_stream_str.c', - 'os/os_stream_null.c', 'os/os_time.c', 'pipebuffer/pb_buffer_fenced.c', 'pipebuffer/pb_buffer_malloc.c', @@ -112,35 +111,35 @@ source = [ 'pipebuffer/pb_bufmgr_pool.c', 'pipebuffer/pb_bufmgr_slab.c', 'pipebuffer/pb_validate.c', + 'rbug/rbug_connection.c', + 'rbug/rbug_context.c', 'rbug/rbug_core.c', + 'rbug/rbug_demarshal.c', 'rbug/rbug_shader.c', - 'rbug/rbug_context.c', 'rbug/rbug_texture.c', - 'rbug/rbug_demarshal.c', - 'rbug/rbug_connection.c', 'rtasm/rtasm_cpu.c', 'rtasm/rtasm_execmem.c', - 'rtasm/rtasm_x86sse.c', 'rtasm/rtasm_ppc.c', 'rtasm/rtasm_ppc_spe.c', + 'rtasm/rtasm_x86sse.c', 'tgsi/tgsi_build.c', 'tgsi/tgsi_dump.c', 'tgsi/tgsi_exec.c', 'tgsi/tgsi_info.c', 'tgsi/tgsi_iterate.c', 'tgsi/tgsi_parse.c', + 'tgsi/tgsi_ppc.c', 'tgsi/tgsi_sanity.c', 'tgsi/tgsi_scan.c', - 'tgsi/tgsi_ppc.c', 'tgsi/tgsi_sse2.c', 'tgsi/tgsi_text.c', 'tgsi/tgsi_transform.c', 'tgsi/tgsi_ureg.c', 'tgsi/tgsi_util.c', - 'translate/translate_generic.c', - 'translate/translate_sse.c', 'translate/translate.c', 'translate/translate_cache.c', + 'translate/translate_generic.c', + 'translate/translate_sse.c', 'util/u_bitmask.c', 'util/u_blit.c', 'util/u_blitter.c', @@ -148,7 +147,9 @@ source = [ 'util/u_caps.c', 'util/u_cpu_detect.c', 'util/u_debug.c', + 'util/u_debug_describe.c', 'util/u_debug_memory.c', + 'util/u_debug_refcnt.c', 'util/u_debug_stack.c', 'util/u_debug_symbol.c', 'util/u_dump_defines.c', @@ -170,6 +171,8 @@ source = [ 'util/u_hash.c', 'util/u_hash_table.c', 'util/u_keymap.c', + 'util/u_linear.c', + 'util/u_linkage.c', 'util/u_network.c', 'util/u_math.c', 'util/u_mempool.c', @@ -208,9 +211,9 @@ if env['llvm']: 'gallivm/lp_bld_format_soa.c', 'gallivm/lp_bld_format_yuv.c', 'gallivm/lp_bld_gather.c', + 'gallivm/lp_bld_init.c', 'gallivm/lp_bld_intr.c', 'gallivm/lp_bld_logic.c', - 'gallivm/lp_bld_init.c', 'gallivm/lp_bld_misc.cpp', 'gallivm/lp_bld_pack.c', 'gallivm/lp_bld_printf.c', @@ -222,10 +225,10 @@ if env['llvm']: 'gallivm/lp_bld_tgsi_soa.c', 'gallivm/lp_bld_type.c', 'draw/draw_llvm.c', - 'draw/draw_pt_fetch_shade_pipeline_llvm.c', + 'draw/draw_llvm_sample.c', 'draw/draw_llvm_translate.c', - 'draw/draw_vs_llvm.c', - 'draw/draw_llvm_sample.c' + 'draw/draw_pt_fetch_shade_pipeline_llvm.c', + 'draw/draw_vs_llvm.c' ] gallium = env.ConvenienceLibrary( diff --git a/src/gallium/auxiliary/draw/draw_cliptest_tmp.h b/src/gallium/auxiliary/draw/draw_cliptest_tmp.h new file mode 100644 index 0000000000..958ed20dc8 --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_cliptest_tmp.h @@ -0,0 +1,114 @@ +/************************************************************************** + * + * Copyright 2010, VMware, inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + + +static boolean TAG(do_cliptest)( struct pt_post_vs *pvs, + struct draw_vertex_info *info ) +{ + struct vertex_header *out = info->verts; + const float *scale = pvs->draw->viewport.scale; + const float *trans = pvs->draw->viewport.translate; + /* const */ float (*plane)[4] = pvs->draw->plane; + const unsigned pos = draw_current_shader_position_output(pvs->draw); + const unsigned ef = pvs->draw->vs.edgeflag_output; + const unsigned nr = pvs->draw->nr_planes; + const unsigned flags = (FLAGS); + unsigned need_pipeline = 0; + unsigned j; + + for (j = 0; j < info->count; j++) { + float *position = out->data[pos]; + unsigned mask = 0x0; + + initialize_vertex_header(out); + + if (flags & (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_HALF_Z | DO_CLIP_USER)) { + out->clip[0] = position[0]; + out->clip[1] = position[1]; + out->clip[2] = position[2]; + out->clip[3] = position[3]; + + /* Do the hardwired planes first: + */ + if (flags & DO_CLIP_XY) { + if (-position[0] + position[3] < 0) mask |= (1<<0); + if ( position[0] + position[3] < 0) mask |= (1<<1); + if (-position[1] + position[3] < 0) mask |= (1<<2); + if ( position[1] + position[3] < 0) mask |= (1<<3); + } + + /* Clip Z planes according to full cube, half cube or none. + */ + if (flags & DO_CLIP_FULL_Z) { + if ( position[2] + position[3] < 0) mask |= (1<<4); + if (-position[2] + position[3] < 0) mask |= (1<<5); + } + else if (flags & DO_CLIP_HALF_Z) { + if ( position[2] < 0) mask |= (1<<4); + if (-position[2] + position[3] < 0) mask |= (1<<5); + } + + if (flags & DO_CLIP_USER) { + unsigned i; + for (i = 6; i < nr; i++) { + if (dot4(position, plane[i]) < 0) + mask |= (1<<i); + } + } + + out->clipmask = mask; + need_pipeline |= out->clipmask; + } + + if ((flags & DO_VIEWPORT) && mask == 0) + { + /* divide by w */ + float w = 1.0f / position[3]; + + /* Viewport mapping */ + position[0] = position[0] * w * scale[0] + trans[0]; + position[1] = position[1] * w * scale[1] + trans[1]; + position[2] = position[2] * w * scale[2] + trans[2]; + position[3] = w; + } + + if ((flags & DO_EDGEFLAG) && ef) { + const float *edgeflag = out->data[ef]; + out->edgeflag = !(edgeflag[0] != 1.0f); + need_pipeline |= !out->edgeflag; + } + + out = (struct vertex_header *)( (char *)out + info->stride ); + } + + return need_pipeline != 0; +} + + +#undef FLAGS +#undef TAG diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index 995b675b9a..937b093479 100644 --- a/src/gallium/auxiliary/draw/draw_context.c +++ b/src/gallium/auxiliary/draw/draw_context.c @@ -34,6 +34,7 @@ #include "pipe/p_context.h" #include "util/u_memory.h" #include "util/u_math.h" +#include "util/u_cpu_detect.h" #include "draw_context.h" #include "draw_vs.h" #include "draw_gs.h" @@ -41,6 +42,25 @@ #if HAVE_LLVM #include "gallivm/lp_bld_init.h" #include "draw_llvm.h" + +static boolean +draw_get_option_use_llvm(void) +{ + static boolean first = TRUE; + static boolean value; + if (first) { + first = FALSE; + value = debug_get_bool_option("DRAW_USE_LLVM", TRUE); + +#ifdef PIPE_ARCH_X86 + util_cpu_detect(); + /* require SSE2 due to LLVM PR6960. */ + if (!util_cpu_caps.has_sse2) + value = FALSE; +#endif + } + return value; +} #endif struct draw_context *draw_create( struct pipe_context *pipe ) @@ -50,10 +70,13 @@ struct draw_context *draw_create( struct pipe_context *pipe ) goto fail; #if HAVE_LLVM - lp_build_init(); - assert(lp_build_engine); - draw->engine = lp_build_engine; - draw->llvm = draw_llvm_create(draw); + if(draw_get_option_use_llvm()) + { + lp_build_init(); + assert(lp_build_engine); + draw->engine = lp_build_engine; + draw->llvm = draw_llvm_create(draw); + } #endif if (!draw_init(draw)) @@ -83,6 +106,8 @@ boolean draw_init(struct draw_context *draw) ASSIGN_4V( draw->plane[4], 0, 0, 1, 1 ); /* yes these are correct */ ASSIGN_4V( draw->plane[5], 0, 0, -1, 1 ); /* mesa's a bit wonky */ draw->nr_planes = 6; + draw->clip_xy = 1; + draw->clip_z = 1; draw->reduced_prim = ~0; /* != any of PIPE_PRIM_x */ @@ -135,7 +160,8 @@ void draw_destroy( struct draw_context *draw ) draw_vs_destroy( draw ); draw_gs_destroy( draw ); #ifdef HAVE_LLVM - draw_llvm_destroy( draw->llvm ); + if(draw->llvm) + draw_llvm_destroy( draw->llvm ); #endif FREE( draw ); @@ -162,6 +188,14 @@ void draw_set_mrd(struct draw_context *draw, double mrd) } +static void update_clip_flags( struct draw_context *draw ) +{ + draw->clip_xy = !draw->driver.bypass_clip_xy; + draw->clip_z = (!draw->driver.bypass_clip_z && + !draw->depth_clamp); + draw->clip_user = (draw->nr_planes > 6); +} + /** * Register new primitive rasterization/rendering state. * This causes the drawing pipeline to be rebuilt. @@ -176,18 +210,25 @@ void draw_set_rasterizer_state( struct draw_context *draw, draw->rasterizer = raster; draw->rast_handle = rast_handle; - draw->bypass_clipping = draw->driver.bypass_clipping; - } + } } - +/* With a little more work, llvmpipe will be able to turn this off and + * do its own x/y clipping. + * + * Some hardware can turn off clipping altogether - in particular any + * hardware with a TNL unit can do its own clipping, even if it is + * relying on the draw module for some other reason. + */ void draw_set_driver_clipping( struct draw_context *draw, - boolean bypass_clipping ) + boolean bypass_clip_xy, + boolean bypass_clip_z ) { draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE ); - draw->driver.bypass_clipping = bypass_clipping; - draw->bypass_clipping = draw->driver.bypass_clipping; + draw->driver.bypass_clip_xy = bypass_clip_xy; + draw->driver.bypass_clip_z = bypass_clip_z; + update_clip_flags(draw); } @@ -217,6 +258,8 @@ void draw_set_clip_state( struct draw_context *draw, memcpy(&draw->plane[6], clip->ucp, clip->nr * sizeof(clip->ucp[0])); draw->nr_planes = 6 + clip->nr; draw->depth_clamp = clip->depth_clamp; + + update_clip_flags(draw); } @@ -472,47 +515,28 @@ void draw_set_render( struct draw_context *draw, } - -/** - * Tell the drawing context about the index/element buffer to use - * (ala glDrawElements) - * If no element buffer is to be used (i.e. glDrawArrays) then this - * should be called with eltSize=0 and elements=NULL. - * - * \param draw the drawing context - * \param eltSize size of each element (1, 2 or 4 bytes) - * \param elements the element buffer ptr - */ void -draw_set_mapped_element_buffer_range( struct draw_context *draw, - unsigned eltSize, - int eltBias, - unsigned min_index, - unsigned max_index, - const void *elements ) +draw_set_index_buffer(struct draw_context *draw, + const struct pipe_index_buffer *ib) { - draw->pt.user.elts = elements; - draw->pt.user.eltSize = eltSize; - draw->pt.user.eltBias = eltBias; - draw->pt.user.min_index = min_index; - draw->pt.user.max_index = max_index; + if (ib) + memcpy(&draw->pt.index_buffer, ib, sizeof(draw->pt.index_buffer)); + else + memset(&draw->pt.index_buffer, 0, sizeof(draw->pt.index_buffer)); } +/** + * Tell drawing context where to find mapped index/element buffer. + */ void -draw_set_mapped_element_buffer( struct draw_context *draw, - unsigned eltSize, - int eltBias, - const void *elements ) +draw_set_mapped_index_buffer(struct draw_context *draw, + const void *elements) { - draw->pt.user.elts = elements; - draw->pt.user.eltSize = eltSize; - draw->pt.user.eltBias = eltBias; - draw->pt.user.min_index = 0; - draw->pt.user.max_index = 0xffffffff; + draw->pt.user.elts = elements; } - + /* Revamp me please: */ void draw_do_flush( struct draw_context *draw, unsigned flags ) @@ -659,7 +683,8 @@ draw_set_mapped_texture(struct draw_context *draw, const void *data[DRAW_MAX_TEXTURE_LEVELS]) { #ifdef HAVE_LLVM - draw_llvm_set_mapped_texture(draw, + if(draw->llvm) + draw_llvm_set_mapped_texture(draw, sampler_idx, width, height, depth, last_level, row_stride, img_stride, data); diff --git a/src/gallium/auxiliary/draw/draw_context.h b/src/gallium/auxiliary/draw/draw_context.h index 116716af6f..4c780e4dcb 100644 --- a/src/gallium/auxiliary/draw/draw_context.h +++ b/src/gallium/auxiliary/draw/draw_context.h @@ -160,18 +160,11 @@ void draw_set_vertex_elements(struct draw_context *draw, unsigned count, const struct pipe_vertex_element *elements); -void -draw_set_mapped_element_buffer_range( struct draw_context *draw, - unsigned eltSize, - int eltBias, - unsigned min_index, - unsigned max_index, - const void *elements ); - -void draw_set_mapped_element_buffer( struct draw_context *draw, - unsigned eltSize, - int eltBias, - const void *elements ); +void draw_set_index_buffer(struct draw_context *draw, + const struct pipe_index_buffer *ib); + +void draw_set_mapped_index_buffer(struct draw_context *draw, + const void *elements); void draw_set_mapped_vertex_buffer(struct draw_context *draw, unsigned attr, const void *buffer); @@ -196,6 +189,9 @@ draw_set_so_state(struct draw_context *draw, * draw_pt.c */ +void draw_vbo(struct draw_context *draw, + const struct pipe_draw_info *info); + void draw_arrays(struct draw_context *draw, unsigned prim, unsigned start, unsigned count); @@ -216,7 +212,8 @@ void draw_set_render( struct draw_context *draw, struct vbuf_render *render ); void draw_set_driver_clipping( struct draw_context *draw, - boolean bypass_clipping ); + boolean bypass_clip_xy, + boolean bypass_clip_z ); void draw_set_force_passthrough( struct draw_context *draw, boolean enable ); diff --git a/src/gallium/auxiliary/draw/draw_decompose_tmp.h b/src/gallium/auxiliary/draw/draw_decompose_tmp.h index a52d2b5058..a142563af9 100644 --- a/src/gallium/auxiliary/draw/draw_decompose_tmp.h +++ b/src/gallium/auxiliary/draw/draw_decompose_tmp.h @@ -54,10 +54,10 @@ FUNC(FUNC_VARS) FUNC_ENTER; - /* prim, count, and last_vertex_last should have been defined */ + /* prim, prim_flags, count, and last_vertex_last should have been defined */ if (0) { - debug_printf("%s: prim 0x%x, count %d, last_vertex_last %d\n", - __FUNCTION__, prim, count, last_vertex_last); + debug_printf("%s: prim 0x%x, prim_flags 0x%x, count %d, last_vertex_last %d\n", + __FUNCTION__, prim, prim_flags, count, last_vertex_last); } switch (prim) { @@ -80,7 +80,7 @@ FUNC(FUNC_VARS) case PIPE_PRIM_LINE_LOOP: case PIPE_PRIM_LINE_STRIP: if (count >= 2) { - flags = DRAW_PIPE_RESET_STIPPLE; + flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE; idx[1] = GET_ELT(0); idx[2] = idx[1]; @@ -90,7 +90,7 @@ FUNC(FUNC_VARS) LINE(flags, idx[0], idx[1]); } /* close the loop */ - if (prim == PIPE_PRIM_LINE_LOOP) + if (prim == PIPE_PRIM_LINE_LOOP && !prim_flags) LINE(flags, idx[1], idx[2]); } break; @@ -255,17 +255,23 @@ FUNC(FUNC_VARS) if (last_vertex_last) { flags = (DRAW_PIPE_RESET_STIPPLE | - DRAW_PIPE_EDGE_FLAG_2 | DRAW_PIPE_EDGE_FLAG_0); + if (!(prim_flags & DRAW_SPLIT_BEFORE)) + flags |= DRAW_PIPE_EDGE_FLAG_2; + edge_next = DRAW_PIPE_EDGE_FLAG_0; - edge_finish = DRAW_PIPE_EDGE_FLAG_1; + edge_finish = + (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_1; } else { flags = (DRAW_PIPE_RESET_STIPPLE | - DRAW_PIPE_EDGE_FLAG_0 | DRAW_PIPE_EDGE_FLAG_1); + if (!(prim_flags & DRAW_SPLIT_BEFORE)) + flags |= DRAW_PIPE_EDGE_FLAG_0; + edge_next = DRAW_PIPE_EDGE_FLAG_1; - edge_finish = DRAW_PIPE_EDGE_FLAG_2; + edge_finish = + (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_2; } idx[0] = GET_ELT(0); @@ -300,7 +306,7 @@ FUNC(FUNC_VARS) case PIPE_PRIM_LINE_STRIP_ADJACENCY: if (count >= 4) { - flags = DRAW_PIPE_RESET_STIPPLE; + flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE; idx[1] = GET_ELT(0); idx[2] = GET_ELT(1); idx[3] = GET_ELT(2); diff --git a/src/gallium/auxiliary/draw/draw_gs.c b/src/gallium/auxiliary/draw/draw_gs.c index 4a1013e79a..50a03ac95a 100644 --- a/src/gallium/auxiliary/draw/draw_gs.c +++ b/src/gallium/auxiliary/draw/draw_gs.c @@ -380,7 +380,7 @@ static void gs_tri_adj(struct draw_geometry_shader *shader, #define FUNC gs_run_elts #define LOCAL_VARS const ushort *elts = input_prims->elts; -#define GET_ELT(idx) (elts[idx] & ~DRAW_PIPE_FLAG_MASK) +#define GET_ELT(idx) (elts[idx]) #include "draw_gs_tmp.h" @@ -457,6 +457,7 @@ int draw_geometry_shader_run(struct draw_geometry_shader *shader, output_prims->start = 0; output_prims->count = shader->emitted_vertices; output_prims->prim = shader->output_primitive; + output_prims->flags = 0x0; output_prims->primitive_lengths = shader->primitive_lengths; output_prims->primitive_count = shader->emitted_primitives; output_verts->count = shader->emitted_vertices; diff --git a/src/gallium/auxiliary/draw/draw_gs_tmp.h b/src/gallium/auxiliary/draw/draw_gs_tmp.h index 4a17af0dea..de7b02655a 100644 --- a/src/gallium/auxiliary/draw/draw_gs_tmp.h +++ b/src/gallium/auxiliary/draw/draw_gs_tmp.h @@ -6,12 +6,10 @@ #define FUNC_ENTER \ /* declare more local vars */ \ - struct draw_context *draw = gs->draw; \ const unsigned prim = input_prims->prim; \ + const unsigned prim_flags = input_prims->flags; \ const unsigned count = input_prims->count; \ - const boolean last_vertex_last = \ - !(draw->rasterizer->flatshade && \ - draw->rasterizer->flatshade_first); \ + const boolean last_vertex_last = TRUE; \ do { \ debug_assert(input_prims->primitive_count == 1); \ switch (prim) { \ diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c index 8d53601d19..8759c38cab 100644 --- a/src/gallium/auxiliary/draw/draw_llvm.c +++ b/src/gallium/auxiliary/draw/draw_llvm.c @@ -210,13 +210,6 @@ draw_llvm_create(struct draw_context *draw) { struct draw_llvm *llvm; -#ifdef PIPE_ARCH_X86 - util_cpu_detect(); - /* require SSE2 due to LLVM PR6960. */ - if (!util_cpu_caps.has_sse2) - return NULL; -#endif - llvm = CALLOC_STRUCT( draw_llvm ); if (!llvm) return NULL; @@ -292,15 +285,23 @@ draw_llvm_destroy(struct draw_llvm *llvm) } struct draw_llvm_variant * -draw_llvm_create_variant(struct draw_llvm *llvm, int num_inputs) +draw_llvm_create_variant(struct draw_llvm *llvm, + unsigned num_inputs, + const struct draw_llvm_variant_key *key) { - struct draw_llvm_variant *variant = MALLOC(sizeof(struct draw_llvm_variant)); + struct draw_llvm_variant *variant; struct llvm_vertex_shader *shader = llvm_vertex_shader(llvm->draw->vs.vertex_shader); + variant = MALLOC(sizeof *variant + + shader->variant_key_size - + sizeof variant->key); + if (variant == NULL) + return NULL; + variant->llvm = llvm; - draw_llvm_make_variant_key(llvm, &variant->key); + memcpy(&variant->key, key, shader->variant_key_size); llvm->vertex_header_ptr_type = create_vertex_header(llvm, num_inputs); @@ -738,8 +739,9 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant) step = LLVMConstInt(LLVMInt32Type(), max_vertices, 0); /* code generated texture sampling */ - sampler = draw_llvm_sampler_soa_create(variant->key.sampler, - context_ptr); + sampler = draw_llvm_sampler_soa_create( + draw_llvm_variant_key_samplers(&variant->key), + context_ptr); #if DEBUG_STORE lp_build_printf(builder, "start = %d, end = %d, step = %d\n", @@ -901,8 +903,9 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian step = LLVMConstInt(LLVMInt32Type(), max_vertices, 0); /* code generated texture sampling */ - sampler = draw_llvm_sampler_soa_create(variant->key.sampler, - context_ptr); + sampler = draw_llvm_sampler_soa_create( + draw_llvm_variant_key_samplers(&variant->key), + context_ptr); fetch_max = LLVMBuildSub(builder, fetch_count, LLVMConstInt(LLVMInt32Type(), 1, 0), @@ -1002,35 +1005,42 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian lp_func_delete_body(variant->function_elts); } -void -draw_llvm_make_variant_key(struct draw_llvm *llvm, - struct draw_llvm_variant_key *key) + +struct draw_llvm_variant_key * +draw_llvm_make_variant_key(struct draw_llvm *llvm, char *store) { unsigned i; + struct draw_llvm_variant_key *key; + struct lp_sampler_static_state *sampler; - memset(key, 0, sizeof(struct draw_llvm_variant_key)); + key = (struct draw_llvm_variant_key *)store; + /* Presumably all variants of the shader should have the same + * number of vertex elements - ie the number of shader inputs. + */ key->nr_vertex_elements = llvm->draw->pt.nr_vertex_elements; + /* All variants of this shader will have the same value for + * nr_samplers. Not yet trying to compact away holes in the + * sampler array. + */ + key->nr_samplers = llvm->draw->vs.vertex_shader->info.file_max[TGSI_FILE_SAMPLER] + 1; + + sampler = draw_llvm_variant_key_samplers(key); + memcpy(key->vertex_element, llvm->draw->pt.vertex_element, sizeof(struct pipe_vertex_element) * key->nr_vertex_elements); + + memset(sampler, 0, key->nr_samplers * sizeof *sampler); - memcpy(&key->vs, - &llvm->draw->vs.vertex_shader->state, - sizeof(struct pipe_shader_state)); - - /* if the driver implemented the sampling hooks then - * setup our sampling state */ - if (llvm->draw->num_sampler_views && llvm->draw->num_samplers) { - for(i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; ++i) { - struct draw_vertex_shader *shader = llvm->draw->vs.vertex_shader; - if(shader->info.file_mask[TGSI_FILE_SAMPLER] & (1 << i)) - lp_sampler_static_state(&key->sampler[i], - llvm->draw->sampler_views[i], - llvm->draw->samplers[i]); - } + for (i = 0 ; i < key->nr_samplers; i++) { + lp_sampler_static_state(&sampler[i], + llvm->draw->sampler_views[i], + llvm->draw->samplers[i]); } + + return key; } void diff --git a/src/gallium/auxiliary/draw/draw_llvm.h b/src/gallium/auxiliary/draw/draw_llvm.h index 4addb47d2d..6196b2f983 100644 --- a/src/gallium/auxiliary/draw/draw_llvm.h +++ b/src/gallium/auxiliary/draw/draw_llvm.h @@ -151,12 +151,43 @@ typedef void struct draw_llvm_variant_key { - struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS]; - unsigned nr_vertex_elements; - struct pipe_shader_state vs; - struct lp_sampler_static_state sampler[PIPE_MAX_VERTEX_SAMPLERS]; + unsigned nr_vertex_elements:16; + unsigned nr_samplers:16; + + /* Variable number of vertex elements: + */ + struct pipe_vertex_element vertex_element[1]; + + /* Followed by variable number of samplers: + */ +/* struct lp_sampler_static_state sampler; */ }; +#define DRAW_LLVM_MAX_VARIANT_KEY_SIZE \ + (sizeof(struct draw_llvm_variant_key) + \ + PIPE_MAX_VERTEX_SAMPLERS * sizeof(struct lp_sampler_static_state) + \ + (PIPE_MAX_ATTRIBS-1) * sizeof(struct pipe_vertex_element)) + + +static INLINE size_t +draw_llvm_variant_key_size(unsigned nr_vertex_elements, + unsigned nr_samplers) +{ + return (sizeof(struct draw_llvm_variant_key) + + nr_samplers * sizeof(struct lp_sampler_static_state) + + (nr_vertex_elements - 1) * sizeof(struct pipe_vertex_element)); +} + + +static INLINE struct lp_sampler_static_state * +draw_llvm_variant_key_samplers(struct draw_llvm_variant_key *key) +{ + return (struct lp_sampler_static_state *) + &key->vertex_element[key->nr_vertex_elements]; +} + + + struct draw_llvm_variant_list_item { struct draw_llvm_variant *base; @@ -165,7 +196,6 @@ struct draw_llvm_variant_list_item struct draw_llvm_variant { - struct draw_llvm_variant_key key; LLVMValueRef function; LLVMValueRef function_elts; draw_jit_vert_func jit_func; @@ -176,11 +206,16 @@ struct draw_llvm_variant struct draw_llvm *llvm; struct draw_llvm_variant_list_item list_item_global; struct draw_llvm_variant_list_item list_item_local; + + /* key is variable-sized, must be last */ + struct draw_llvm_variant_key key; + /* key is variable-sized, must be last */ }; struct llvm_vertex_shader { struct draw_vertex_shader base; + unsigned variant_key_size; struct draw_llvm_variant_list_item variants; unsigned variants_created; unsigned variants_cached; @@ -220,14 +255,15 @@ void draw_llvm_destroy(struct draw_llvm *llvm); struct draw_llvm_variant * -draw_llvm_create_variant(struct draw_llvm *llvm, int num_inputs); +draw_llvm_create_variant(struct draw_llvm *llvm, + unsigned num_vertex_header_attribs, + const struct draw_llvm_variant_key *key); void draw_llvm_destroy_variant(struct draw_llvm_variant *variant); -void -draw_llvm_make_variant_key(struct draw_llvm *llvm, - struct draw_llvm_variant_key *key); +struct draw_llvm_variant_key * +draw_llvm_make_variant_key(struct draw_llvm *llvm, char *store); LLVMValueRef draw_llvm_translate_from(LLVMBuilderRef builder, diff --git a/src/gallium/auxiliary/draw/draw_pipe.c b/src/gallium/auxiliary/draw/draw_pipe.c index 58995e0724..6206197dae 100644 --- a/src/gallium/auxiliary/draw/draw_pipe.c +++ b/src/gallium/auxiliary/draw/draw_pipe.c @@ -169,35 +169,27 @@ static void do_triangle( struct draw_context *draw, /* * Set up macros for draw_pt_decompose.h template code. * This code uses vertex indexes / elements. - * - * Flags are needed by the stipple and unfilled stages. When the two stages - * are active, vcache_run_extras is called and the flags are stored in the - * higher bits of i0. Otherwise, flags do not matter. */ #define TRIANGLE(flags,i0,i1,i2) \ do { \ - assert(!((i1) & DRAW_PIPE_FLAG_MASK)); \ - assert(!((i2) & DRAW_PIPE_FLAG_MASK)); \ do_triangle( draw, \ - i0, /* flags */ \ - verts + stride * (i0 & ~DRAW_PIPE_FLAG_MASK), \ + flags, \ + verts + stride * (i0), \ verts + stride * (i1), \ verts + stride * (i2) ); \ } while (0) #define LINE(flags,i0,i1) \ do { \ - assert(!((i1) & DRAW_PIPE_FLAG_MASK)); \ do_line( draw, \ - i0, /* flags */ \ - verts + stride * (i0 & ~DRAW_PIPE_FLAG_MASK), \ + flags, \ + verts + stride * (i0), \ verts + stride * (i1) ); \ } while (0) #define POINT(i0) \ do { \ - assert(!((i0) & DRAW_PIPE_FLAG_MASK)); \ do_point( draw, verts + stride * (i0) ); \ } while (0) @@ -207,6 +199,7 @@ static void do_triangle( struct draw_context *draw, #define FUNC_VARS \ struct draw_context *draw, \ unsigned prim, \ + unsigned prim_flags, \ struct vertex_header *vertices, \ unsigned stride, \ const ushort *elts, \ @@ -245,22 +238,27 @@ void draw_pipeline_run( struct draw_context *draw, const unsigned count = prim_info->primitive_lengths[i]; #if DEBUG - /* make sure none of the element indexes go outside the vertex buffer */ + /* Warn if one of the element indexes go outside the vertex buffer */ { unsigned max_index = 0x0, i; /* find the largest element index */ for (i = 0; i < count; i++) { - unsigned int index = (prim_info->elts[start + i] - & ~DRAW_PIPE_FLAG_MASK); + unsigned int index = prim_info->elts[start + i]; if (index > max_index) max_index = index; } - assert(max_index <= vert_info->count); + if (max_index >= vert_info->count) { + debug_printf("%s: max_index (%u) outside vertex buffer (%u)\n", + __FUNCTION__, + max_index, + vert_info->count); + } } #endif pipe_run_elts(draw, prim_info->prim, + prim_info->flags, vert_info->verts, vert_info->stride, prim_info->elts + start, @@ -298,6 +296,7 @@ void draw_pipeline_run( struct draw_context *draw, #define FUNC_VARS \ struct draw_context *draw, \ unsigned prim, \ + unsigned prim_flags, \ struct vertex_header *vertices, \ unsigned stride, \ unsigned count @@ -330,6 +329,7 @@ void draw_pipeline_run_linear( struct draw_context *draw, pipe_run_linear(draw, prim_info->prim, + prim_info->flags, (struct vertex_header*)verts, vert_info->stride, count); diff --git a/src/gallium/auxiliary/draw/draw_pipe_validate.c b/src/gallium/auxiliary/draw/draw_pipe_validate.c index eafa29276f..8b92543987 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_validate.c +++ b/src/gallium/auxiliary/draw/draw_pipe_validate.c @@ -265,7 +265,7 @@ static struct draw_stage *validate_pipeline( struct draw_stage *stage ) /* Clip stage */ - if (!draw->bypass_clipping) + if (draw->clip_xy || draw->clip_z || draw->clip_user) { draw->pipeline.clip->next = next; next = draw->pipeline.clip; diff --git a/src/gallium/auxiliary/draw/draw_pipe_vbuf.c b/src/gallium/auxiliary/draw/draw_pipe_vbuf.c index 3c93c9014a..58c5858734 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_vbuf.c +++ b/src/gallium/auxiliary/draw/draw_pipe_vbuf.c @@ -353,9 +353,6 @@ vbuf_alloc_vertices( struct vbuf_stage *vbuf ) /* Allocate a new vertex buffer */ vbuf->max_vertices = vbuf->render->max_vertex_buffer_bytes / vbuf->vertex_size; - /* even number */ - vbuf->max_vertices = vbuf->max_vertices & ~1; - if(vbuf->max_vertices >= UNDEFINED_VERTEX_ID) vbuf->max_vertices = UNDEFINED_VERTEX_ID - 1; diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index 397d4bf653..362f563ba6 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -140,8 +140,7 @@ struct draw_context } middle; struct { - struct draw_pt_front_end *vcache; - struct draw_pt_front_end *varray; + struct draw_pt_front_end *vsplit; } front; struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS]; @@ -150,6 +149,8 @@ struct draw_context struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS]; unsigned nr_vertex_elements; + struct pipe_index_buffer index_buffer; + /* user-space vertex data, buffers */ struct { /** vertex element/index buffer (ex: glDrawElements) */ @@ -175,13 +176,19 @@ struct draw_context } pt; struct { - boolean bypass_clipping; - boolean bypass_vs; + boolean bypass_clip_xy; + boolean bypass_clip_z; } driver; boolean flushing; /**< debugging/sanity */ boolean suspend_flushing; /**< internally set */ - boolean bypass_clipping; /**< set if either api or driver bypass_clipping true */ + + /* Flags set if API requires clipping in these planes and the + * driver doesn't indicate that it can do it for us. + */ + boolean clip_xy; + boolean clip_z; + boolean clip_user; boolean force_passthrough; /**< never clip or shade */ @@ -296,6 +303,10 @@ struct draw_vertex_info { unsigned count; }; +/* these flags are set if the primitive is a segment of a larger one */ +#define DRAW_SPLIT_BEFORE 0x1 +#define DRAW_SPLIT_AFTER 0x2 + struct draw_prim_info { boolean linear; unsigned start; @@ -304,6 +315,7 @@ struct draw_prim_info { unsigned count; unsigned prim; + unsigned flags; unsigned *primitive_lengths; unsigned primitive_count; }; @@ -369,21 +381,15 @@ void draw_pipeline_destroy( struct draw_context *draw ); -/* We use the top few bits in the elts[] parameter to convey a little - * API information. This limits the number of vertices we can address - * to only 4096 -- if that becomes a problem, we can switch to 32-bit - * draw indices. - * - * These flags expected at first vertex of lines & triangles when - * unfilled and/or line stipple modes are operational. +/* + * These flags are used by the pipeline when unfilled and/or line stipple modes + * are operational. */ -#define DRAW_PIPE_MAX_VERTICES (0x1<<12) -#define DRAW_PIPE_EDGE_FLAG_0 (0x1<<12) -#define DRAW_PIPE_EDGE_FLAG_1 (0x2<<12) -#define DRAW_PIPE_EDGE_FLAG_2 (0x4<<12) -#define DRAW_PIPE_EDGE_FLAG_ALL (0x7<<12) -#define DRAW_PIPE_RESET_STIPPLE (0x8<<12) -#define DRAW_PIPE_FLAG_MASK (0xf<<12) +#define DRAW_PIPE_EDGE_FLAG_0 0x1 +#define DRAW_PIPE_EDGE_FLAG_1 0x2 +#define DRAW_PIPE_EDGE_FLAG_2 0x4 +#define DRAW_PIPE_EDGE_FLAG_ALL 0x7 +#define DRAW_PIPE_RESET_STIPPLE 0x8 void draw_pipeline_run( struct draw_context *draw, const struct draw_vertex_info *vert, diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c index 248927505d..f44bf2507c 100644 --- a/src/gallium/auxiliary/draw/draw_pt.c +++ b/src/gallium/auxiliary/draw/draw_pt.c @@ -39,25 +39,14 @@ #include "util/u_math.h" #include "util/u_prim.h" #include "util/u_format.h" +#include "util/u_draw.h" DEBUG_GET_ONCE_BOOL_OPTION(draw_fse, "DRAW_FSE", FALSE) DEBUG_GET_ONCE_BOOL_OPTION(draw_no_fse, "DRAW_NO_FSE", FALSE) -#ifdef HAVE_LLVM -DEBUG_GET_ONCE_BOOL_OPTION(draw_use_llvm, "DRAW_USE_LLVM", TRUE) -#endif - -static unsigned trim( unsigned count, unsigned first, unsigned incr ) -{ - if (count < first) - return 0; - return count - (count - first) % incr; -} - - /* Overall we split things into: - * - frontend -- prepare fetch_elts, draw_elts - eg vcache + * - frontend -- prepare fetch_elts, draw_elts - eg vsplit * - middle -- fetch, shade, cliptest, viewport * - pipeline -- the prim pipeline: clipping, wide lines, etc * - backend -- the vbuf_render provided by the driver. @@ -77,7 +66,7 @@ draw_pt_arrays(struct draw_context *draw, { unsigned first, incr; draw_pt_split_prim(prim, &first, &incr); - count = trim(count, first, incr); + count = draw_pt_trim_count(count, first, incr); if (count < first) return TRUE; } @@ -97,7 +86,9 @@ draw_pt_arrays(struct draw_context *draw, opt |= PT_PIPELINE; } - if (!draw->bypass_clipping && !draw->pt.test_fse) { + if ((draw->clip_xy || + draw->clip_z || + draw->clip_user) && !draw->pt.test_fse) { opt |= PT_CLIPTEST; } @@ -115,22 +106,11 @@ draw_pt_arrays(struct draw_context *draw, middle = draw->pt.middle.general; } - - /* Pick the right frontend - */ - if (draw->pt.user.elts || (opt & PT_PIPELINE)) { - frontend = draw->pt.front.vcache; - } else { - frontend = draw->pt.front.varray; - } + frontend = draw->pt.front.vsplit; frontend->prepare( frontend, prim, middle, opt ); - frontend->run(frontend, - draw_pt_elt_func(draw), - draw_pt_elt_ptr(draw, start), - draw->pt.user.eltBias, - count); + frontend->run(frontend, start, count); frontend->finish( frontend ); @@ -143,12 +123,8 @@ boolean draw_pt_init( struct draw_context *draw ) draw->pt.test_fse = debug_get_option_draw_fse(); draw->pt.no_fse = debug_get_option_draw_no_fse(); - draw->pt.front.vcache = draw_pt_vcache( draw ); - if (!draw->pt.front.vcache) - return FALSE; - - draw->pt.front.varray = draw_pt_varray(draw); - if (!draw->pt.front.varray) + draw->pt.front.vsplit = draw_pt_vsplit(draw); + if (!draw->pt.front.vsplit) return FALSE; draw->pt.middle.fetch_emit = draw_pt_fetch_emit( draw ); @@ -164,7 +140,7 @@ boolean draw_pt_init( struct draw_context *draw ) return FALSE; #if HAVE_LLVM - if (debug_get_option_draw_use_llvm()) + if (draw->llvm) draw->pt.middle.llvm = draw_pt_fetch_pipeline_or_emit_llvm( draw ); #endif @@ -194,14 +170,9 @@ void draw_pt_destroy( struct draw_context *draw ) draw->pt.middle.fetch_shade_emit = NULL; } - if (draw->pt.front.vcache) { - draw->pt.front.vcache->destroy( draw->pt.front.vcache ); - draw->pt.front.vcache = NULL; - } - - if (draw->pt.front.varray) { - draw->pt.front.varray->destroy( draw->pt.front.varray ); - draw->pt.front.varray = NULL; + if (draw->pt.front.vsplit) { + draw->pt.front.vsplit->destroy( draw->pt.front.vsplit ); + draw->pt.front.vsplit = NULL; } } @@ -221,24 +192,29 @@ draw_print_arrays(struct draw_context *draw, uint prim, int start, uint count) uint ii = 0; uint j; - if (draw->pt.user.elts) { + if (draw->pt.user.eltSize) { + const char *elts; + /* indexed arrays */ + elts = (const char *) draw->pt.user.elts; + elts += draw->pt.index_buffer.offset; + switch (draw->pt.user.eltSize) { case 1: { - const ubyte *elem = (const ubyte *) draw->pt.user.elts; + const ubyte *elem = (const ubyte *) elts; ii = elem[start + i]; } break; case 2: { - const ushort *elem = (const ushort *) draw->pt.user.elts; + const ushort *elem = (const ushort *) elts; ii = elem[start + i]; } break; case 4: { - const uint *elem = (const uint *) draw->pt.user.elts; + const uint *elem = (const uint *) elts; ii = elem[start + i]; } break; @@ -324,17 +300,8 @@ draw_arrays(struct draw_context *draw, unsigned prim, /** - * Draw vertex arrays. - * This is the main entrypoint into the drawing module. - * If drawing an indexed primitive, the draw_set_mapped_element_buffer_range() - * function should have already been called to specify the element/index buffer - * information. - * - * \param prim one of PIPE_PRIM_x - * \param start index of first vertex to draw - * \param count number of vertices to draw - * \param startInstance number for the first primitive instance (usually 0). - * \param instanceCount number of instances to draw (1=non-instanced) + * Instanced drawing. + * \sa draw_vbo */ void draw_arrays_instanced(struct draw_context *draw, @@ -344,10 +311,50 @@ draw_arrays_instanced(struct draw_context *draw, unsigned startInstance, unsigned instanceCount) { - unsigned reduced_prim = u_reduced_prim(mode); + struct pipe_draw_info info; + + util_draw_init_info(&info); + + info.mode = mode; + info.start = start; + info.count = count; + info.start_instance = startInstance; + info.instance_count = instanceCount; + + info.indexed = (draw->pt.user.elts != NULL); + if (!info.indexed) { + info.min_index = start; + info.max_index = start + count - 1; + } + + draw_vbo(draw, &info); +} + + +/** + * Draw vertex arrays. + * This is the main entrypoint into the drawing module. If drawing an indexed + * primitive, the draw_set_index_buffer() and draw_set_mapped_index_buffer() + * functions should have already been called to specify the element/index + * buffer information. + */ +void +draw_vbo(struct draw_context *draw, + const struct pipe_draw_info *info) +{ + unsigned reduced_prim = u_reduced_prim(info->mode); unsigned instance; - assert(instanceCount > 0); + assert(info->instance_count > 0); + if (info->indexed) + assert(draw->pt.user.elts); + + draw->pt.user.eltSize = + (info->indexed) ? draw->pt.index_buffer.index_size : 0; + + draw->pt.user.eltBias = info->index_bias; + draw->pt.user.min_index = info->min_index; + draw->pt.user.max_index = info->max_index; if (reduced_prim != draw->reduced_prim) { draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE); @@ -355,8 +362,8 @@ draw_arrays_instanced(struct draw_context *draw, } if (0) - debug_printf("draw_arrays(mode=%u start=%u count=%u):\n", - mode, start, count); + debug_printf("draw_vbo(mode=%u start=%u count=%u):\n", + info->mode, info->start, info->count); if (0) tgsi_dump(draw->vs.vertex_shader->state.tokens, 0); @@ -384,10 +391,10 @@ draw_arrays_instanced(struct draw_context *draw, } if (0) - draw_print_arrays(draw, mode, start, MIN2(count, 20)); + draw_print_arrays(draw, info->mode, info->start, MIN2(info->count, 20)); - for (instance = 0; instance < instanceCount; instance++) { - draw->instance_id = instance + startInstance; - draw_pt_arrays(draw, mode, start, count); + for (instance = 0; instance < info->instance_count; instance++) { + draw->instance_id = instance + info->start_instance; + draw_pt_arrays(draw, info->mode, info->start, info->count); } } diff --git a/src/gallium/auxiliary/draw/draw_pt.h b/src/gallium/auxiliary/draw/draw_pt.h index 44356fba4c..5fbb424291 100644 --- a/src/gallium/auxiliary/draw/draw_pt.h +++ b/src/gallium/auxiliary/draw/draw_pt.h @@ -35,8 +35,6 @@ #include "pipe/p_compiler.h" -typedef unsigned (*pt_elt_func)( const void *elts, unsigned idx ); - struct draw_pt_middle_end; struct draw_context; struct draw_prim_info; @@ -52,13 +50,18 @@ struct draw_vertex_info; /* The "front end" - prepare sets of fetch, draw elements for the * middle end. * - * Currenly one version of this: - * - vcache - catchall implementation, decomposes to TRI/LINE/POINT prims - * Later: - * - varray, varray_split - * - velement, velement_split + * The fetch elements are indices to the vertices. The draw elements are + * indices to the fetched vertices. When both arrays of elements are both + * linear, middle->run_linear is called; When only the fetch elements are + * linear, middle->run_linear_elts is called; Otherwise, middle->run is + * called. + * + * When the number of the draw elements exceeds max_vertex of the middle end, + * the draw elements (as well as the fetch elements) are splitted and the + * middle end is called multiple times. * - * Currenly only using the vcache version. + * Currenly there is: + * - vsplit - catchall implementation, splits big prims */ struct draw_pt_front_end { void (*prepare)( struct draw_pt_front_end *, @@ -67,9 +70,7 @@ struct draw_pt_front_end { unsigned opt ); void (*run)( struct draw_pt_front_end *, - pt_elt_func elt_func, - const void *elt_ptr, - int elt_bias, + unsigned start, unsigned count ); void (*finish)( struct draw_pt_front_end * ); @@ -80,6 +81,8 @@ struct draw_pt_front_end { /* The "middle end" - prepares actual hardware vertices for the * hardware backend. * + * prim_flags is as defined by pipe_draw_info::flags. + * * Currently two versions of this: * - fetch, vertex shade, cliptest, prim-pipeline * - fetch, emit (ie passthrough) @@ -94,11 +97,13 @@ struct draw_pt_middle_end { const unsigned *fetch_elts, unsigned fetch_count, const ushort *draw_elts, - unsigned draw_count ); + unsigned draw_count, + unsigned prim_flags ); void (*run_linear)(struct draw_pt_middle_end *, unsigned start, - unsigned count); + unsigned count, + unsigned prim_flags ); /* Transform all vertices in a linear range and then draw them with * the supplied element list. May fail and return FALSE. @@ -107,7 +112,8 @@ struct draw_pt_middle_end { unsigned fetch_start, unsigned fetch_count, const ushort *draw_elts, - unsigned draw_count ); + unsigned draw_count, + unsigned prim_flags ); int (*get_max_vertex_count)( struct draw_pt_middle_end * ); @@ -122,19 +128,11 @@ struct vbuf_render; struct vertex_header; -/* Helper functions. - */ -pt_elt_func draw_pt_elt_func( struct draw_context *draw ); -const void *draw_pt_elt_ptr( struct draw_context *draw, - unsigned start ); - /* Frontends: * - * Currently only the general-purpose vcache implementation, could add - * a special case for tiny vertex buffers. + * Currently only the general-purpose vsplit implementation. */ -struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw ); -struct draw_pt_front_end *draw_pt_varray(struct draw_context *draw); +struct draw_pt_front_end *draw_pt_vsplit(struct draw_context *draw); /* Middle-ends: @@ -223,7 +221,9 @@ boolean draw_pt_post_vs_run( struct pt_post_vs *pvs, struct draw_vertex_info *info ); void draw_pt_post_vs_prepare( struct pt_post_vs *pvs, - boolean bypass_clipping, + boolean clip_xy, + boolean clip_z, + boolean clip_user, boolean bypass_viewport, boolean opengl, boolean need_edgeflags ); @@ -237,6 +237,7 @@ void draw_pt_post_vs_destroy( struct pt_post_vs *pvs ); * Utils: */ void draw_pt_split_prim(unsigned prim, unsigned *first, unsigned *incr); +unsigned draw_pt_trim_count(unsigned count, unsigned first, unsigned incr); #endif diff --git a/src/gallium/auxiliary/draw/draw_pt_elts.c b/src/gallium/auxiliary/draw/draw_pt_elts.c deleted file mode 100644 index 88f4d9f495..0000000000 --- a/src/gallium/auxiliary/draw/draw_pt_elts.c +++ /dev/null @@ -1,89 +0,0 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - - /* - * Authors: - * Keith Whitwell <keith@tungstengraphics.com> - */ - -#include "draw/draw_pt.h" -#include "draw/draw_private.h" - -/* Neat get_elt func that also works for varrays drawing by encoding - * the start value into a pointer. - */ - -static unsigned elt_uint( const void *elts, unsigned idx ) -{ - return *(((const uint *)elts) + idx); -} - -static unsigned elt_ushort( const void *elts, unsigned idx ) -{ - return *(((const ushort *)elts) + idx); -} - -static unsigned elt_ubyte( const void *elts, unsigned idx ) -{ - return *(((const ubyte *)elts) + idx); -} - -static unsigned elt_vert( const void *elts, unsigned idx ) -{ - /* unsigned index is packed in the pointer */ - return (unsigned)(uintptr_t)elts + idx; -} - -pt_elt_func draw_pt_elt_func( struct draw_context *draw ) -{ - switch (draw->pt.user.eltSize) { - case 0: return &elt_vert; - case 1: return &elt_ubyte; - case 2: return &elt_ushort; - case 4: return &elt_uint; - default: return NULL; - } -} - -const void *draw_pt_elt_ptr( struct draw_context *draw, - unsigned start ) -{ - const char *elts = draw->pt.user.elts; - - switch (draw->pt.user.eltSize) { - case 0: - return (const void *)(((const ubyte *)NULL) + start); - case 1: - return (const void *)(((const ubyte *)elts) + start); - case 2: - return (const void *)(((const ushort *)elts) + start); - case 4: - return (const void *)(((const uint *)elts) + start); - default: - return NULL; - } -} diff --git a/src/gallium/auxiliary/draw/draw_pt_emit.c b/src/gallium/auxiliary/draw/draw_pt_emit.c index 5568fbb9f8..c8dfc16911 100644 --- a/src/gallium/auxiliary/draw/draw_pt_emit.c +++ b/src/gallium/auxiliary/draw/draw_pt_emit.c @@ -120,9 +120,6 @@ void draw_pt_emit_prepare( struct pt_emit *emit, *max_vertices = (draw->render->max_vertex_buffer_bytes / (vinfo->size * 4)); - - /* even number */ - *max_vertices = *max_vertices & ~1; } @@ -147,11 +144,6 @@ void draw_pt_emit( struct pt_emit *emit, if (vertex_count == 0) return; - if (vertex_count >= UNDEFINED_VERTEX_ID) { - assert(0); - return; - } - /* XXX: and work out some way to coordinate the render primitive * between vbuf.c and here... */ @@ -226,9 +218,6 @@ void draw_pt_emit_linear(struct pt_emit *emit, */ draw_do_flush( draw, DRAW_FLUSH_BACKEND ); - if (count >= UNDEFINED_VERTEX_ID) - goto fail; - /* XXX: and work out some way to coordinate the render primitive * between vbuf.c and here... */ diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c b/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c index 5c8af17c8e..e706b7796f 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c @@ -191,15 +191,6 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle, *max_vertices = (draw->render->max_vertex_buffer_bytes / (vinfo->size * 4)); - - /* Return an even number of verts. - * This prevents "parity" errors when splitting long triangle strips which - * can lead to front/back culling mix-ups. - * Every other triangle in a strip has an alternate front/back orientation - * so splitting at an odd position can cause the orientation of subsequent - * triangles to get reversed. - */ - *max_vertices = *max_vertices & ~1; } @@ -210,7 +201,8 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle, const unsigned *fetch_elts, unsigned fetch_count, const ushort *draw_elts, - unsigned draw_count ) + unsigned draw_count, + unsigned prim_flags ) { struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle; struct draw_context *draw = feme->draw; @@ -220,11 +212,6 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle, */ draw_do_flush( draw, DRAW_FLUSH_BACKEND ); - if (fetch_count >= UNDEFINED_VERTEX_ID) { - assert(0); - return; - } - draw->render->allocate_vertices( draw->render, (ushort)feme->translate->key.output_stride, (ushort)fetch_count ); @@ -273,7 +260,8 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle, static void fetch_emit_run_linear( struct draw_pt_middle_end *middle, unsigned start, - unsigned count ) + unsigned count, + unsigned prim_flags ) { struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle; struct draw_context *draw = feme->draw; @@ -283,9 +271,6 @@ static void fetch_emit_run_linear( struct draw_pt_middle_end *middle, */ draw_do_flush( draw, DRAW_FLUSH_BACKEND ); - if (count >= UNDEFINED_VERTEX_ID) - goto fail; - if (!draw->render->allocate_vertices( draw->render, (ushort)feme->translate->key.output_stride, (ushort)count )) @@ -334,7 +319,8 @@ static boolean fetch_emit_run_linear_elts( struct draw_pt_middle_end *middle, unsigned start, unsigned count, const ushort *draw_elts, - unsigned draw_count ) + unsigned draw_count, + unsigned prim_flags ) { struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle; struct draw_context *draw = feme->draw; @@ -344,9 +330,6 @@ static boolean fetch_emit_run_linear_elts( struct draw_pt_middle_end *middle, */ draw_do_flush( draw, DRAW_FLUSH_BACKEND ); - if (count >= UNDEFINED_VERTEX_ID) - return FALSE; - if (!draw->render->allocate_vertices( draw->render, (ushort)feme->translate->key.output_stride, (ushort)count )) diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c index b8270280b6..7c198c6026 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c @@ -102,7 +102,7 @@ static void fse_prepare( struct draw_pt_middle_end *middle, fse->key.nr_inputs); /* inputs - fetch from api format */ fse->key.viewport = !draw->identity_viewport; - fse->key.clip = !draw->bypass_clipping; + fse->key.clip = draw->clip_xy || draw->clip_z || draw->clip_user; fse->key.const_vbuffers = 0; memset(fse->key.element, 0, @@ -175,15 +175,6 @@ static void fse_prepare( struct draw_pt_middle_end *middle, *max_vertices = (draw->render->max_vertex_buffer_bytes / (vinfo->size * 4)); - /* Return an even number of verts. - * This prevents "parity" errors when splitting long triangle strips which - * can lead to front/back culling mix-ups. - * Every other triangle in a strip has an alternate front/back orientation - * so splitting at an odd position can cause the orientation of subsequent - * triangles to get reversed. - */ - *max_vertices = *max_vertices & ~1; - /* Probably need to do this somewhere (or fix exec shader not to * need it): */ @@ -197,7 +188,8 @@ static void fse_prepare( struct draw_pt_middle_end *middle, static void fse_run_linear( struct draw_pt_middle_end *middle, unsigned start, - unsigned count ) + unsigned count, + unsigned prim_flags ) { struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle; struct draw_context *draw = fse->draw; @@ -207,9 +199,6 @@ static void fse_run_linear( struct draw_pt_middle_end *middle, */ draw_do_flush( draw, DRAW_FLUSH_BACKEND ); - if (count >= UNDEFINED_VERTEX_ID) - goto fail; - if (!draw->render->allocate_vertices( draw->render, (ushort)fse->key.output_stride, (ushort)count )) @@ -265,7 +254,8 @@ fse_run(struct draw_pt_middle_end *middle, const unsigned *fetch_elts, unsigned fetch_count, const ushort *draw_elts, - unsigned draw_count ) + unsigned draw_count, + unsigned prim_flags ) { struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle; struct draw_context *draw = fse->draw; @@ -275,9 +265,6 @@ fse_run(struct draw_pt_middle_end *middle, */ draw_do_flush( draw, DRAW_FLUSH_BACKEND ); - if (fetch_count >= UNDEFINED_VERTEX_ID) - goto fail; - if (!draw->render->allocate_vertices( draw->render, (ushort)fse->key.output_stride, (ushort)fetch_count )) @@ -327,7 +314,8 @@ static boolean fse_run_linear_elts( struct draw_pt_middle_end *middle, unsigned start, unsigned count, const ushort *draw_elts, - unsigned draw_count ) + unsigned draw_count, + unsigned prim_flags ) { struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle; struct draw_context *draw = fse->draw; @@ -337,9 +325,6 @@ static boolean fse_run_linear_elts( struct draw_pt_middle_end *middle, */ draw_do_flush( draw, DRAW_FLUSH_BACKEND ); - if (count >= UNDEFINED_VERTEX_ID) - return FALSE; - if (!draw->render->allocate_vertices( draw->render, (ushort)fse->key.output_stride, (ushort)count )) diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c index 5b16c3788e..b72fd61245 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c @@ -100,8 +100,10 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, * but gl vs dx9 clip spaces. */ draw_pt_post_vs_prepare( fpme->post_vs, - (boolean)draw->bypass_clipping, - (boolean)draw->identity_viewport, + draw->clip_xy, + draw->clip_z, + draw->clip_user, + draw->identity_viewport, (boolean)draw->rasterizer->gl_rasterization_rules, (draw->vs.edgeflag_output ? TRUE : FALSE) ); @@ -112,16 +114,13 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, gs_out_prim, max_vertices ); - *max_vertices = MAX2( *max_vertices, - DRAW_PIPE_MAX_VERTICES ); + *max_vertices = MAX2( *max_vertices, 4096 ); } else { - *max_vertices = DRAW_PIPE_MAX_VERTICES; + /* limit max fetches by limiting max_vertices */ + *max_vertices = 4096; } - /* return even number */ - *max_vertices = *max_vertices & ~1; - /* No need to prepare the shader. */ vs->prepare(vs, draw); @@ -295,7 +294,8 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle, const unsigned *fetch_elts, unsigned fetch_count, const ushort *draw_elts, - unsigned draw_count ) + unsigned draw_count, + unsigned prim_flags ) { struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; struct draw_fetch_info fetch_info; @@ -311,6 +311,7 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle, prim_info.count = draw_count; prim_info.elts = draw_elts; prim_info.prim = fpme->input_prim; + prim_info.flags = prim_flags; prim_info.primitive_count = 1; prim_info.primitive_lengths = &draw_count; @@ -320,7 +321,8 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle, static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle, unsigned start, - unsigned count) + unsigned count, + unsigned prim_flags) { struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; struct draw_fetch_info fetch_info; @@ -336,6 +338,7 @@ static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle, prim_info.count = count; prim_info.elts = NULL; prim_info.prim = fpme->input_prim; + prim_info.flags = prim_flags; prim_info.primitive_count = 1; prim_info.primitive_lengths = &count; @@ -348,7 +351,8 @@ static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle unsigned start, unsigned count, const ushort *draw_elts, - unsigned draw_count ) + unsigned draw_count, + unsigned prim_flags ) { struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; struct draw_fetch_info fetch_info; @@ -364,6 +368,7 @@ static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle prim_info.count = draw_count; prim_info.elts = draw_elts; prim_info.prim = fpme->input_prim; + prim_info.flags = prim_flags; prim_info.primitive_count = 1; prim_info.primitive_lengths = &draw_count; diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c index 4b99bee86a..77291e304e 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c @@ -66,7 +66,8 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle, struct draw_context *draw = fpme->draw; struct llvm_vertex_shader *shader = llvm_vertex_shader(draw->vs.vertex_shader); - struct draw_llvm_variant_key key; + char store[DRAW_LLVM_MAX_VARIANT_KEY_SIZE]; + struct draw_llvm_variant_key *key; struct draw_llvm_variant *variant = NULL; struct draw_llvm_variant_list_item *li; unsigned i; @@ -106,8 +107,10 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle, * but gl vs dx9 clip spaces. */ draw_pt_post_vs_prepare( fpme->post_vs, - (boolean)draw->bypass_clipping, - (boolean)(draw->identity_viewport), + draw->clip_xy, + draw->clip_z, + draw->clip_user, + draw->identity_viewport, (boolean)draw->rasterizer->gl_rasterization_rules, (draw->vs.edgeflag_output ? TRUE : FALSE) ); @@ -118,21 +121,21 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle, out_prim, max_vertices ); - *max_vertices = MAX2( *max_vertices, - DRAW_PIPE_MAX_VERTICES ); + *max_vertices = MAX2( *max_vertices, 4096 ); } else { - *max_vertices = DRAW_PIPE_MAX_VERTICES; + /* limit max fetches by limiting max_vertices */ + *max_vertices = 4096; } /* return even number */ *max_vertices = *max_vertices & ~1; - - draw_llvm_make_variant_key(fpme->llvm, &key); + + key = draw_llvm_make_variant_key(fpme->llvm, store); li = first_elem(&shader->variants); while(!at_end(&shader->variants, li)) { - if(memcmp(&li->base->key, &key, sizeof key) == 0) { + if(memcmp(&li->base->key, key, shader->variant_key_size) == 0) { variant = li->base; break; } @@ -155,7 +158,7 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle, } } - variant = draw_llvm_create_variant(fpme->llvm, nr); + variant = draw_llvm_create_variant(fpme->llvm, nr, key); if (variant) { insert_at_head(&shader->variants, &variant->list_item_local); @@ -294,7 +297,8 @@ static void llvm_middle_end_run( struct draw_pt_middle_end *middle, const unsigned *fetch_elts, unsigned fetch_count, const ushort *draw_elts, - unsigned draw_count ) + unsigned draw_count, + unsigned prim_flags ) { struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle; struct draw_fetch_info fetch_info; @@ -310,6 +314,7 @@ static void llvm_middle_end_run( struct draw_pt_middle_end *middle, prim_info.count = draw_count; prim_info.elts = draw_elts; prim_info.prim = fpme->input_prim; + prim_info.flags = prim_flags; prim_info.primitive_count = 1; prim_info.primitive_lengths = &draw_count; @@ -319,7 +324,8 @@ static void llvm_middle_end_run( struct draw_pt_middle_end *middle, static void llvm_middle_end_linear_run( struct draw_pt_middle_end *middle, unsigned start, - unsigned count) + unsigned count, + unsigned prim_flags) { struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle; struct draw_fetch_info fetch_info; @@ -335,6 +341,7 @@ static void llvm_middle_end_linear_run( struct draw_pt_middle_end *middle, prim_info.count = count; prim_info.elts = NULL; prim_info.prim = fpme->input_prim; + prim_info.flags = prim_flags; prim_info.primitive_count = 1; prim_info.primitive_lengths = &count; @@ -348,7 +355,8 @@ llvm_middle_end_linear_run_elts( struct draw_pt_middle_end *middle, unsigned start, unsigned count, const ushort *draw_elts, - unsigned draw_count ) + unsigned draw_count, + unsigned prim_flags ) { struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle; struct draw_fetch_info fetch_info; @@ -364,6 +372,7 @@ llvm_middle_end_linear_run_elts( struct draw_pt_middle_end *middle, prim_info.count = draw_count; prim_info.elts = draw_elts; prim_info.prim = fpme->input_prim; + prim_info.flags = prim_flags; prim_info.primitive_count = 1; prim_info.primitive_lengths = &draw_count; diff --git a/src/gallium/auxiliary/draw/draw_pt_post_vs.c b/src/gallium/auxiliary/draw/draw_pt_post_vs.c index 308f927b77..769409cfd6 100644 --- a/src/gallium/auxiliary/draw/draw_pt_post_vs.c +++ b/src/gallium/auxiliary/draw/draw_pt_post_vs.c @@ -26,14 +26,26 @@ **************************************************************************/ #include "util/u_memory.h" +#include "util/u_math.h" #include "pipe/p_context.h" #include "draw/draw_context.h" #include "draw/draw_private.h" #include "draw/draw_pt.h" + +#define DO_CLIP_XY 0x1 +#define DO_CLIP_FULL_Z 0x2 +#define DO_CLIP_HALF_Z 0x4 +#define DO_CLIP_USER 0x8 +#define DO_VIEWPORT 0x10 +#define DO_EDGEFLAG 0x20 + + struct pt_post_vs { struct draw_context *draw; + unsigned flags; + boolean (*run)( struct pt_post_vs *pvs, struct draw_vertex_info *info ); }; @@ -56,186 +68,47 @@ dot4(const float *a, const float *b) a[3]*b[3]); } -static INLINE unsigned -compute_clipmask_gl(const float *clip, /*const*/ float plane[][4], unsigned nr, - boolean clip_depth) -{ - unsigned mask = 0x0; - unsigned i; +#define FLAGS (0) +#define TAG(x) x##_none +#include "draw_cliptest_tmp.h" -#if 0 - debug_printf("compute clipmask %f %f %f %f\n", - clip[0], clip[1], clip[2], clip[3]); - assert(clip[3] != 0.0); -#endif +#define FLAGS (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_VIEWPORT) +#define TAG(x) x##_xy_fullz_viewport +#include "draw_cliptest_tmp.h" - /* Do the hardwired planes first: - */ - if (-clip[0] + clip[3] < 0) mask |= (1<<0); - if ( clip[0] + clip[3] < 0) mask |= (1<<1); - if (-clip[1] + clip[3] < 0) mask |= (1<<2); - if ( clip[1] + clip[3] < 0) mask |= (1<<3); - if (clip_depth) { - if ( clip[2] + clip[3] < 0) mask |= (1<<4); /* match mesa clipplane numbering - for now */ - if (-clip[2] + clip[3] < 0) mask |= (1<<5); /* match mesa clipplane numbering - for now */ - } +#define FLAGS (DO_CLIP_XY | DO_CLIP_HALF_Z | DO_VIEWPORT) +#define TAG(x) x##_xy_halfz_viewport +#include "draw_cliptest_tmp.h" - /* Followed by any remaining ones: - */ - for (i = 6; i < nr; i++) { - if (dot4(clip, plane[i]) < 0) - mask |= (1<<i); - } +#define FLAGS (DO_CLIP_FULL_Z | DO_VIEWPORT) +#define TAG(x) x##_fullz_viewport +#include "draw_cliptest_tmp.h" - return mask; -} +#define FLAGS (DO_CLIP_HALF_Z | DO_VIEWPORT) +#define TAG(x) x##_halfz_viewport +#include "draw_cliptest_tmp.h" +#define FLAGS (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | DO_VIEWPORT) +#define TAG(x) x##_xy_fullz_user_viewport +#include "draw_cliptest_tmp.h" -/* The normal case - cliptest, rhw divide, viewport transform. - * - * Also handle identity viewport here at the expense of a few wasted - * instructions - */ -static boolean post_vs_cliptest_viewport_gl( struct pt_post_vs *pvs, - struct draw_vertex_info *info ) -{ - struct vertex_header *out = info->verts; - const float *scale = pvs->draw->viewport.scale; - const float *trans = pvs->draw->viewport.translate; - const unsigned pos = draw_current_shader_position_output(pvs->draw); - unsigned clipped = 0; - unsigned j; - - if (0) debug_printf("%s count, %d\n", __FUNCTION__, info->count); - - for (j = 0; j < info->count; j++) { - float *position = out->data[pos]; - - initialize_vertex_header(out); -#if 0 - debug_printf("%d) io = %p, data = %p = [%f, %f, %f, %f]\n", - j, out, position, position[0], position[1], position[2], position[3]); -#endif - - out->clip[0] = position[0]; - out->clip[1] = position[1]; - out->clip[2] = position[2]; - out->clip[3] = position[3]; - - out->vertex_id = 0xffff; - /* Disable depth clipping if depth clamping is enabled. */ - out->clipmask = compute_clipmask_gl(out->clip, - pvs->draw->plane, - pvs->draw->nr_planes, - !pvs->draw->depth_clamp); - clipped += out->clipmask; - - if (out->clipmask == 0) - { - /* divide by w */ - float w = 1.0f / position[3]; - - /* Viewport mapping */ - position[0] = position[0] * w * scale[0] + trans[0]; - position[1] = position[1] * w * scale[1] + trans[1]; - position[2] = position[2] * w * scale[2] + trans[2]; - position[3] = w; -#if 0 - debug_printf("post viewport: %f %f %f %f\n", - position[0], - position[1], - position[2], - position[3]); -#endif - } - - out = (struct vertex_header *)( (char *)out + info->stride ); - } - - return clipped != 0; -} +#define FLAGS (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | DO_VIEWPORT | DO_EDGEFLAG) +#define TAG(x) x##_xy_fullz_user_viewport_edgeflag +#include "draw_cliptest_tmp.h" -/* As above plus edgeflags +/* Don't want to create 64 versions of this function, so catch the + * less common ones here. This is looking like something which should + * be code-generated, perhaps appended to the end of the vertex + * shader. */ -static boolean -post_vs_cliptest_viewport_gl_edgeflag(struct pt_post_vs *pvs, - struct draw_vertex_info *info) -{ - unsigned j; - boolean needpipe; - - needpipe = post_vs_cliptest_viewport_gl(pvs, info); - - /* If present, copy edgeflag VS output into vertex header. - * Otherwise, leave header as is. - */ - if (pvs->draw->vs.edgeflag_output) { - struct vertex_header *out = info->verts; - int ef = pvs->draw->vs.edgeflag_output; - - for (j = 0; j < info->count; j++) { - const float *edgeflag = out->data[ef]; - out->edgeflag = !(edgeflag[0] != 1.0f); - needpipe |= !out->edgeflag; - out = (struct vertex_header *)( (char *)out + info->stride ); - } - } - return needpipe; -} - +#define FLAGS (pvs->flags) +#define TAG(x) x##_generic +#include "draw_cliptest_tmp.h" -/* If bypass_clipping is set, skip cliptest and rhw divide. - */ -static boolean post_vs_viewport( struct pt_post_vs *pvs, - struct draw_vertex_info *info ) -{ - struct vertex_header *out = info->verts; - const float *scale = pvs->draw->viewport.scale; - const float *trans = pvs->draw->viewport.translate; - const unsigned pos = draw_current_shader_position_output(pvs->draw); - unsigned j; - - if (0) debug_printf("%s\n", __FUNCTION__); - for (j = 0; j < info->count; j++) { - float *position = out->data[pos]; - - initialize_vertex_header(out); - /* Viewport mapping only, no cliptest/rhw divide - */ - position[0] = position[0] * scale[0] + trans[0]; - position[1] = position[1] * scale[1] + trans[1]; - position[2] = position[2] * scale[2] + trans[2]; - - out = (struct vertex_header *)((char *)out + info->stride); - } - - return FALSE; -} - - -/* If bypass_clipping is set and we have an identity viewport, nothing - * to do. - */ -static boolean post_vs_none( struct pt_post_vs *pvs, - struct draw_vertex_info *info ) -{ - struct vertex_header *out = info->verts; - unsigned j; - - if (0) debug_printf("%s\n", __FUNCTION__); - /* just initialize the vertex_id in all headers */ - for (j = 0; j < info->count; j++) { - initialize_vertex_header(out); - - out = (struct vertex_header *)((char *)out + info->stride); - } - return FALSE; -} - boolean draw_pt_post_vs_run( struct pt_post_vs *pvs, struct draw_vertex_info *info ) { @@ -244,31 +117,72 @@ boolean draw_pt_post_vs_run( struct pt_post_vs *pvs, void draw_pt_post_vs_prepare( struct pt_post_vs *pvs, - boolean bypass_clipping, + boolean clip_xy, + boolean clip_z, + boolean clip_user, boolean bypass_viewport, boolean opengl, boolean need_edgeflags ) { - if (!need_edgeflags) { - if (bypass_clipping) { - if (bypass_viewport) - pvs->run = post_vs_none; - else - pvs->run = post_vs_viewport; - } - else { - /* if (opengl) */ - pvs->run = post_vs_cliptest_viewport_gl; - } + pvs->flags = 0; + + if (clip_xy) + pvs->flags |= DO_CLIP_XY; + + if (clip_z && opengl) { + pvs->flags |= DO_CLIP_FULL_Z; + ASSIGN_4V( pvs->draw->plane[4], 0, 0, 1, 1 ); + } + + if (clip_z && !opengl) { + pvs->flags |= DO_CLIP_HALF_Z; + ASSIGN_4V( pvs->draw->plane[4], 0, 0, 1, 0 ); } - else { - /* If we need to copy edgeflags to the vertex header, it should - * mean we're running the primitive pipeline. Hence the bypass - * flags should be false. - */ - assert(!bypass_clipping); - assert(!bypass_viewport); - pvs->run = post_vs_cliptest_viewport_gl_edgeflag; + + if (clip_user) + pvs->flags |= DO_CLIP_USER; + + if (!bypass_viewport) + pvs->flags |= DO_VIEWPORT; + + if (need_edgeflags) + pvs->flags |= DO_EDGEFLAG; + + /* Now select the relevant function: + */ + switch (pvs->flags) { + case 0: + pvs->run = do_cliptest_none; + break; + + case DO_CLIP_XY | DO_CLIP_FULL_Z | DO_VIEWPORT: + pvs->run = do_cliptest_xy_fullz_viewport; + break; + + case DO_CLIP_XY | DO_CLIP_HALF_Z | DO_VIEWPORT: + pvs->run = do_cliptest_xy_halfz_viewport; + break; + + case DO_CLIP_FULL_Z | DO_VIEWPORT: + pvs->run = do_cliptest_fullz_viewport; + break; + + case DO_CLIP_HALF_Z | DO_VIEWPORT: + pvs->run = do_cliptest_halfz_viewport; + break; + + case DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | DO_VIEWPORT: + pvs->run = do_cliptest_xy_fullz_user_viewport; + break; + + case (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | + DO_VIEWPORT | DO_EDGEFLAG): + pvs->run = do_cliptest_xy_fullz_user_viewport_edgeflag; + break; + + default: + pvs->run = do_cliptest_generic; + break; } } diff --git a/src/gallium/auxiliary/draw/draw_pt_so_emit.c b/src/gallium/auxiliary/draw/draw_pt_so_emit.c index f7f4f24d35..c86bdd99a3 100644 --- a/src/gallium/auxiliary/draw/draw_pt_so_emit.c +++ b/src/gallium/auxiliary/draw/draw_pt_so_emit.c @@ -225,7 +225,7 @@ static void so_tri(struct pt_so_emit *so, int i0, int i1, int i2) #define FUNC so_run_elts #define LOCAL_VARS const ushort *elts = input_prims->elts; -#define GET_ELT(idx) (elts[start + (idx)] & ~DRAW_PIPE_FLAG_MASK) +#define GET_ELT(idx) (elts[start + (idx)]) #include "draw_so_emit_tmp.h" diff --git a/src/gallium/auxiliary/draw/draw_pt_util.c b/src/gallium/auxiliary/draw/draw_pt_util.c index 182a597cca..513bbbed21 100644 --- a/src/gallium/auxiliary/draw/draw_pt_util.c +++ b/src/gallium/auxiliary/draw/draw_pt_util.c @@ -92,3 +92,10 @@ void draw_pt_split_prim(unsigned prim, unsigned *first, unsigned *incr) break; } } + +unsigned draw_pt_trim_count(unsigned count, unsigned first, unsigned incr) +{ + if (count < first) + return 0; + return count - (count - first) % incr; +} diff --git a/src/gallium/auxiliary/draw/draw_pt_varray.c b/src/gallium/auxiliary/draw/draw_pt_varray.c deleted file mode 100644 index cd7bb7bf25..0000000000 --- a/src/gallium/auxiliary/draw/draw_pt_varray.c +++ /dev/null @@ -1,200 +0,0 @@ -/************************************************************************** - * - * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include "util/u_math.h" -#include "util/u_memory.h" - -#include "draw/draw_context.h" -#include "draw/draw_private.h" -#include "draw/draw_pt.h" - -#define FETCH_MAX 256 -#define DRAW_MAX (FETCH_MAX+8) - -struct varray_frontend { - struct draw_pt_front_end base; - struct draw_context *draw; - - ushort draw_elts[DRAW_MAX]; - unsigned fetch_elts[FETCH_MAX]; - - unsigned driver_fetch_max; - unsigned fetch_max; - - struct draw_pt_middle_end *middle; - - unsigned input_prim; - unsigned output_prim; -}; - - -static void varray_flush_linear(struct varray_frontend *varray, - unsigned start, unsigned count) -{ - if (count) { - assert(varray->middle->run_linear); - varray->middle->run_linear(varray->middle, start, count); - } -} - -static void varray_line_loop_segment(struct varray_frontend *varray, - unsigned start, - unsigned segment_start, - unsigned segment_count, - boolean end ) -{ - assert(segment_count < varray->fetch_max); - if (segment_count >= 1) { - unsigned nr = 0, i; - - for (i = 0; i < segment_count; i++) - varray->fetch_elts[nr++] = start + segment_start + i; - - if (end) - varray->fetch_elts[nr++] = start; - - assert(nr <= FETCH_MAX); - - varray->middle->run(varray->middle, - varray->fetch_elts, - nr, - varray->draw_elts, /* ie. linear */ - nr); - } -} - - - -static void varray_fan_segment(struct varray_frontend *varray, - unsigned start, - unsigned segment_start, - unsigned segment_count ) -{ - assert(segment_count < varray->fetch_max); - if (segment_count >= 2) { - unsigned nr = 0, i; - - if (segment_start != 0) - varray->fetch_elts[nr++] = start; - - for (i = 0 ; i < segment_count; i++) - varray->fetch_elts[nr++] = start + segment_start + i; - - assert(nr <= FETCH_MAX); - - varray->middle->run(varray->middle, - varray->fetch_elts, - nr, - varray->draw_elts, /* ie. linear */ - nr); - } -} - - - - -#define FUNC varray_run -#include "draw_pt_varray_tmp_linear.h" - -static unsigned decompose_prim[PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY + 1] = { - PIPE_PRIM_POINTS, - PIPE_PRIM_LINES, - PIPE_PRIM_LINE_STRIP, /* decomposed LINELOOP */ - PIPE_PRIM_LINE_STRIP, - PIPE_PRIM_TRIANGLES, - PIPE_PRIM_TRIANGLE_STRIP, - PIPE_PRIM_TRIANGLE_FAN, - PIPE_PRIM_QUADS, - PIPE_PRIM_QUAD_STRIP, - PIPE_PRIM_POLYGON, - PIPE_PRIM_LINES_ADJACENCY, - PIPE_PRIM_LINE_STRIP_ADJACENCY, - PIPE_PRIM_TRIANGLES_ADJACENCY, - PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY -}; - - - -static void varray_prepare(struct draw_pt_front_end *frontend, - unsigned in_prim, - struct draw_pt_middle_end *middle, - unsigned opt) -{ - struct varray_frontend *varray = (struct varray_frontend *)frontend; - - varray->base.run = varray_run; - - varray->input_prim = in_prim; - assert(in_prim < Elements(decompose_prim)); - varray->output_prim = decompose_prim[in_prim]; - - varray->middle = middle; - middle->prepare(middle, - varray->output_prim, - opt, &varray->driver_fetch_max ); - - /* check that the max is even */ - assert((varray->driver_fetch_max & 1) == 0); - - varray->fetch_max = MIN2(FETCH_MAX, varray->driver_fetch_max); -} - - - - -static void varray_finish(struct draw_pt_front_end *frontend) -{ - struct varray_frontend *varray = (struct varray_frontend *)frontend; - varray->middle->finish(varray->middle); - varray->middle = NULL; -} - -static void varray_destroy(struct draw_pt_front_end *frontend) -{ - FREE(frontend); -} - - -struct draw_pt_front_end *draw_pt_varray(struct draw_context *draw) -{ - ushort i; - struct varray_frontend *varray = CALLOC_STRUCT(varray_frontend); - if (varray == NULL) - return NULL; - - varray->base.prepare = varray_prepare; - varray->base.run = NULL; - varray->base.finish = varray_finish; - varray->base.destroy = varray_destroy; - varray->draw = draw; - - for (i = 0; i < DRAW_MAX; i++) { - varray->draw_elts[i] = i; - } - - return &varray->base; -} diff --git a/src/gallium/auxiliary/draw/draw_pt_varray_tmp.h b/src/gallium/auxiliary/draw/draw_pt_varray_tmp.h deleted file mode 100644 index 7c722457c3..0000000000 --- a/src/gallium/auxiliary/draw/draw_pt_varray_tmp.h +++ /dev/null @@ -1,238 +0,0 @@ - -static void FUNC(struct draw_pt_front_end *frontend, - pt_elt_func get_elt, - const void *elts, - unsigned count) -{ - struct varray_frontend *varray = (struct varray_frontend *)frontend; - struct draw_context *draw = varray->draw; - unsigned start = (unsigned)elts; - - boolean flatfirst = (draw->rasterizer->flatshade && - draw->rasterizer->flatshade_first); - unsigned i, j; - ushort flags; - unsigned first, incr; - - varray->fetch_start = start; - - draw_pt_split_prim(varray->input_prim, &first, &incr); - -#if 0 - debug_printf("%s (%d) %d/%d\n", __FUNCTION__, - varray->input_prim, - start, count); -#endif - - switch (varray->input_prim) { - case PIPE_PRIM_POINTS: - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i < end; i++) { - POINT(varray, i + 0); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - } - break; - - case PIPE_PRIM_LINES: - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i+1 < end; i += 2) { - LINE(varray, DRAW_PIPE_RESET_STIPPLE, - i + 0, i + 1); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - } - break; - - case PIPE_PRIM_LINE_LOOP: - if (count >= 2) { - flags = DRAW_PIPE_RESET_STIPPLE; - - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 1; i < end; i++, flags = 0) { - LINE(varray, flags, i - 1, i); - } - LINE(varray, flags, i - 1, 0); - i = end; - fetch_init(varray, end); - varray_flush(varray); - } - } - break; - - case PIPE_PRIM_LINE_STRIP: - flags = DRAW_PIPE_RESET_STIPPLE; - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 1; i < end; i++, flags = 0) { - LINE(varray, flags, i - 1, i); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - } - break; - - case PIPE_PRIM_TRIANGLES: - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i+2 < end; i += 3) { - TRIANGLE(varray, DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL, - i + 0, i + 1, i + 2); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - } - break; - - case PIPE_PRIM_TRIANGLE_STRIP: - if (flatfirst) { - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i+2 < end; i++) { - TRIANGLE(varray, DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL, - i + 0, i + 1 + (i&1), i + 2 - (i&1)); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - if (j + first + i <= count) { - varray->fetch_start -= 2; - i -= 2; - } - } - } - else { - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i + 2 < end; i++) { - TRIANGLE(varray, DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL, - i + 0 + (i&1), i + 1 - (i&1), i + 2); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - if (j + first + i <= count) { - varray->fetch_start -= 2; - i -= 2; - } - } - } - break; - - case PIPE_PRIM_TRIANGLE_FAN: - if (count >= 3) { - if (flatfirst) { - flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL; - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i+2 < end; i++) { - TRIANGLE(varray, flags, i + 1, i + 2, 0); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - } - } - else { - flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL; - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i+2 < end; i++) { - TRIANGLE(varray, flags, 0, i + 1, i + 2); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - } - } - } - break; - - case PIPE_PRIM_QUADS: - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i+3 < end; i += 4) { - QUAD(varray, i + 0, i + 1, i + 2, i + 3); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - } - break; - - case PIPE_PRIM_QUAD_STRIP: - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i+3 < end; i += 2) { - QUAD(varray, i + 2, i + 0, i + 1, i + 3); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - if (j + first + i <= count) { - varray->fetch_start -= 2; - i -= 2; - } - } - break; - - case PIPE_PRIM_POLYGON: - { - /* These bitflags look a little odd because we submit the - * vertices as (1,2,0) to satisfy flatshade requirements. - */ - const ushort edge_first = DRAW_PIPE_EDGE_FLAG_2; - const ushort edge_middle = DRAW_PIPE_EDGE_FLAG_0; - const ushort edge_last = DRAW_PIPE_EDGE_FLAG_1; - - flags = DRAW_PIPE_RESET_STIPPLE | edge_first | edge_middle; - for (j = 0; j + first <= count; j += i) { - unsigned end = MIN2(FETCH_MAX, count - j); - end -= (end % incr); - for (i = 0; i+2 < end; i++, flags = edge_middle) { - - if (i + 3 == count) - flags |= edge_last; - - TRIANGLE(varray, flags, i + 1, i + 2, 0); - } - i = end; - fetch_init(varray, end); - varray_flush(varray); - } - } - break; - - default: - assert(0); - break; - } - - varray_flush(varray); -} - -#undef TRIANGLE -#undef QUAD -#undef POINT -#undef LINE -#undef FUNC diff --git a/src/gallium/auxiliary/draw/draw_pt_varray_tmp_linear.h b/src/gallium/auxiliary/draw/draw_pt_varray_tmp_linear.h deleted file mode 100644 index 55e43b2a71..0000000000 --- a/src/gallium/auxiliary/draw/draw_pt_varray_tmp_linear.h +++ /dev/null @@ -1,103 +0,0 @@ -static unsigned trim( unsigned count, unsigned first, unsigned incr ) -{ - /* - * count either has been trimmed in draw_pt_arrays or is set to - * (driver)_fetch_max which is hopefully always larger than first. - */ - assert(count >= first); - return count - (count - first) % incr; -} - -static void FUNC(struct draw_pt_front_end *frontend, - pt_elt_func get_elt, - const void *elts, - int elt_bias, - unsigned count) -{ - struct varray_frontend *varray = (struct varray_frontend *)frontend; - unsigned start = (unsigned) ((char *) elts - (char *) NULL); - - unsigned j; - unsigned first, incr; - - assert(elt_bias == 0); - - draw_pt_split_prim(varray->input_prim, &first, &incr); - - /* Sanitize primitive length: - */ - count = trim(count, first, incr); - if (count < first) - return; - -#if 0 - debug_printf("%s (%d) %d/%d\n", __FUNCTION__, - varray->input_prim, - start, count); -#endif - - switch (varray->input_prim) { - case PIPE_PRIM_POINTS: - case PIPE_PRIM_LINES: - case PIPE_PRIM_TRIANGLES: - case PIPE_PRIM_LINE_STRIP: - case PIPE_PRIM_TRIANGLE_STRIP: - case PIPE_PRIM_QUADS: - case PIPE_PRIM_QUAD_STRIP: - case PIPE_PRIM_LINES_ADJACENCY: - case PIPE_PRIM_LINE_STRIP_ADJACENCY: - case PIPE_PRIM_TRIANGLES_ADJACENCY: - case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: - for (j = 0; j < count;) { - unsigned remaining = count - j; - unsigned nr = trim( MIN2(varray->driver_fetch_max, remaining), first, incr ); - varray_flush_linear(varray, start + j, nr); - j += nr; - if (nr != remaining) - j -= (first - incr); - } - break; - - case PIPE_PRIM_LINE_LOOP: - /* Always have to decompose as we've stated that this will be - * emitted as a line-strip. - */ - for (j = 0; j < count;) { - unsigned remaining = count - j; - unsigned nr = trim( MIN2(varray->fetch_max-1, remaining), first, incr ); - varray_line_loop_segment(varray, start, j, nr, nr == remaining); - j += nr; - if (nr != remaining) - j -= (first - incr); - } - break; - - - case PIPE_PRIM_POLYGON: - case PIPE_PRIM_TRIANGLE_FAN: - if (count < varray->driver_fetch_max) { - varray_flush_linear(varray, start, count); - } - else { - for ( j = 0; j < count;) { - unsigned remaining = count - j; - unsigned nr = trim( MIN2(varray->fetch_max-1, remaining), first, incr ); - varray_fan_segment(varray, start, j, nr); - j += nr; - if (nr != remaining) - j -= (first - incr); - } - } - break; - - default: - assert(0); - break; - } -} - -#undef TRIANGLE -#undef QUAD -#undef POINT -#undef LINE -#undef FUNC diff --git a/src/gallium/auxiliary/draw/draw_pt_vcache.c b/src/gallium/auxiliary/draw/draw_pt_vcache.c deleted file mode 100644 index a848b54f7d..0000000000 --- a/src/gallium/auxiliary/draw/draw_pt_vcache.c +++ /dev/null @@ -1,610 +0,0 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - - /* - * Authors: - * Keith Whitwell <keith@tungstengraphics.com> - */ - -#include "util/u_memory.h" -#include "util/u_prim.h" -#include "draw/draw_context.h" -#include "draw/draw_private.h" -#include "draw/draw_pt.h" - - -#define CACHE_MAX 256 -#define FETCH_MAX 256 -#define DRAW_MAX (16*1024) - - -struct vcache_frontend { - struct draw_pt_front_end base; - struct draw_context *draw; - - unsigned in[CACHE_MAX]; - ushort out[CACHE_MAX]; - - ushort draw_elts[DRAW_MAX]; - unsigned fetch_elts[FETCH_MAX]; - - unsigned draw_count; - unsigned fetch_count; - unsigned fetch_max; - - struct draw_pt_middle_end *middle; - - unsigned input_prim; - unsigned output_prim; - - unsigned middle_prim; - unsigned opt; -}; - - -static INLINE void -vcache_flush( struct vcache_frontend *vcache ) -{ - if (vcache->middle_prim != vcache->output_prim) { - vcache->middle_prim = vcache->output_prim; - vcache->middle->prepare( vcache->middle, - vcache->middle_prim, - vcache->opt, - &vcache->fetch_max ); - } - - if (vcache->draw_count) { - vcache->middle->run( vcache->middle, - vcache->fetch_elts, - vcache->fetch_count, - vcache->draw_elts, - vcache->draw_count ); - } - - memset(vcache->in, ~0, sizeof(vcache->in)); - vcache->fetch_count = 0; - vcache->draw_count = 0; -} - - -static INLINE void -vcache_check_flush( struct vcache_frontend *vcache ) -{ - if (vcache->draw_count + 6 >= DRAW_MAX || - vcache->fetch_count + 6 >= FETCH_MAX) { - vcache_flush( vcache ); - } -} - - -static INLINE void -vcache_elt( struct vcache_frontend *vcache, - unsigned felt, - ushort flags ) -{ - unsigned idx = felt % CACHE_MAX; - - if (vcache->in[idx] != felt) { - assert(vcache->fetch_count < FETCH_MAX); - - vcache->in[idx] = felt; - vcache->out[idx] = (ushort)vcache->fetch_count; - vcache->fetch_elts[vcache->fetch_count++] = felt; - } - - vcache->draw_elts[vcache->draw_count++] = vcache->out[idx] | flags; -} - - - -static INLINE void -vcache_triangle( struct vcache_frontend *vcache, - unsigned i0, - unsigned i1, - unsigned i2 ) -{ - vcache_elt(vcache, i0, 0); - vcache_elt(vcache, i1, 0); - vcache_elt(vcache, i2, 0); - vcache_check_flush(vcache); -} - - -static INLINE void -vcache_triangle_flags( struct vcache_frontend *vcache, - ushort flags, - unsigned i0, - unsigned i1, - unsigned i2 ) -{ - vcache_elt(vcache, i0, flags); - vcache_elt(vcache, i1, 0); - vcache_elt(vcache, i2, 0); - vcache_check_flush(vcache); -} - - -static INLINE void -vcache_line( struct vcache_frontend *vcache, - unsigned i0, - unsigned i1 ) -{ - vcache_elt(vcache, i0, 0); - vcache_elt(vcache, i1, 0); - vcache_check_flush(vcache); -} - - -static INLINE void -vcache_line_flags( struct vcache_frontend *vcache, - ushort flags, - unsigned i0, - unsigned i1 ) -{ - vcache_elt(vcache, i0, flags); - vcache_elt(vcache, i1, 0); - vcache_check_flush(vcache); -} - - -static INLINE void -vcache_point( struct vcache_frontend *vcache, - unsigned i0 ) -{ - vcache_elt(vcache, i0, 0); - vcache_check_flush(vcache); -} - - -static INLINE void -vcache_line_adj_flags( struct vcache_frontend *vcache, - unsigned flags, - unsigned a0, unsigned i0, unsigned i1, unsigned a1 ) -{ - vcache_elt(vcache, a0, 0); - vcache_elt(vcache, i0, flags); - vcache_elt(vcache, i1, 0); - vcache_elt(vcache, a1, 0); - vcache_check_flush(vcache); -} - - -static INLINE void -vcache_line_adj( struct vcache_frontend *vcache, - unsigned a0, unsigned i0, unsigned i1, unsigned a1 ) -{ - vcache_elt(vcache, a0, 0); - vcache_elt(vcache, i0, 0); - vcache_elt(vcache, i1, 0); - vcache_elt(vcache, a1, 0); - vcache_check_flush(vcache); -} - - -static INLINE void -vcache_triangle_adj_flags( struct vcache_frontend *vcache, - unsigned flags, - unsigned i0, unsigned a0, - unsigned i1, unsigned a1, - unsigned i2, unsigned a2 ) -{ - vcache_elt(vcache, i0, flags); - vcache_elt(vcache, a0, 0); - vcache_elt(vcache, i1, 0); - vcache_elt(vcache, a1, 0); - vcache_elt(vcache, i2, 0); - vcache_elt(vcache, a2, 0); - vcache_check_flush(vcache); -} - - -static INLINE void -vcache_triangle_adj( struct vcache_frontend *vcache, - unsigned i0, unsigned a0, - unsigned i1, unsigned a1, - unsigned i2, unsigned a2 ) -{ - vcache_elt(vcache, i0, 0); - vcache_elt(vcache, a0, 0); - vcache_elt(vcache, i1, 0); - vcache_elt(vcache, a1, 0); - vcache_elt(vcache, i2, 0); - vcache_elt(vcache, a2, 0); - vcache_check_flush(vcache); -} - - -/* At least for now, we're back to using a template include file for - * this. The two paths aren't too different though - it may be - * possible to reunify them. - */ -#define TRIANGLE(flags,i0,i1,i2) vcache_triangle_flags(vcache,flags,i0,i1,i2) -#define LINE(flags,i0,i1) vcache_line_flags(vcache,flags,i0,i1) -#define POINT(i0) vcache_point(vcache,i0) -#define LINE_ADJ(flags,a0,i0,i1,a1) \ - vcache_line_adj_flags(vcache,flags,a0,i0,i1,a1) -#define TRIANGLE_ADJ(flags,i0,a0,i1,a1,i2,a2) \ - vcache_triangle_adj_flags(vcache,flags,i0,a0,i1,a1,i2,a2) -#define FUNC vcache_run_extras -#include "draw_pt_vcache_tmp.h" - -#define TRIANGLE(flags,i0,i1,i2) vcache_triangle(vcache,i0,i1,i2) -#define LINE(flags,i0,i1) vcache_line(vcache,i0,i1) -#define POINT(i0) vcache_point(vcache,i0) -#define LINE_ADJ(flags,a0,i0,i1,a1) \ - vcache_line_adj(vcache,a0,i0,i1,a1) -#define TRIANGLE_ADJ(flags,i0,a0,i1,a1,i2,a2) \ - vcache_triangle_adj(vcache,i0,a0,i1,a1,i2,a2) -#define FUNC vcache_run -#include "draw_pt_vcache_tmp.h" - -static INLINE void -rebase_uint_elts( const unsigned *src, - unsigned count, - int delta, - ushort *dest ) -{ - unsigned i; - for (i = 0; i < count; i++) - dest[i] = (ushort)(src[i] + delta); -} - - -static INLINE void -rebase_ushort_elts( const ushort *src, - unsigned count, - int delta, - ushort *dest ) -{ - unsigned i; - for (i = 0; i < count; i++) - dest[i] = (ushort)(src[i] + delta); -} - - -static INLINE void -rebase_ubyte_elts( const ubyte *src, - unsigned count, - int delta, - ushort *dest ) -{ - unsigned i; - for (i = 0; i < count; i++) - dest[i] = (ushort)(src[i] + delta); -} - - -static INLINE void -translate_uint_elts( const unsigned *src, - unsigned count, - ushort *dest ) -{ - unsigned i; - for (i = 0; i < count; i++) - dest[i] = (ushort)(src[i]); -} - - -static INLINE void -translate_ushort_elts( const ushort *src, - unsigned count, - ushort *dest ) -{ - unsigned i; - for (i = 0; i < count; i++) - dest[i] = (ushort)(src[i]); -} - - -static INLINE void -translate_ubyte_elts( const ubyte *src, - unsigned count, - ushort *dest ) -{ - unsigned i; - for (i = 0; i < count; i++) - dest[i] = (ushort)(src[i]); -} - - - - -#if 0 -static INLINE enum pipe_format -format_from_get_elt( pt_elt_func get_elt ) -{ - switch (draw->pt.user.eltSize) { - case 1: return PIPE_FORMAT_R8_UNORM; - case 2: return PIPE_FORMAT_R16_UNORM; - case 4: return PIPE_FORMAT_R32_UNORM; - default: return PIPE_FORMAT_NONE; - } -} -#endif - - -/** - * Check if any vertex attributes use instance divisors. - * Note that instance divisors complicate vertex fetching so we need - * to take the vcache path when they're in use. - */ -static boolean -any_instance_divisors(const struct draw_context *draw) -{ - uint i; - - for (i = 0; i < draw->pt.nr_vertex_elements; i++) { - uint div = draw->pt.vertex_element[i].instance_divisor; - if (div) - return TRUE; - } - return FALSE; -} - - -static INLINE void -vcache_check_run( struct draw_pt_front_end *frontend, - pt_elt_func get_elt, - const void *elts, - int elt_bias, - unsigned draw_count ) -{ - struct vcache_frontend *vcache = (struct vcache_frontend *)frontend; - struct draw_context *draw = vcache->draw; - const unsigned min_index = draw->pt.user.min_index; - const unsigned max_index = draw->pt.user.max_index; - const unsigned index_size = draw->pt.user.eltSize; - unsigned fetch_count; - const ushort *transformed_elts; - ushort *storage = NULL; - boolean ok = FALSE; - - /* debug: verify indexes are in range [min_index, max_index] */ - if (0) { - unsigned i; - for (i = 0; i < draw_count; i++) { - if (index_size == 1) { - assert( ((const ubyte *) elts)[i] >= min_index); - assert( ((const ubyte *) elts)[i] <= max_index); - } - else if (index_size == 2) { - assert( ((const ushort *) elts)[i] >= min_index); - assert( ((const ushort *) elts)[i] <= max_index); - } - else { - assert(index_size == 4); - assert( ((const uint *) elts)[i] >= min_index); - assert( ((const uint *) elts)[i] <= max_index); - } - } - } - - /* Note: max_index is frequently 0xffffffff so we have to be sure - * that any arithmetic involving max_index doesn't overflow! - */ - if (max_index >= (unsigned) DRAW_PIPE_MAX_VERTICES) - goto fail; - - if (any_instance_divisors(draw)) - goto fail; - - fetch_count = max_index + 1 - min_index; - - if (0) - debug_printf("fetch_count %d fetch_max %d draw_count %d\n", fetch_count, - vcache->fetch_max, - draw_count); - - if (elt_bias + max_index >= DRAW_PIPE_MAX_VERTICES || - fetch_count >= UNDEFINED_VERTEX_ID || - fetch_count > draw_count) { - if (0) debug_printf("fail\n"); - goto fail; - } - - if (vcache->middle_prim != vcache->input_prim) { - vcache->middle_prim = vcache->input_prim; - vcache->middle->prepare( vcache->middle, - vcache->middle_prim, - vcache->opt, - &vcache->fetch_max ); - } - - assert((elt_bias >= 0 && min_index + elt_bias >= min_index) || - (elt_bias < 0 && min_index + elt_bias < min_index)); - - if (min_index == 0 && - index_size == 2) { - transformed_elts = (const ushort *)elts; - } - else { - storage = MALLOC( draw_count * sizeof(ushort) ); - if (!storage) - goto fail; - - if (min_index == 0) { - switch(index_size) { - case 1: - translate_ubyte_elts( (const ubyte *)elts, - draw_count, - storage ); - break; - - case 2: - translate_ushort_elts( (const ushort *)elts, - draw_count, - storage ); - break; - - case 4: - translate_uint_elts( (const uint *)elts, - draw_count, - storage ); - break; - - default: - assert(0); - FREE(storage); - return; - } - } - else { - switch(index_size) { - case 1: - rebase_ubyte_elts( (const ubyte *)elts, - draw_count, - 0 - (int)min_index, - storage ); - break; - - case 2: - rebase_ushort_elts( (const ushort *)elts, - draw_count, - 0 - (int)min_index, - storage ); - break; - - case 4: - rebase_uint_elts( (const uint *)elts, - draw_count, - 0 - (int)min_index, - storage ); - break; - - default: - assert(0); - FREE(storage); - return; - } - } - transformed_elts = storage; - } - - if (fetch_count < UNDEFINED_VERTEX_ID) - ok = vcache->middle->run_linear_elts( vcache->middle, - min_index + elt_bias, /* start */ - fetch_count, - transformed_elts, - draw_count ); - - FREE(storage); - - if (ok) - return; - - debug_printf("failed to execute atomic draw elts for %d/%d, splitting up\n", - fetch_count, draw_count); - -fail: - vcache_run( frontend, get_elt, elts, elt_bias, draw_count ); -} - - - - -static void -vcache_prepare( struct draw_pt_front_end *frontend, - unsigned in_prim, - struct draw_pt_middle_end *middle, - unsigned opt ) -{ - struct vcache_frontend *vcache = (struct vcache_frontend *)frontend; - - if (opt & PT_PIPELINE) { - vcache->base.run = vcache_run_extras; - } - else { - vcache->base.run = vcache_check_run; - } - - /* VCache will always emit the reduced version of its input - * primitive, ie STRIP/FANS become TRIS, etc. - * - * This is not to be confused with what the GS might be up to, - * which is a separate issue. - */ - vcache->input_prim = in_prim; - switch (in_prim) { - case PIPE_PRIM_LINES_ADJACENCY: - case PIPE_PRIM_LINE_STRIP_ADJACENCY: - vcache->output_prim = PIPE_PRIM_LINES_ADJACENCY; - break; - case PIPE_PRIM_TRIANGLES_ADJACENCY: - case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: - vcache->output_prim = PIPE_PRIM_TRIANGLES_ADJACENCY; - break; - default: - vcache->output_prim = u_reduced_prim(in_prim); - } - - vcache->middle = middle; - vcache->opt = opt; - - /* Have to run prepare here, but try and guess a good prim for - * doing so: - */ - vcache->middle_prim = (opt & PT_PIPELINE) - ? vcache->output_prim : vcache->input_prim; - - middle->prepare( middle, - vcache->middle_prim, - opt, &vcache->fetch_max ); -} - - -static void -vcache_finish( struct draw_pt_front_end *frontend ) -{ - struct vcache_frontend *vcache = (struct vcache_frontend *)frontend; - vcache->middle->finish( vcache->middle ); - vcache->middle = NULL; -} - - -static void -vcache_destroy( struct draw_pt_front_end *frontend ) -{ - FREE(frontend); -} - - -struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw ) -{ - struct vcache_frontend *vcache = CALLOC_STRUCT( vcache_frontend ); - if (vcache == NULL) - return NULL; - - vcache->base.prepare = vcache_prepare; - vcache->base.run = NULL; - vcache->base.finish = vcache_finish; - vcache->base.destroy = vcache_destroy; - vcache->draw = draw; - - memset(vcache->in, ~0, sizeof(vcache->in)); - - return &vcache->base; -} diff --git a/src/gallium/auxiliary/draw/draw_pt_vcache_tmp.h b/src/gallium/auxiliary/draw/draw_pt_vcache_tmp.h deleted file mode 100644 index 1a3748d5f0..0000000000 --- a/src/gallium/auxiliary/draw/draw_pt_vcache_tmp.h +++ /dev/null @@ -1,19 +0,0 @@ -#define FUNC_VARS \ - struct draw_pt_front_end *frontend, \ - pt_elt_func get_elt, \ - const void *elts, \ - int elt_bias, \ - unsigned count - -#define LOCAL_VARS \ - struct vcache_frontend *vcache = (struct vcache_frontend *) frontend; \ - struct draw_context *draw = vcache->draw; \ - const unsigned prim = vcache->input_prim; \ - const boolean last_vertex_last = !(draw->rasterizer->flatshade && \ - draw->rasterizer->flatshade_first); - -#define GET_ELT(idx) (get_elt(elts, idx) + elt_bias) - -#define FUNC_EXIT do { vcache_flush(vcache); } while (0) - -#include "draw_decompose_tmp.h" diff --git a/src/gallium/auxiliary/draw/draw_pt_vsplit.c b/src/gallium/auxiliary/draw/draw_pt_vsplit.c new file mode 100644 index 0000000000..a687525309 --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_pt_vsplit.c @@ -0,0 +1,208 @@ +/* + * Mesa 3-D graphics library + * Version: 7.9 + * + * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (C) 2010 LunarG Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "util/u_math.h" +#include "util/u_memory.h" + +#include "draw/draw_context.h" +#include "draw/draw_private.h" +#include "draw/draw_pt.h" + +#define SEGMENT_SIZE 1024 +#define MAP_SIZE 256 + +struct vsplit_frontend { + struct draw_pt_front_end base; + struct draw_context *draw; + + unsigned prim; + + struct draw_pt_middle_end *middle; + + unsigned max_vertices; + ushort segment_size; + + /* buffers for splitting */ + unsigned fetch_elts[SEGMENT_SIZE]; + ushort draw_elts[SEGMENT_SIZE]; + ushort identity_draw_elts[SEGMENT_SIZE]; + + struct { + /* map a fetch element to a draw element */ + unsigned fetches[MAP_SIZE]; + ushort draws[MAP_SIZE]; + boolean has_max_fetch; + + ushort num_fetch_elts; + ushort num_draw_elts; + } cache; +}; + + +static void +vsplit_clear_cache(struct vsplit_frontend *vsplit) +{ + memset(vsplit->cache.fetches, 0xff, sizeof(vsplit->cache.fetches)); + vsplit->cache.has_max_fetch = FALSE; + vsplit->cache.num_fetch_elts = 0; + vsplit->cache.num_draw_elts = 0; +} + +static void +vsplit_flush_cache(struct vsplit_frontend *vsplit, unsigned flags) +{ + vsplit->middle->run(vsplit->middle, + vsplit->fetch_elts, vsplit->cache.num_fetch_elts, + vsplit->draw_elts, vsplit->cache.num_draw_elts, flags); +} + +/** + * Add a fetch element and add it to the draw elements. + */ +static INLINE void +vsplit_add_cache(struct vsplit_frontend *vsplit, unsigned fetch) +{ + unsigned hash = fetch % MAP_SIZE; + + if (vsplit->cache.fetches[hash] != fetch) { + /* update cache */ + vsplit->cache.fetches[hash] = fetch; + vsplit->cache.draws[hash] = vsplit->cache.num_fetch_elts; + + /* add fetch */ + assert(vsplit->cache.num_fetch_elts < vsplit->segment_size); + vsplit->fetch_elts[vsplit->cache.num_fetch_elts++] = fetch; + } + + vsplit->draw_elts[vsplit->cache.num_draw_elts++] = vsplit->cache.draws[hash]; +} + + +/** + * Add a fetch element and add it to the draw elements. The fetch element is + * in full range (uint). + */ +static INLINE void +vsplit_add_cache_uint(struct vsplit_frontend *vsplit, unsigned fetch) +{ + /* special care for 0xffffffff */ + if (fetch == 0xffffffff && !vsplit->cache.has_max_fetch) { + unsigned hash = fetch % MAP_SIZE; + vsplit->cache.fetches[hash] = fetch - 1; /* force update */ + vsplit->cache.has_max_fetch = TRUE; + } + + vsplit_add_cache(vsplit, fetch); +} + + +#define FUNC vsplit_run_linear +#include "draw_pt_vsplit_tmp.h" + +#define FUNC vsplit_run_ubyte +#define ELT_TYPE ubyte +#define ADD_CACHE(vsplit, fetch) vsplit_add_cache(vsplit, fetch) +#include "draw_pt_vsplit_tmp.h" + +#define FUNC vsplit_run_ushort +#define ELT_TYPE ushort +#define ADD_CACHE(vsplit, fetch) vsplit_add_cache(vsplit, fetch) +#include "draw_pt_vsplit_tmp.h" + +#define FUNC vsplit_run_uint +#define ELT_TYPE uint +#define ADD_CACHE(vsplit, fetch) vsplit_add_cache_uint(vsplit, fetch) +#include "draw_pt_vsplit_tmp.h" + + +static void vsplit_prepare(struct draw_pt_front_end *frontend, + unsigned in_prim, + struct draw_pt_middle_end *middle, + unsigned opt) +{ + struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend; + + switch (vsplit->draw->pt.user.eltSize) { + case 0: + vsplit->base.run = vsplit_run_linear; + break; + case 1: + vsplit->base.run = vsplit_run_ubyte; + break; + case 2: + vsplit->base.run = vsplit_run_ushort; + break; + case 4: + vsplit->base.run = vsplit_run_uint; + break; + default: + assert(0); + break; + } + + /* split only */ + vsplit->prim = in_prim; + + vsplit->middle = middle; + middle->prepare(middle, vsplit->prim, opt, &vsplit->max_vertices); + + vsplit->segment_size = MIN2(SEGMENT_SIZE, vsplit->max_vertices); +} + + +static void vsplit_finish(struct draw_pt_front_end *frontend) +{ + struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend; + vsplit->middle->finish(vsplit->middle); + vsplit->middle = NULL; +} + + +static void vsplit_destroy(struct draw_pt_front_end *frontend) +{ + FREE(frontend); +} + + +struct draw_pt_front_end *draw_pt_vsplit(struct draw_context *draw) +{ + struct vsplit_frontend *vsplit = CALLOC_STRUCT(vsplit_frontend); + ushort i; + + if (!vsplit) + return NULL; + + vsplit->base.prepare = vsplit_prepare; + vsplit->base.run = NULL; + vsplit->base.finish = vsplit_finish; + vsplit->base.destroy = vsplit_destroy; + vsplit->draw = draw; + + for (i = 0; i < SEGMENT_SIZE; i++) + vsplit->identity_draw_elts[i] = i; + + return &vsplit->base; +} diff --git a/src/gallium/auxiliary/draw/draw_pt_vsplit_tmp.h b/src/gallium/auxiliary/draw/draw_pt_vsplit_tmp.h new file mode 100644 index 0000000000..3f66f962e1 --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_pt_vsplit_tmp.h @@ -0,0 +1,309 @@ +/* + * Mesa 3-D graphics library + * Version: 7.9 + * + * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (C) 2010 LunarG Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#define CONCAT2(name, elt_type) name ## elt_type +#define CONCAT(name, elt_type) CONCAT2(name, elt_type) + +#ifdef ELT_TYPE + +/** + * Fetch all elements in [min_index, max_index] with bias, and use the + * (rebased) index buffer as the draw elements. + */ +static boolean +CONCAT(vsplit_primitive_, ELT_TYPE)(struct vsplit_frontend *vsplit, + unsigned istart, unsigned icount) +{ + struct draw_context *draw = vsplit->draw; + const ELT_TYPE *ib = (const ELT_TYPE *) + ((const char *) draw->pt.user.elts + draw->pt.index_buffer.offset); + const unsigned min_index = draw->pt.user.min_index; + const unsigned max_index = draw->pt.user.max_index; + const int elt_bias = draw->pt.user.eltBias; + unsigned fetch_start, fetch_count; + const ushort *draw_elts = NULL; + unsigned i; + + /* use the ib directly */ + if (min_index == 0 && sizeof(ib[0]) == sizeof(draw_elts[0])) { + if (icount > vsplit->max_vertices) + return FALSE; + + for (i = 0; i < icount; i++) { + ELT_TYPE idx = ib[istart + i]; + assert(idx >= min_index && idx <= max_index); + } + draw_elts = (const ushort *) ib; + } + else { + /* have to go through vsplit->draw_elts */ + if (icount > vsplit->segment_size) + return FALSE; + } + + /* this is faster only when we fetch less elements than the normal path */ + if (max_index - min_index > icount - 1) + return FALSE; + + if (elt_bias < 0 && min_index < -elt_bias) + return FALSE; + + /* why this check? */ + for (i = 0; i < draw->pt.nr_vertex_elements; i++) { + if (draw->pt.vertex_element[i].instance_divisor) + return FALSE; + } + + fetch_start = min_index + elt_bias; + fetch_count = max_index - min_index + 1; + + if (!draw_elts) { + if (min_index == 0) { + for (i = 0; i < icount; i++) { + ELT_TYPE idx = ib[istart + i]; + + assert(idx >= min_index && idx <= max_index); + vsplit->draw_elts[i] = (ushort) idx; + } + } + else { + for (i = 0; i < icount; i++) { + ELT_TYPE idx = ib[istart + i]; + + assert(idx >= min_index && idx <= max_index); + vsplit->draw_elts[i] = (ushort) (idx - min_index); + } + } + + draw_elts = vsplit->draw_elts; + } + + return vsplit->middle->run_linear_elts(vsplit->middle, + fetch_start, fetch_count, + draw_elts, icount, 0x0); +} + +/** + * Use the cache to prepare the fetch and draw elements, and flush. + * + * When spoken is TRUE, ispoken replaces istart; When close is TRUE, iclose is + * appended. + */ +static INLINE void +CONCAT(vsplit_segment_cache_, ELT_TYPE)(struct vsplit_frontend *vsplit, + unsigned flags, + unsigned istart, unsigned icount, + boolean spoken, unsigned ispoken, + boolean close, unsigned iclose) +{ + struct draw_context *draw = vsplit->draw; + const ELT_TYPE *ib = (const ELT_TYPE *) + ((const char *) draw->pt.user.elts + draw->pt.index_buffer.offset); + const int ibias = draw->pt.user.eltBias; + unsigned i; + + assert(icount + !!close <= vsplit->segment_size); + + vsplit_clear_cache(vsplit); + + spoken = !!spoken; + if (ibias == 0) { + if (spoken) + ADD_CACHE(vsplit, ib[ispoken]); + + for (i = spoken; i < icount; i++) + ADD_CACHE(vsplit, ib[istart + i]); + + if (close) + ADD_CACHE(vsplit, ib[iclose]); + } + else if (ibias > 0) { + if (spoken) + ADD_CACHE(vsplit, (uint) ib[ispoken] + ibias); + + for (i = spoken; i < icount; i++) + ADD_CACHE(vsplit, (uint) ib[istart + i] + ibias); + + if (close) + ADD_CACHE(vsplit, (uint) ib[iclose] + ibias); + } + else { + if (spoken) { + if (ib[ispoken] < -ibias) + return; + ADD_CACHE(vsplit, ib[ispoken] + ibias); + } + + for (i = spoken; i < icount; i++) { + if (ib[istart + i] < -ibias) + return; + ADD_CACHE(vsplit, ib[istart + i] + ibias); + } + + if (close) { + if (ib[iclose] < -ibias) + return; + ADD_CACHE(vsplit, ib[iclose] + ibias); + } + } + + vsplit_flush_cache(vsplit, flags); +} + +static void +CONCAT(vsplit_segment_simple_, ELT_TYPE)(struct vsplit_frontend *vsplit, + unsigned flags, + unsigned istart, + unsigned icount) +{ + CONCAT(vsplit_segment_cache_, ELT_TYPE)(vsplit, + flags, istart, icount, FALSE, 0, FALSE, 0); +} + +static void +CONCAT(vsplit_segment_loop_, ELT_TYPE)(struct vsplit_frontend *vsplit, + unsigned flags, + unsigned istart, + unsigned icount, + unsigned i0) +{ + const boolean close_loop = ((flags) == DRAW_SPLIT_BEFORE); + + CONCAT(vsplit_segment_cache_, ELT_TYPE)(vsplit, + flags, istart, icount, FALSE, 0, close_loop, i0); +} + +static void +CONCAT(vsplit_segment_fan_, ELT_TYPE)(struct vsplit_frontend *vsplit, + unsigned flags, + unsigned istart, + unsigned icount, + unsigned i0) +{ + const boolean use_spoken = (((flags) & DRAW_SPLIT_BEFORE) != 0); + + CONCAT(vsplit_segment_cache_, ELT_TYPE)(vsplit, + flags, istart, icount, use_spoken, i0, FALSE, 0); +} + +#define LOCAL_VARS \ + struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend; \ + const unsigned prim = vsplit->prim; \ + const unsigned max_count_simple = vsplit->segment_size; \ + const unsigned max_count_loop = vsplit->segment_size - 1; \ + const unsigned max_count_fan = vsplit->segment_size; + +#define PRIMITIVE(istart, icount) \ + CONCAT(vsplit_primitive_, ELT_TYPE)(vsplit, istart, icount) + +#else /* ELT_TYPE */ + +static void +vsplit_segment_simple_linear(struct vsplit_frontend *vsplit, unsigned flags, + unsigned istart, unsigned icount) +{ + assert(icount <= vsplit->max_vertices); + vsplit->middle->run_linear(vsplit->middle, istart, icount, flags); +} + +static void +vsplit_segment_loop_linear(struct vsplit_frontend *vsplit, unsigned flags, + unsigned istart, unsigned icount, unsigned i0) +{ + boolean close_loop = (flags == DRAW_SPLIT_BEFORE); + unsigned nr; + + assert(icount + !!close_loop <= vsplit->segment_size); + + if (close_loop) { + for (nr = 0; nr < icount; nr++) + vsplit->fetch_elts[nr] = istart + nr; + vsplit->fetch_elts[nr++] = i0; + + vsplit->middle->run(vsplit->middle, vsplit->fetch_elts, nr, + vsplit->identity_draw_elts, nr, flags); + } + else { + vsplit->middle->run_linear(vsplit->middle, istart, icount, flags); + } +} + +static void +vsplit_segment_fan_linear(struct vsplit_frontend *vsplit, unsigned flags, + unsigned istart, unsigned icount, unsigned i0) +{ + boolean use_spoken = ((flags & DRAW_SPLIT_BEFORE) != 0); + unsigned nr = 0, i; + + assert(icount + !!use_spoken <= vsplit->segment_size); + + if (use_spoken) { + vsplit->fetch_elts[nr++] = i0; + for (i = 1 ; i < icount; i++) + vsplit->fetch_elts[nr++] = istart + i; + + vsplit->middle->run(vsplit->middle, vsplit->fetch_elts, nr, + vsplit->identity_draw_elts, nr, flags); + } + else { + vsplit->middle->run_linear(vsplit->middle, istart, icount, flags); + } +} + +#define LOCAL_VARS \ + struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend; \ + const unsigned prim = vsplit->prim; \ + const unsigned max_count_simple = vsplit->max_vertices; \ + const unsigned max_count_loop = vsplit->segment_size - 1; \ + const unsigned max_count_fan = vsplit->segment_size; + +#define PRIMITIVE(istart, icount) FALSE + +#define ELT_TYPE linear + +#endif /* ELT_TYPE */ + +#define FUNC_VARS \ + struct draw_pt_front_end *frontend, \ + unsigned start, \ + unsigned count + +#define SEGMENT_SIMPLE(flags, istart, icount) \ + CONCAT(vsplit_segment_simple_, ELT_TYPE)(vsplit, flags, istart, icount) + +#define SEGMENT_LOOP(flags, istart, icount, i0) \ + CONCAT(vsplit_segment_loop_, ELT_TYPE)(vsplit, flags, istart, icount, i0) + +#define SEGMENT_FAN(flags, istart, icount, i0) \ + CONCAT(vsplit_segment_fan_, ELT_TYPE)(vsplit, flags, istart, icount, i0) + +#include "draw_split_tmp.h" + +#undef CONCAT2 +#undef CONCAT + +#undef ELT_TYPE +#undef ADD_CACHE diff --git a/src/gallium/auxiliary/draw/draw_so_emit_tmp.h b/src/gallium/auxiliary/draw/draw_so_emit_tmp.h index 6d8937a0b4..7fafde9d5e 100644 --- a/src/gallium/auxiliary/draw/draw_so_emit_tmp.h +++ b/src/gallium/auxiliary/draw/draw_so_emit_tmp.h @@ -7,11 +7,9 @@ #define FUNC_ENTER \ /* declare more local vars */ \ - struct draw_context *draw = so->draw; \ const unsigned prim = input_prims->prim; \ - const boolean last_vertex_last = \ - !(draw->rasterizer->flatshade && \ - draw->rasterizer->flatshade_first); \ + const unsigned prim_flags = input_prims->flags; \ + const boolean last_vertex_last = TRUE; \ do { \ debug_assert(input_prims->primitive_count == 1); \ switch (prim) { \ diff --git a/src/gallium/auxiliary/draw/draw_split_tmp.h b/src/gallium/auxiliary/draw/draw_split_tmp.h new file mode 100644 index 0000000000..47defc62b9 --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_split_tmp.h @@ -0,0 +1,176 @@ +/* + * Mesa 3-D graphics library + * Version: 7.9 + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (C) 2010 LunarG Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +static void +FUNC(FUNC_VARS) +{ + unsigned first, incr; + LOCAL_VARS + + /* + * prim, start, count, and max_count_{simple,loop,fan} should have been + * defined + */ + if (0) { + debug_printf("%s: prim 0x%x, start %d, count %d, max_count_simple %d, " + "max_count_loop %d, max_count_fan %d\n", + __FUNCTION__, prim, start, count, max_count_simple, + max_count_loop, max_count_fan); + } + + draw_pt_split_prim(prim, &first, &incr); + /* sanitize primitive length */ + count = draw_pt_trim_count(count, first, incr); + if (count < first) + return; + + /* try flushing the entire primitive */ + if (PRIMITIVE(start, count)) + return; + + /* must be able to at least flush two complete primitives */ + assert(max_count_simple >= first + incr && + max_count_loop >= first + incr && + max_count_fan >= first + incr); + + /* no splitting required */ + if (count <= max_count_simple) { + SEGMENT_SIMPLE(0x0, start, count); + } + else { + const unsigned rollback = first - incr; + unsigned flags = DRAW_SPLIT_AFTER, seg_start = 0, seg_max; + + /* + * Both count and seg_max below are explicitly trimmed. Because + * + * seg_start = N * (seg_max - rollback) = N' * incr, + * + * we have + * + * remaining = count - seg_start = first + N'' * incr. + * + * That is, remaining is implicitly trimmed. + */ + switch (prim) { + case PIPE_PRIM_POINTS: + case PIPE_PRIM_LINES: + case PIPE_PRIM_LINE_STRIP: + case PIPE_PRIM_TRIANGLES: + case PIPE_PRIM_TRIANGLE_STRIP: + case PIPE_PRIM_QUADS: + case PIPE_PRIM_QUAD_STRIP: + case PIPE_PRIM_LINES_ADJACENCY: + case PIPE_PRIM_LINE_STRIP_ADJACENCY: + case PIPE_PRIM_TRIANGLES_ADJACENCY: + case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: + seg_max = + draw_pt_trim_count(MIN2(max_count_simple, count), first, incr); + if (prim == PIPE_PRIM_TRIANGLE_STRIP || + prim == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY) { + /* make sure we flush even number of triangles at a time */ + if (seg_max < count && !(((seg_max - first) / incr) & 1)) + seg_max -= incr; + } + + do { + const unsigned remaining = count - seg_start; + + if (remaining > seg_max) { + SEGMENT_SIMPLE(flags, start + seg_start, seg_max); + seg_start += seg_max - rollback; + + flags |= DRAW_SPLIT_BEFORE; + } + else { + flags &= ~DRAW_SPLIT_AFTER; + + SEGMENT_SIMPLE(flags, start + seg_start, remaining); + seg_start += remaining; + } + } while (seg_start < count); + break; + + case PIPE_PRIM_LINE_LOOP: + seg_max = + draw_pt_trim_count(MIN2(max_count_loop, count), first, incr); + + do { + const unsigned remaining = count - seg_start; + + if (remaining > seg_max) { + SEGMENT_LOOP(flags, start + seg_start, seg_max, start); + seg_start += seg_max - rollback; + + flags |= DRAW_SPLIT_BEFORE; + } + else { + flags &= ~DRAW_SPLIT_AFTER; + + SEGMENT_LOOP(flags, start + seg_start, remaining, start); + seg_start += remaining; + } + } while (seg_start < count); + break; + + case PIPE_PRIM_TRIANGLE_FAN: + case PIPE_PRIM_POLYGON: + seg_max = + draw_pt_trim_count(MIN2(max_count_fan, count), first, incr); + + do { + const unsigned remaining = count - seg_start; + + if (remaining > seg_max) { + SEGMENT_FAN(flags, start + seg_start, seg_max, start); + seg_start += seg_max - rollback; + + flags |= DRAW_SPLIT_BEFORE; + } + else { + flags &= ~DRAW_SPLIT_AFTER; + + SEGMENT_FAN(flags, start + seg_start, remaining, start); + seg_start += remaining; + } + } while (seg_start < count); + break; + + default: + assert(0); + break; + } + } +} + +#undef FUNC +#undef FUNC_VARS +#undef LOCAL_VARS + +#undef PRIMITIVE +#undef SEGMENT_SIMPLE +#undef SEGMENT_LOOP +#undef SEGMENT_FAN diff --git a/src/gallium/auxiliary/draw/draw_vs_llvm.c b/src/gallium/auxiliary/draw/draw_vs_llvm.c index d13ad24fff..fa9992db78 100644 --- a/src/gallium/auxiliary/draw/draw_vs_llvm.c +++ b/src/gallium/auxiliary/draw/draw_vs_llvm.c @@ -28,6 +28,7 @@ #include "util/u_math.h" #include "util/u_memory.h" #include "pipe/p_shader_tokens.h" +#include "pipe/p_screen.h" #include "draw_private.h" #include "draw_context.h" @@ -109,6 +110,11 @@ draw_create_vs_llvm(struct draw_context *draw, tgsi_scan_shader(state->tokens, &vs->base.info); + vs->variant_key_size = + draw_llvm_variant_key_size( + vs->base.info.file_max[TGSI_FILE_INPUT]+1, + vs->base.info.file_max[TGSI_FILE_SAMPLER]+1); + vs->base.draw = draw; vs->base.prepare = vs_llvm_prepare; vs->base.run_linear = vs_llvm_run_linear; diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit.c b/src/gallium/auxiliary/gallivm/lp_bld_arit.c index 7b35dd4bb4..e0d30be98d 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_arit.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_arit.c @@ -59,14 +59,6 @@ #include "lp_bld_arit.h" -/* - * XXX: Increasing eliminates some artifacts, but adds others, most - * noticeably corruption in the Earth halo in Google Earth. - */ -#define RCP_NEWTON_STEPS 0 - -#define RSQRT_NEWTON_STEPS 0 - #define EXP_POLY_DEGREE 3 #define LOG_POLY_DEGREE 5 @@ -267,7 +259,7 @@ lp_build_add(struct lp_build_context *bld, } -/** Return the sum of the elements of a */ +/** Return the scalar sum of the elements of a */ LLVMValueRef lp_build_sum_vector(struct lp_build_context *bld, LLVMValueRef a) @@ -278,11 +270,9 @@ lp_build_sum_vector(struct lp_build_context *bld, assert(lp_check_value(type, a)); - if (a == bld->zero) - return bld->zero; - if (a == bld->undef) - return bld->undef; - assert(type.length > 1); + if (type.length == 1) { + return a; + } assert(!bld->type.norm); @@ -546,7 +536,7 @@ lp_build_mul_imm(struct lp_build_context *bld, if(b == 2 && bld->type.floating) return lp_build_add(bld, a, a); - if(util_is_pot(b)) { + if(util_is_power_of_two(b)) { unsigned shift = ffs(b) - 1; if(bld->type.floating) { @@ -1266,6 +1256,11 @@ lp_build_sqrt(struct lp_build_context *bld, * * x_{i+1} = x_i * (2 - a * x_i) * + * XXX: Unfortunately this won't give IEEE-754 conformant results for 0 or + * +/-Inf, giving NaN instead. Certain applications rely on this behavior, + * such as Google Earth, which does RCP(RSQRT(0.0) when drawing the Earth's + * halo. It would be necessary to clamp the argument to prevent this. + * * See also: * - http://en.wikipedia.org/wiki/Division_(digital)#Newton.E2.80.93Raphson_division * - http://softwarecommunity.intel.com/articles/eng/1818.htm @@ -1306,13 +1301,27 @@ lp_build_rcp(struct lp_build_context *bld, if(LLVMIsConstant(a)) return LLVMConstFDiv(bld->one, a); - if(util_cpu_caps.has_sse && type.width == 32 && type.length == 4) { + /* + * We don't use RCPPS because: + * - it only has 10bits of precision + * - it doesn't even get the reciprocate of 1.0 exactly + * - doing Newton-Rapshon steps yields wrong (NaN) values for 0.0 or Inf + * - for recent processors the benefit over DIVPS is marginal, a case + * depedent + * + * We could still use it on certain processors if benchmarks show that the + * RCPPS plus necessary workarounds are still preferrable to DIVPS; or for + * particular uses that require less workarounds. + */ + + if (FALSE && util_cpu_caps.has_sse && type.width == 32 && type.length == 4) { + const unsigned num_iterations = 0; LLVMValueRef res; unsigned i; res = lp_build_intrinsic_unary(bld->builder, "llvm.x86.sse.rcp.ps", bld->vec_type, a); - for (i = 0; i < RCP_NEWTON_STEPS; ++i) { + for (i = 0; i < num_iterations; ++i) { res = lp_build_rcp_refine(bld, a, res); } @@ -1363,13 +1372,14 @@ lp_build_rsqrt(struct lp_build_context *bld, assert(type.floating); - if(util_cpu_caps.has_sse && type.width == 32 && type.length == 4) { + if (util_cpu_caps.has_sse && type.width == 32 && type.length == 4) { + const unsigned num_iterations = 0; LLVMValueRef res; unsigned i; res = lp_build_intrinsic_unary(bld->builder, "llvm.x86.sse.rsqrt.ps", bld->vec_type, a); - for (i = 0; i < RSQRT_NEWTON_STEPS; ++i) { + for (i = 0; i < num_iterations; ++i) { res = lp_build_rsqrt_refine(bld, a, res); } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_debug.c b/src/gallium/auxiliary/gallivm/lp_bld_debug.c index 39dfc51e50..d3a5afff8c 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_debug.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_debug.c @@ -46,7 +46,7 @@ boolean lp_check_alignment(const void *ptr, unsigned alignment) { - assert(util_is_pot(alignment)); + assert(util_is_power_of_two(alignment)); return ((uintptr_t)ptr & (alignment - 1)) == 0; } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c index 247cb83ce6..92123e09d3 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c @@ -388,7 +388,7 @@ lp_build_fetch_rgba_aos(LLVMBuilderRef builder, if (format_matches_type(format_desc, type) && format_desc->block.bits <= type.width * 4 && - util_is_pot(format_desc->block.bits)) { + util_is_power_of_two(format_desc->block.bits)) { LLVMValueRef packed; /* @@ -416,7 +416,7 @@ lp_build_fetch_rgba_aos(LLVMBuilderRef builder, format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) && format_desc->block.width == 1 && format_desc->block.height == 1 && - util_is_pot(format_desc->block.bits) && + util_is_power_of_two(format_desc->block.bits) && format_desc->block.bits <= 32 && format_desc->is_bitmask && !format_desc->is_mixed && diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp index 6d5410d970..48baf7c425 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp +++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp @@ -40,6 +40,7 @@ #include <llvm/ExecutionEngine/ExecutionEngine.h> #include <llvm/ExecutionEngine/JITEventListener.h> #include <llvm/Support/CommandLine.h> +#include <llvm/Support/PrettyStackTrace.h> #include "pipe/p_config.h" #include "util/u_debug.h" @@ -143,7 +144,6 @@ lp_set_target_options(void) llvm::UnsafeFPMath = true; #endif -#if 0 /* * LLVM will generate MMX instructions for vectors <= 64 bits, leading to * innefficient code, and in 32bit systems, to the corruption of the FPU @@ -152,10 +152,8 @@ lp_set_target_options(void) * See also: * - http://llvm.org/bugs/show_bug.cgi?id=3287 * - http://l4.me.uk/post/2009/06/07/llvm-wrinkle-3-configuration-what-configuration/ - * - * XXX: Unfortunately this is not working. */ - static boolean first = FALSE; + static boolean first = TRUE; if (first) { static const char* options[] = { "prog", @@ -164,7 +162,13 @@ lp_set_target_options(void) llvm::cl::ParseCommandLineOptions(2, const_cast<char**>(options)); first = FALSE; } -#endif + + /* + * By default LLVM adds a signal handler to output a pretty stack trace. + * This signal handler is never removed, causing problems when unloading the + * shared object where the gallium driver resides. + */ + llvm::DisablePrettyStackTrace = true; } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_pack.h b/src/gallium/auxiliary/gallivm/lp_bld_pack.h index e470082b97..e947b90d16 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_pack.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_pack.h @@ -37,6 +37,8 @@ #define LP_BLD_PACK_H +#include "pipe/p_compiler.h" + #include "gallivm/lp_bld.h" diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.c b/src/gallium/auxiliary/gallivm/lp_bld_sample.c index 0fd014ab9b..259b1142e3 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.c @@ -82,9 +82,9 @@ lp_sampler_static_state(struct lp_sampler_static_state *state, state->swizzle_a = view->swizzle_a; state->target = texture->target; - state->pot_width = util_is_pot(texture->width0); - state->pot_height = util_is_pot(texture->height0); - state->pot_depth = util_is_pot(texture->depth0); + state->pot_width = util_is_power_of_two(texture->width0); + state->pot_height = util_is_power_of_two(texture->height0); + state->pot_depth = util_is_power_of_two(texture->depth0); state->wrap_s = sampler->wrap_s; state->wrap_t = sampler->wrap_t; @@ -124,6 +124,52 @@ lp_sampler_static_state(struct lp_sampler_static_state *state, /** + * Compute the partial offset of a pixel block along an arbitrary axis. + * + * @param coord coordinate in pixels + * @param stride number of bytes between rows of successive pixel blocks + * @param block_length number of pixels in a pixels block along the coordinate + * axis + * @param out_offset resulting relative offset of the pixel block in bytes + * @param out_subcoord resulting sub-block pixel coordinate + */ +void +lp_build_sample_partial_offset(struct lp_build_context *bld, + unsigned block_length, + LLVMValueRef coord, + LLVMValueRef stride, + LLVMValueRef *out_offset, + LLVMValueRef *out_subcoord) +{ + LLVMValueRef offset; + LLVMValueRef subcoord; + + if (block_length == 1) { + subcoord = bld->zero; + } + else { + /* + * Pixel blocks have power of two dimensions. LLVM should convert the + * rem/div to bit arithmetic. + * TODO: Verify this. + */ + + LLVMValueRef block_width = lp_build_const_int_vec(bld->type, block_length); + subcoord = LLVMBuildURem(bld->builder, coord, block_width, ""); + coord = LLVMBuildUDiv(bld->builder, coord, block_width, ""); + } + + offset = lp_build_mul(bld, coord, stride); + + assert(out_offset); + assert(out_subcoord); + + *out_offset = offset; + *out_subcoord = subcoord; +} + + +/** * Compute the offset of a pixel block. * * x, y, z, y_stride, z_stride are vectors, and they refer to pixels. @@ -144,48 +190,35 @@ lp_build_sample_offset(struct lp_build_context *bld, { LLVMValueRef x_stride; LLVMValueRef offset; - LLVMValueRef i; - LLVMValueRef j; - - /* - * Describe the coordinates in terms of pixel blocks. - * - * TODO: pixel blocks are power of two. LLVM should convert rem/div to - * bit arithmetic. Verify this. - */ - - if (format_desc->block.width == 1) { - i = bld->zero; - } - else { - LLVMValueRef block_width = lp_build_const_int_vec(bld->type, format_desc->block.width); - i = LLVMBuildURem(bld->builder, x, block_width, ""); - x = LLVMBuildUDiv(bld->builder, x, block_width, ""); - } - - if (format_desc->block.height == 1) { - j = bld->zero; - } - else { - LLVMValueRef block_height = lp_build_const_int_vec(bld->type, format_desc->block.height); - j = LLVMBuildURem(bld->builder, y, block_height, ""); - y = LLVMBuildUDiv(bld->builder, y, block_height, ""); - } x_stride = lp_build_const_vec(bld->type, format_desc->block.bits/8); - offset = lp_build_mul(bld, x, x_stride); + + lp_build_sample_partial_offset(bld, + format_desc->block.width, + x, x_stride, + &offset, out_i); if (y && y_stride) { - LLVMValueRef y_offset = lp_build_mul(bld, y, y_stride); + LLVMValueRef y_offset; + lp_build_sample_partial_offset(bld, + format_desc->block.height, + y, y_stride, + &y_offset, out_j); offset = lp_build_add(bld, offset, y_offset); } + else { + *out_j = bld->zero; + } if (z && z_stride) { - LLVMValueRef z_offset = lp_build_mul(bld, z, z_stride); + LLVMValueRef z_offset; + LLVMValueRef k; + lp_build_sample_partial_offset(bld, + 1, /* pixel blocks are always 2D */ + z, z_stride, + &z_offset, &k); offset = lp_build_add(bld, offset, z_offset); } *out_offset = offset; - *out_i = i; - *out_j = j; } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.h b/src/gallium/auxiliary/gallivm/lp_bld_sample.h index 5b8f478094..caafc4eca0 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.h @@ -36,6 +36,8 @@ #define LP_BLD_SAMPLE_H +#include "pipe/p_format.h" + #include "gallivm/lp_bld.h" struct pipe_resource; @@ -147,6 +149,15 @@ lp_sampler_static_state(struct lp_sampler_static_state *state, void +lp_build_sample_partial_offset(struct lp_build_context *bld, + unsigned block_length, + LLVMValueRef coord, + LLVMValueRef stride, + LLVMValueRef *out_offset, + LLVMValueRef *out_i); + + +void lp_build_sample_offset(struct lp_build_context *bld, const struct util_format_description *format_desc, LLVMValueRef x, diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c index 806c7d56a8..1f39d9c98b 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c @@ -176,6 +176,7 @@ texture_dims(enum pipe_texture_target tex) case PIPE_TEXTURE_1D: return 1; case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_CUBE: return 2; case PIPE_TEXTURE_3D: @@ -322,59 +323,6 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld, /** - * Fetch the texels as <4n x i8> in AoS form. - */ -static LLVMValueRef -lp_build_sample_packed(struct lp_build_sample_context *bld, - LLVMValueRef x, - LLVMValueRef y, - LLVMValueRef y_stride, - LLVMValueRef data_array) -{ - LLVMValueRef offset, i, j; - LLVMValueRef data_ptr; - LLVMValueRef res; - - /* convert x,y,z coords to linear offset from start of texture, in bytes */ - lp_build_sample_offset(&bld->uint_coord_bld, - bld->format_desc, - x, y, NULL, y_stride, NULL, - &offset, &i, &j); - - /* get pointer to mipmap level 0 data */ - data_ptr = lp_build_get_const_mipmap_level(bld, data_array, 0); - - if (util_format_is_rgba8_variant(bld->format_desc)) { - /* Just fetch the data directly without swizzling */ - assert(bld->format_desc->block.width == 1); - assert(bld->format_desc->block.height == 1); - assert(bld->format_desc->block.bits <= bld->texel_type.width); - - res = lp_build_gather(bld->builder, - bld->texel_type.length, - bld->format_desc->block.bits, - bld->texel_type.width, - data_ptr, offset); - } - else { - struct lp_type type; - - assert(bld->texel_type.width == 32); - - memset(&type, 0, sizeof type); - type.width = 8; - type.length = bld->texel_type.length*4; - type.norm = TRUE; - - res = lp_build_fetch_rgba_aos(bld->builder, bld->format_desc, type, - data_ptr, offset, i, j); - } - - return res; -} - - -/** * Helper to compute the mirror function for the PIPE_WRAP_MIRROR modes. */ static LLVMValueRef @@ -408,7 +356,7 @@ lp_build_coord_mirror(struct lp_build_sample_context *bld, /** - * We only support a few wrap modes in lp_build_sample_wrap_int() at this time. + * We only support a few wrap modes in lp_build_sample_wrap_linear_int() at this time. * Return whether the given mode is supported by that function. */ static boolean @@ -430,13 +378,18 @@ is_simple_wrap_mode(unsigned mode) * \param length the texture size along one dimension * \param is_pot if TRUE, length is a power of two * \param wrap_mode one of PIPE_TEX_WRAP_x + * \param i0 resulting sub-block pixel coordinate for coord0 */ -static LLVMValueRef -lp_build_sample_wrap_int(struct lp_build_sample_context *bld, - LLVMValueRef coord, - LLVMValueRef length, - boolean is_pot, - unsigned wrap_mode) +static void +lp_build_sample_wrap_nearest_int(struct lp_build_sample_context *bld, + unsigned block_length, + LLVMValueRef coord, + LLVMValueRef length, + LLVMValueRef stride, + boolean is_pot, + unsigned wrap_mode, + LLVMValueRef *out_offset, + LLVMValueRef *out_i) { struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld; struct lp_build_context *int_coord_bld = &bld->int_coord_bld; @@ -469,7 +422,134 @@ lp_build_sample_wrap_int(struct lp_build_sample_context *bld, assert(0); } - return coord; + lp_build_sample_partial_offset(uint_coord_bld, block_length, coord, stride, + out_offset, out_i); +} + + +/** + * Build LLVM code for texture wrap mode, for scaled integer texcoords. + * \param coord0 the incoming texcoord (s,t,r or q) scaled to the texture size + * \param length the texture size along one dimension + * \param stride pixel stride along the coordinate axis + * \param block_length is the length of the pixel block along the + * coordinate axis + * \param is_pot if TRUE, length is a power of two + * \param wrap_mode one of PIPE_TEX_WRAP_x + * \param offset0 resulting relative offset for coord0 + * \param offset1 resulting relative offset for coord0 + 1 + * \param i0 resulting sub-block pixel coordinate for coord0 + * \param i1 resulting sub-block pixel coordinate for coord0 + 1 + */ +static void +lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld, + unsigned block_length, + LLVMValueRef coord0, + LLVMValueRef length, + LLVMValueRef stride, + boolean is_pot, + unsigned wrap_mode, + LLVMValueRef *offset0, + LLVMValueRef *offset1, + LLVMValueRef *i0, + LLVMValueRef *i1) +{ + struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld; + struct lp_build_context *int_coord_bld = &bld->int_coord_bld; + LLVMValueRef length_minus_one; + LLVMValueRef lmask, umask, mask; + + if (block_length != 1) { + /* + * If the pixel block covers more than one pixel then there is no easy + * way to calculate offset1 relative to offset0. Instead, compute them + * independently. + */ + + LLVMValueRef coord1; + + lp_build_sample_wrap_nearest_int(bld, + block_length, + coord0, + length, + stride, + is_pot, + wrap_mode, + offset0, i0); + + coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); + + lp_build_sample_wrap_nearest_int(bld, + block_length, + coord1, + length, + stride, + is_pot, + wrap_mode, + offset1, i1); + + return; + } + + /* + * Scalar pixels -- try to compute offset0 and offset1 with a single stride + * multiplication. + */ + + *i0 = uint_coord_bld->zero; + *i1 = uint_coord_bld->zero; + + length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one); + + switch(wrap_mode) { + case PIPE_TEX_WRAP_REPEAT: + if (is_pot) { + coord0 = LLVMBuildAnd(bld->builder, coord0, length_minus_one, ""); + } + else { + /* Signed remainder won't give the right results for negative + * dividends but unsigned remainder does.*/ + coord0 = LLVMBuildURem(bld->builder, coord0, length, ""); + } + + mask = lp_build_compare(bld->builder, int_coord_bld->type, + PIPE_FUNC_NOTEQUAL, coord0, length_minus_one); + + *offset0 = lp_build_mul(uint_coord_bld, coord0, stride); + *offset1 = LLVMBuildAnd(bld->builder, + lp_build_add(uint_coord_bld, *offset0, stride), + mask, ""); + break; + + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + lmask = lp_build_compare(int_coord_bld->builder, int_coord_bld->type, + PIPE_FUNC_GEQUAL, coord0, int_coord_bld->zero); + umask = lp_build_compare(int_coord_bld->builder, int_coord_bld->type, + PIPE_FUNC_LESS, coord0, length_minus_one); + + coord0 = lp_build_select(int_coord_bld, lmask, coord0, int_coord_bld->zero); + coord0 = lp_build_select(int_coord_bld, umask, coord0, length_minus_one); + + mask = LLVMBuildAnd(bld->builder, lmask, umask, ""); + + *offset0 = lp_build_mul(uint_coord_bld, coord0, stride); + *offset1 = lp_build_add(uint_coord_bld, + *offset0, + LLVMBuildAnd(bld->builder, stride, mask, "")); + break; + + case PIPE_TEX_WRAP_CLAMP: + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + case PIPE_TEX_WRAP_MIRROR_REPEAT: + case PIPE_TEX_WRAP_MIRROR_CLAMP: + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + default: + assert(0); + *offset0 = uint_coord_bld->zero; + *offset1 = uint_coord_bld->zero; + break; + } } @@ -1740,16 +1820,21 @@ lp_build_sample_2d_linear_aos(struct lp_build_sample_context *bld, LLVMValueRef i32_c8, i32_c128, i32_c255; LLVMValueRef s_ipart, s_fpart, s_fpart_lo, s_fpart_hi; LLVMValueRef t_ipart, t_fpart, t_fpart_lo, t_fpart_hi; - LLVMValueRef x0, x1; - LLVMValueRef y0, y1; - LLVMValueRef neighbors[2][2]; + LLVMValueRef data_ptr; + LLVMValueRef x_stride, y_stride; + LLVMValueRef x_offset0, x_offset1; + LLVMValueRef y_offset0, y_offset1; + LLVMValueRef offset[2][2]; + LLVMValueRef x_subcoord[2], y_subcoord[2]; LLVMValueRef neighbors_lo[2][2]; LLVMValueRef neighbors_hi[2][2]; LLVMValueRef packed, packed_lo, packed_hi; LLVMValueRef unswizzled[4]; - LLVMValueRef stride; + const unsigned level = 0; + unsigned i, j; - assert(bld->static_state->target == PIPE_TEXTURE_2D); + assert(bld->static_state->target == PIPE_TEXTURE_2D + || bld->static_state->target == PIPE_TEXTURE_RECT); assert(bld->static_state->min_img_filter == PIPE_TEX_FILTER_LINEAR); assert(bld->static_state->mag_img_filter == PIPE_TEX_FILTER_LINEAR); assert(bld->static_state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE); @@ -1793,21 +1878,30 @@ lp_build_sample_2d_linear_aos(struct lp_build_sample_context *bld, s_fpart = LLVMBuildAnd(builder, s, i32_c255, ""); t_fpart = LLVMBuildAnd(builder, t, i32_c255, ""); - x0 = s_ipart; - y0 = t_ipart; - - x1 = lp_build_add(&bld->int_coord_bld, x0, bld->int_coord_bld.one); - y1 = lp_build_add(&bld->int_coord_bld, y0, bld->int_coord_bld.one); - - x0 = lp_build_sample_wrap_int(bld, x0, width, bld->static_state->pot_width, - bld->static_state->wrap_s); - y0 = lp_build_sample_wrap_int(bld, y0, height, bld->static_state->pot_height, - bld->static_state->wrap_t); - - x1 = lp_build_sample_wrap_int(bld, x1, width, bld->static_state->pot_width, - bld->static_state->wrap_s); - y1 = lp_build_sample_wrap_int(bld, y1, height, bld->static_state->pot_height, - bld->static_state->wrap_t); + x_stride = lp_build_const_vec(bld->uint_coord_bld.type, + bld->format_desc->block.bits/8); + + y_stride = lp_build_get_const_level_stride_vec(bld, stride_array, level); + + lp_build_sample_wrap_linear_int(bld, + bld->format_desc->block.width, + s_ipart, width, x_stride, + bld->static_state->pot_width, + bld->static_state->wrap_s, + &x_offset0, &x_offset1, + &x_subcoord[0], &x_subcoord[1]); + lp_build_sample_wrap_linear_int(bld, + bld->format_desc->block.height, + t_ipart, height, y_stride, + bld->static_state->pot_height, + bld->static_state->wrap_t, + &y_offset0, &y_offset1, + &y_subcoord[0], &y_subcoord[1]); + + offset[0][0] = lp_build_add(&bld->uint_coord_bld, x_offset0, y_offset0); + offset[0][1] = lp_build_add(&bld->uint_coord_bld, x_offset1, y_offset0); + offset[1][0] = lp_build_add(&bld->uint_coord_bld, x_offset0, y_offset1); + offset[1][1] = lp_build_add(&bld->uint_coord_bld, x_offset1, y_offset1); /* * Transform 4 x i32 in @@ -1836,7 +1930,6 @@ lp_build_sample_2d_linear_aos(struct lp_build_sample_context *bld, LLVMValueRef shuffles_hi[LP_MAX_VECTOR_LENGTH]; LLVMValueRef shuffle_lo; LLVMValueRef shuffle_hi; - unsigned i, j; for(j = 0; j < h16.type.length; j += 4) { #ifdef PIPE_ARCH_LITTLE_ENDIAN @@ -1864,7 +1957,10 @@ lp_build_sample_2d_linear_aos(struct lp_build_sample_context *bld, t_fpart_hi = LLVMBuildShuffleVector(builder, t_fpart, h16.undef, shuffle_hi, ""); } - stride = lp_build_get_const_level_stride_vec(bld, stride_array, 0); + /* + * get pointer to mipmap level 0 data + */ + data_ptr = lp_build_get_const_mipmap_level(bld, data_array, level); /* * Fetch the pixels as 4 x 32bit (rgba order might differ): @@ -1883,20 +1979,38 @@ lp_build_sample_2d_linear_aos(struct lp_build_sample_context *bld, * The higher 8 bits of the resulting elements will be zero. */ - neighbors[0][0] = lp_build_sample_packed(bld, x0, y0, stride, data_array); - neighbors[0][1] = lp_build_sample_packed(bld, x1, y0, stride, data_array); - neighbors[1][0] = lp_build_sample_packed(bld, x0, y1, stride, data_array); - neighbors[1][1] = lp_build_sample_packed(bld, x1, y1, stride, data_array); + for (j = 0; j < 2; ++j) { + for (i = 0; i < 2; ++i) { + LLVMValueRef rgba8; - neighbors[0][0] = LLVMBuildBitCast(builder, neighbors[0][0], u8n_vec_type, ""); - neighbors[0][1] = LLVMBuildBitCast(builder, neighbors[0][1], u8n_vec_type, ""); - neighbors[1][0] = LLVMBuildBitCast(builder, neighbors[1][0], u8n_vec_type, ""); - neighbors[1][1] = LLVMBuildBitCast(builder, neighbors[1][1], u8n_vec_type, ""); + if (util_format_is_rgba8_variant(bld->format_desc)) { + /* + * Given the format is a rgba8, just read the pixels as is, + * without any swizzling. Swizzling will be done later. + */ + rgba8 = lp_build_gather(bld->builder, + bld->texel_type.length, + bld->format_desc->block.bits, + bld->texel_type.width, + data_ptr, offset[j][i]); - lp_build_unpack2(builder, u8n.type, h16.type, neighbors[0][0], &neighbors_lo[0][0], &neighbors_hi[0][0]); - lp_build_unpack2(builder, u8n.type, h16.type, neighbors[0][1], &neighbors_lo[0][1], &neighbors_hi[0][1]); - lp_build_unpack2(builder, u8n.type, h16.type, neighbors[1][0], &neighbors_lo[1][0], &neighbors_hi[1][0]); - lp_build_unpack2(builder, u8n.type, h16.type, neighbors[1][1], &neighbors_lo[1][1], &neighbors_hi[1][1]); + rgba8 = LLVMBuildBitCast(builder, rgba8, u8n_vec_type, ""); + + } + else { + rgba8 = lp_build_fetch_rgba_aos(bld->builder, + bld->format_desc, + u8n.type, + data_ptr, offset[j][i], + x_subcoord[i], + y_subcoord[j]); + } + + lp_build_unpack2(builder, u8n.type, h16.type, + rgba8, + &neighbors_lo[j][i], &neighbors_hi[j][i]); + } + } /* * Linear interpolate with 8.8 fixed point. @@ -2077,7 +2191,8 @@ lp_build_sample_soa(LLVMBuilderRef builder, } else if (util_format_fits_8unorm(bld.format_desc) && bld.format_desc->nr_channels > 1 && - static_state->target == PIPE_TEXTURE_2D && + (static_state->target == PIPE_TEXTURE_2D || + static_state->target == PIPE_TEXTURE_RECT) && static_state->min_img_filter == PIPE_TEX_FILTER_LINEAR && static_state->mag_img_filter == PIPE_TEX_FILTER_LINEAR && static_state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE && diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c index 0aa64affac..0e07f7f3f3 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c @@ -200,8 +200,10 @@ static void lp_exec_mask_cond_push(struct lp_exec_mask *mask, } mask->cond_stack[mask->cond_stack_size++] = mask->cond_mask; assert(LLVMTypeOf(val) == mask->int_vec_type); - mask->cond_mask = val; - + mask->cond_mask = LLVMBuildAnd(mask->bld->builder, + mask->cond_mask, + val, + ""); lp_exec_mask_update(mask); } @@ -802,7 +804,7 @@ emit_store( case TGSI_FILE_PREDICATE: lp_exec_mask_store(&bld->exec_mask, pred, value, - bld->preds[index][chan_index]); + bld->preds[reg->Register.Index][chan_index]); break; default: diff --git a/src/gallium/auxiliary/gallivm/lp_bld_type.h b/src/gallium/auxiliary/gallivm/lp_bld_type.h index 3ffe916f8e..fec1d3dfbc 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_type.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_type.h @@ -128,16 +128,16 @@ struct lp_build_context */ struct lp_type type; - /** Same as lp_build_undef(type) */ + /** Same as lp_build_elem_type(type) */ LLVMTypeRef elem_type; - /** Same as lp_build_undef(type) */ + /** Same as lp_build_vec_type(type) */ LLVMTypeRef vec_type; - /** Same as lp_build_undef(type) */ + /** Same as lp_build_int_elem_type(type) */ LLVMTypeRef int_elem_type; - /** Same as lp_build_undef(type) */ + /** Same as lp_build_int_vec_type(type) */ LLVMTypeRef int_vec_type; /** Same as lp_build_undef(type) */ diff --git a/src/gallium/auxiliary/os/os_stream.c b/src/gallium/auxiliary/os/os_stream.c new file mode 100644 index 0000000000..3c55fc00d9 --- /dev/null +++ b/src/gallium/auxiliary/os/os_stream.c @@ -0,0 +1,58 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "pipe/p_config.h" + +#include "os_stream.h" +#include "util/u_memory.h" +#include "util/u_string.h" + +int +os_default_stream_vprintf (struct os_stream* stream, const char *format, va_list ap) +{ + char buf[1024]; + int retval; + va_list ap2; + va_copy(ap2, ap); + retval = util_vsnprintf(buf, sizeof(buf), format, ap2); + va_end(ap2); + if(retval <= 0) + {} + else if(retval < sizeof(buf)) + stream->write(stream, buf, retval); + else + { + char* str = MALLOC(retval + 1); + if(!str) + return -1; + retval = util_vsnprintf(str, retval + 1, format, ap); + if(retval > 0) + stream->write(stream, str, retval); + FREE(str); + } + + return retval; +} diff --git a/src/gallium/auxiliary/os/os_stream.h b/src/gallium/auxiliary/os/os_stream.h index 693a0621e2..6c6050bb02 100644 --- a/src/gallium/auxiliary/os/os_stream.h +++ b/src/gallium/auxiliary/os/os_stream.h @@ -50,6 +50,9 @@ struct os_stream void (*flush)(struct os_stream *stream); + + int + (*vprintf)(struct os_stream *stream, const char* format, va_list ap); }; @@ -90,6 +93,27 @@ os_stream_flush(struct os_stream *stream) stream->flush(stream); } +int +os_default_stream_vprintf (struct os_stream* stream, const char *format, va_list ap); + +static INLINE int +os_stream_vprintf (struct os_stream* stream, const char *format, va_list ap) +{ + return stream->vprintf(stream, format, ap); +} + +static INLINE int +os_stream_printf (struct os_stream* stream, const char *format, ...) +{ + int retval; + va_list args; + + va_start (args, format); + retval = stream->vprintf(stream, format, args); + va_end (args); + + return retval; +} struct os_stream * os_file_stream_create(const char *filename); @@ -118,5 +142,4 @@ os_str_stream_get_and_close(struct os_stream *stream); #define os_file_stream_create(_filename) os_null_stream_create() #endif - #endif /* _OS_STREAM_H_ */ diff --git a/src/gallium/auxiliary/os/os_stream_log.c b/src/gallium/auxiliary/os/os_stream_log.c index 7cc2028a22..b01377c346 100644 --- a/src/gallium/auxiliary/os/os_stream_log.c +++ b/src/gallium/auxiliary/os/os_stream_log.c @@ -73,7 +73,8 @@ static struct os_stream os_log_stream_struct = { &os_log_stream_close, &os_log_stream_write, - &os_log_stream_flush + &os_log_stream_flush, + &os_default_stream_vprintf, }; diff --git a/src/gallium/auxiliary/os/os_stream_null.c b/src/gallium/auxiliary/os/os_stream_null.c index 128c4e8f0e..a549a789e6 100644 --- a/src/gallium/auxiliary/os/os_stream_null.c +++ b/src/gallium/auxiliary/os/os_stream_null.c @@ -56,12 +56,18 @@ os_null_stream_flush(struct os_stream *stream) (void)stream; } +static int +os_null_stream_vprintf (struct os_stream* stream, const char *format, va_list ap) +{ + return 0; +} static struct os_stream os_null_stream = { &os_null_stream_close, &os_null_stream_write, - &os_null_stream_flush + &os_null_stream_flush, + &os_null_stream_vprintf }; diff --git a/src/gallium/auxiliary/os/os_stream_stdc.c b/src/gallium/auxiliary/os/os_stream_stdc.c index 9e7ed71107..37e7d063e2 100644 --- a/src/gallium/auxiliary/os/os_stream_stdc.c +++ b/src/gallium/auxiliary/os/os_stream_stdc.c @@ -83,6 +83,14 @@ os_stdc_stream_flush(struct os_stream *_stream) fflush(stream->file); } +static int +os_stdc_stream_vprintf (struct os_stream* _stream, const char *format, va_list ap) +{ + struct os_stdc_stream *stream = os_stdc_stream(_stream); + + return vfprintf(stream->file, format, ap); +} + struct os_stream * os_file_stream_create(const char *filename) @@ -96,6 +104,7 @@ os_file_stream_create(const char *filename) stream->base.close = &os_stdc_stream_close; stream->base.write = &os_stdc_stream_write; stream->base.flush = &os_stdc_stream_flush; + stream->base.vprintf = &os_stdc_stream_vprintf; stream->file = fopen(filename, "w"); if(!stream->file) diff --git a/src/gallium/auxiliary/os/os_stream_str.c b/src/gallium/auxiliary/os/os_stream_str.c index b5c7270d2a..be9478b2a1 100644 --- a/src/gallium/auxiliary/os/os_stream_str.c +++ b/src/gallium/auxiliary/os/os_stream_str.c @@ -118,6 +118,7 @@ os_str_stream_create(size_t size) stream->base.close = &os_str_stream_close; stream->base.write = &os_str_stream_write; stream->base.flush = &os_str_stream_flush; + stream->base.vprintf = &os_default_stream_vprintf; stream->str = os_malloc(size); if(!stream->str) diff --git a/src/gallium/auxiliary/pipebuffer/pb_bufmgr.h b/src/gallium/auxiliary/pipebuffer/pb_bufmgr.h index cec2524da2..2ef02160f2 100644 --- a/src/gallium/auxiliary/pipebuffer/pb_bufmgr.h +++ b/src/gallium/auxiliary/pipebuffer/pb_bufmgr.h @@ -50,8 +50,7 @@ #define PB_BUFMGR_H_ -#include "pipe/p_compiler.h" -#include "pipe/p_defines.h" +#include "pb_buffer.h" #ifdef __cplusplus diff --git a/src/gallium/auxiliary/rtasm/rtasm_cpu.c b/src/gallium/auxiliary/rtasm/rtasm_cpu.c index 2e15751e50..0461c81550 100644 --- a/src/gallium/auxiliary/rtasm/rtasm_cpu.c +++ b/src/gallium/auxiliary/rtasm/rtasm_cpu.c @@ -30,7 +30,7 @@ #include "rtasm_cpu.h" -#if defined(PIPE_ARCH_X86) +#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) static boolean rtasm_sse_enabled(void) { static boolean firsttime = 1; @@ -49,7 +49,7 @@ static boolean rtasm_sse_enabled(void) int rtasm_cpu_has_sse(void) { /* FIXME: actually detect this at run-time */ -#if defined(PIPE_ARCH_X86) +#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) return rtasm_sse_enabled(); #else return 0; @@ -59,7 +59,7 @@ int rtasm_cpu_has_sse(void) int rtasm_cpu_has_sse2(void) { /* FIXME: actually detect this at run-time */ -#if defined(PIPE_ARCH_X86) +#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) return rtasm_sse_enabled(); #else return 0; diff --git a/src/gallium/auxiliary/rtasm/rtasm_x86sse.c b/src/gallium/auxiliary/rtasm/rtasm_x86sse.c index 9f70b73698..75b0f6a68e 100644 --- a/src/gallium/auxiliary/rtasm/rtasm_x86sse.c +++ b/src/gallium/auxiliary/rtasm/rtasm_x86sse.c @@ -22,8 +22,9 @@ **************************************************************************/ #include "pipe/p_config.h" +#include "util/u_cpu_detect.h" -#if defined(PIPE_ARCH_X86) +#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) #include "pipe/p_compiler.h" #include "util/u_debug.h" @@ -231,6 +232,10 @@ static void emit_modrm( struct x86_function *p, assert(reg.mod == mod_REG); + /* TODO: support extended x86-64 registers */ + assert(reg.idx < 8); + assert(regmem.idx < 8); + val |= regmem.mod << 6; /* mod field */ val |= reg.idx << 3; /* reg field */ val |= regmem.idx; /* r/m field */ @@ -363,6 +368,12 @@ int x86_get_label( struct x86_function *p ) */ +void x64_rexw(struct x86_function *p) +{ + if(x86_target(p) != X86_32) + emit_1ub(p, 0x48); +} + void x86_jcc( struct x86_function *p, enum x86_cc cc, int label ) @@ -449,6 +460,52 @@ void x86_mov_reg_imm( struct x86_function *p, struct x86_reg dst, int imm ) emit_1i(p, imm); } +void x86_mov_imm( struct x86_function *p, struct x86_reg dst, int imm ) +{ + DUMP_RI( dst, imm ); + if(dst.mod == mod_REG) + x86_mov_reg_imm(p, dst, imm); + else + { + emit_1ub(p, 0xc7); + emit_modrm_noreg(p, 0, dst); + emit_1i(p, imm); + } +} + +void x86_mov16_imm( struct x86_function *p, struct x86_reg dst, uint16_t imm ) +{ + DUMP_RI( dst, imm ); + emit_1ub(p, 0x66); + if(dst.mod == mod_REG) + { + emit_1ub(p, 0xb8 + dst.idx); + emit_2ub(p, imm & 0xff, imm >> 8); + } + else + { + emit_1ub(p, 0xc7); + emit_modrm_noreg(p, 0, dst); + emit_2ub(p, imm & 0xff, imm >> 8); + } +} + +void x86_mov8_imm( struct x86_function *p, struct x86_reg dst, uint8_t imm ) +{ + DUMP_RI( dst, imm ); + if(dst.mod == mod_REG) + { + emit_1ub(p, 0xb0 + dst.idx); + emit_1ub(p, imm); + } + else + { + emit_1ub(p, 0xc6); + emit_modrm_noreg(p, 0, dst); + emit_1ub(p, imm); + } +} + /** * Immediate group 1 instructions. */ @@ -520,7 +577,7 @@ void x86_push( struct x86_function *p, } - p->stack_offset += 4; + p->stack_offset += sizeof(void*); } void x86_push_imm32( struct x86_function *p, @@ -530,7 +587,7 @@ void x86_push_imm32( struct x86_function *p, emit_1ub(p, 0x68); emit_1i(p, imm32); - p->stack_offset += 4; + p->stack_offset += sizeof(void*); } @@ -540,23 +597,33 @@ void x86_pop( struct x86_function *p, DUMP_R( reg ); assert(reg.mod == mod_REG); emit_1ub(p, 0x58 + reg.idx); - p->stack_offset -= 4; + p->stack_offset -= sizeof(void*); } void x86_inc( struct x86_function *p, struct x86_reg reg ) { DUMP_R( reg ); - assert(reg.mod == mod_REG); - emit_1ub(p, 0x40 + reg.idx); + if(x86_target(p) == X86_32 && reg.mod == mod_REG) + { + emit_1ub(p, 0x40 + reg.idx); + return; + } + emit_1ub(p, 0xff); + emit_modrm_noreg(p, 0, reg); } void x86_dec( struct x86_function *p, struct x86_reg reg ) { DUMP_R( reg ); - assert(reg.mod == mod_REG); - emit_1ub(p, 0x48 + reg.idx); + if(x86_target(p) == X86_32 && reg.mod == mod_REG) + { + emit_1ub(p, 0x48 + reg.idx); + return; + } + emit_1ub(p, 0xff); + emit_modrm_noreg(p, 1, reg); } void x86_ret( struct x86_function *p ) @@ -583,9 +650,82 @@ void x86_mov( struct x86_function *p, struct x86_reg src ) { DUMP_RR( dst, src ); + /* special hack for reading arguments until we support x86-64 registers everywhere */ + if(src.mod == mod_REG && dst.mod == mod_REG && (src.idx >= 8 || dst.idx >= 8)) + { + uint8_t rex = 0x40; + if(dst.idx >= 8) + { + rex |= 4; + dst.idx -= 8; + } + if(src.idx >= 8) + { + rex |= 1; + src.idx -= 8; + } + emit_1ub(p, rex); + } + emit_op_modrm( p, 0x8b, 0x89, dst, src ); +} + +void x86_mov16( struct x86_function *p, + struct x86_reg dst, + struct x86_reg src ) +{ + DUMP_RR( dst, src ); + emit_1ub(p, 0x66); + emit_op_modrm( p, 0x8b, 0x89, dst, src ); +} + +void x86_mov8( struct x86_function *p, + struct x86_reg dst, + struct x86_reg src ) +{ + DUMP_RR( dst, src ); + emit_op_modrm( p, 0x8a, 0x88, dst, src ); +} + +void x64_mov64( struct x86_function *p, + struct x86_reg dst, + struct x86_reg src ) +{ + uint8_t rex = 0x48; + DUMP_RR( dst, src ); + assert(x86_target(p) != X86_32); + + /* special hack for reading arguments until we support x86-64 registers everywhere */ + if(src.mod == mod_REG && dst.mod == mod_REG && (src.idx >= 8 || dst.idx >= 8)) + { + if(dst.idx >= 8) + { + rex |= 4; + dst.idx -= 8; + } + if(src.idx >= 8) + { + rex |= 1; + src.idx -= 8; + } + } + emit_1ub(p, rex); emit_op_modrm( p, 0x8b, 0x89, dst, src ); } +void x86_movzx8(struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR( dst, src ); + emit_2ub(p, 0x0f, 0xb6); + emit_modrm(p, dst, src); +} + +void x86_movzx16(struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR( dst, src ); + emit_2ub(p, 0x0f, 0xb7); + emit_modrm(p, dst, src); +} + void x86_xor( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) @@ -680,6 +820,61 @@ void x86_div( struct x86_function *p, emit_op_modrm(p, 0xf7, 0, x86_make_reg(file_REG32, 6), src); } +void x86_bswap( struct x86_function *p, struct x86_reg reg ) +{ + DUMP_R(reg); + assert(reg.file == file_REG32); + assert(reg.mod == mod_REG); + emit_2ub(p, 0x0f, 0xc8 + reg.idx); +} + +void x86_shr_imm( struct x86_function *p, struct x86_reg reg, unsigned imm ) +{ + DUMP_RI(reg, imm); + if(imm == 1) + { + emit_1ub(p, 0xd1); + emit_modrm_noreg(p, 5, reg); + } + else + { + emit_1ub(p, 0xc1); + emit_modrm_noreg(p, 5, reg); + emit_1ub(p, imm); + } +} + +void x86_sar_imm( struct x86_function *p, struct x86_reg reg, unsigned imm ) +{ + DUMP_RI(reg, imm); + if(imm == 1) + { + emit_1ub(p, 0xd1); + emit_modrm_noreg(p, 7, reg); + } + else + { + emit_1ub(p, 0xc1); + emit_modrm_noreg(p, 7, reg); + emit_1ub(p, imm); + } +} + +void x86_shl_imm( struct x86_function *p, struct x86_reg reg, unsigned imm ) +{ + DUMP_RI(reg, imm); + if(imm == 1) + { + emit_1ub(p, 0xd1); + emit_modrm_noreg(p, 4, reg); + } + else + { + emit_1ub(p, 0xc1); + emit_modrm_noreg(p, 4, reg); + emit_1ub(p, imm); + } +} /*********************************************************************** @@ -1013,6 +1208,77 @@ void sse_movmskps( struct x86_function *p, * SSE2 instructions */ +void sse2_movd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR(dst, src); + emit_2ub(p, 0x66, 0x0f); + if(dst.mod == mod_REG && dst.file == file_REG32) + { + emit_1ub(p, 0x7e); + emit_modrm(p, src, dst); + } + else + { + emit_op_modrm(p, 0x6e, 0x7e, dst, src); + } +} + +void sse2_movq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR(dst, src); + switch (dst.mod) { + case mod_REG: + emit_3ub(p, 0xf3, 0x0f, 0x7e); + emit_modrm(p, dst, src); + break; + case mod_INDIRECT: + case mod_DISP32: + case mod_DISP8: + assert(src.mod == mod_REG); + emit_3ub(p, 0x66, 0x0f, 0xd6); + emit_modrm(p, src, dst); + break; + default: + assert(0); + break; + } +} + +void sse2_movdqu( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR(dst, src); + emit_2ub(p, 0xf3, 0x0f); + emit_op_modrm(p, 0x6f, 0x7f, dst, src); +} + +void sse2_movdqa( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR(dst, src); + emit_2ub(p, 0x66, 0x0f); + emit_op_modrm(p, 0x6f, 0x7f, dst, src); +} + +void sse2_movsd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR(dst, src); + emit_2ub(p, 0xf2, 0x0f); + emit_op_modrm(p, 0x10, 0x11, dst, src); +} + +void sse2_movupd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR(dst, src); + emit_2ub(p, 0x66, 0x0f); + emit_op_modrm(p, 0x10, 0x11, dst, src); +} + +void sse2_movapd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR(dst, src); + emit_2ub(p, 0x66, 0x0f); + emit_op_modrm(p, 0x28, 0x29, dst, src); +} + /** * Perform a reduced swizzle: */ @@ -1027,6 +1293,28 @@ void sse2_pshufd( struct x86_function *p, emit_1ub(p, shuf); } +void sse2_pshuflw( struct x86_function *p, + struct x86_reg dst, + struct x86_reg src, + unsigned char shuf) +{ + DUMP_RRI( dst, src, shuf ); + emit_3ub(p, 0xf2, X86_TWOB, 0x70); + emit_modrm(p, dst, src); + emit_1ub(p, shuf); +} + +void sse2_pshufhw( struct x86_function *p, + struct x86_reg dst, + struct x86_reg src, + unsigned char shuf) +{ + DUMP_RRI( dst, src, shuf ); + emit_3ub(p, 0xf3, X86_TWOB, 0x70); + emit_modrm(p, dst, src); + emit_1ub(p, shuf); +} + void sse2_cvttps2dq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) @@ -1045,6 +1333,24 @@ void sse2_cvtps2dq( struct x86_function *p, emit_modrm( p, dst, src ); } +void sse2_cvtsd2ss( struct x86_function *p, + struct x86_reg dst, + struct x86_reg src ) +{ + DUMP_RR( dst, src ); + emit_3ub(p, 0xf2, 0x0f, 0x5a); + emit_modrm( p, dst, src ); +} + +void sse2_cvtpd2ps( struct x86_function *p, + struct x86_reg dst, + struct x86_reg src ) +{ + DUMP_RR( dst, src ); + emit_3ub(p, 0x66, 0x0f, 0x5a); + emit_modrm( p, dst, src ); +} + void sse2_packssdw( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) @@ -1081,6 +1387,97 @@ void sse2_punpcklbw( struct x86_function *p, emit_modrm( p, dst, src ); } +void sse2_punpcklwd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR( dst, src ); + emit_3ub(p, 0x66, 0x0f, 0x61); + emit_modrm( p, dst, src ); +} + +void sse2_punpckldq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR( dst, src ); + emit_3ub(p, 0x66, 0x0f, 0x62); + emit_modrm( p, dst, src ); +} + +void sse2_punpcklqdq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR( dst, src ); + emit_3ub(p, 0x66, 0x0f, 0x6c); + emit_modrm( p, dst, src ); +} + +void sse2_psllw_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ) +{ + DUMP_RI(dst, imm); + emit_3ub(p, 0x66, 0x0f, 0x71); + emit_modrm_noreg(p, 6, dst); + emit_1ub(p, imm); +} + +void sse2_pslld_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ) +{ + DUMP_RI(dst, imm); + emit_3ub(p, 0x66, 0x0f, 0x72); + emit_modrm_noreg(p, 6, dst); + emit_1ub(p, imm); +} + +void sse2_psllq_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ) +{ + DUMP_RI(dst, imm); + emit_3ub(p, 0x66, 0x0f, 0x73); + emit_modrm_noreg(p, 6, dst); + emit_1ub(p, imm); +} + +void sse2_psrlw_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ) +{ + DUMP_RI(dst, imm); + emit_3ub(p, 0x66, 0x0f, 0x71); + emit_modrm_noreg(p, 2, dst); + emit_1ub(p, imm); +} + +void sse2_psrld_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ) +{ + DUMP_RI(dst, imm); + emit_3ub(p, 0x66, 0x0f, 0x72); + emit_modrm_noreg(p, 2, dst); + emit_1ub(p, imm); +} + +void sse2_psrlq_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ) +{ + DUMP_RI(dst, imm); + emit_3ub(p, 0x66, 0x0f, 0x73); + emit_modrm_noreg(p, 2, dst); + emit_1ub(p, imm); +} + +void sse2_psraw_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ) +{ + DUMP_RI(dst, imm); + emit_3ub(p, 0x66, 0x0f, 0x71); + emit_modrm_noreg(p, 4, dst); + emit_1ub(p, imm); +} + +void sse2_psrad_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ) +{ + DUMP_RI(dst, imm); + emit_3ub(p, 0x66, 0x0f, 0x72); + emit_modrm_noreg(p, 4, dst); + emit_1ub(p, imm); +} + +void sse2_por( struct x86_function *p, struct x86_reg dst, struct x86_reg src ) +{ + DUMP_RR(dst, src); + emit_3ub(p, 0x66, 0x0f, 0xeb); + emit_modrm(p, dst, src); +} void sse2_rcpps( struct x86_function *p, struct x86_reg dst, @@ -1100,18 +1497,6 @@ void sse2_rcpss( struct x86_function *p, emit_modrm( p, dst, src ); } -void sse2_movd( struct x86_function *p, - struct x86_reg dst, - struct x86_reg src ) -{ - DUMP_RR( dst, src ); - emit_2ub(p, 0x66, X86_TWOB); - emit_op_modrm( p, 0x6e, 0x7e, dst, src ); -} - - - - /*********************************************************************** * x87 instructions */ @@ -1702,23 +2087,80 @@ void x86_cdecl_caller_pop_regs( struct x86_function *p ) } -/* Retreive a reference to one of the function arguments, taking into - * account any push/pop activity: - */ struct x86_reg x86_fn_arg( struct x86_function *p, - unsigned arg ) + unsigned arg ) { - return x86_make_disp(x86_make_reg(file_REG32, reg_SP), + switch(x86_target(p)) + { + case X86_64_WIN64_ABI: + /* Microsoft uses a different calling convention than the rest of the world */ + switch(arg) + { + case 1: + return x86_make_reg(file_REG32, reg_CX); + case 2: + return x86_make_reg(file_REG32, reg_DX); + case 3: + return x86_make_reg(file_REG32, reg_R8); + case 4: + return x86_make_reg(file_REG32, reg_R9); + default: + /* Win64 allocates stack slots as if it pushed the first 4 arguments too */ + return x86_make_disp(x86_make_reg(file_REG32, reg_SP), + p->stack_offset + arg * 8); + } + case X86_64_STD_ABI: + switch(arg) + { + case 1: + return x86_make_reg(file_REG32, reg_DI); + case 2: + return x86_make_reg(file_REG32, reg_SI); + case 3: + return x86_make_reg(file_REG32, reg_DX); + case 4: + return x86_make_reg(file_REG32, reg_CX); + case 5: + return x86_make_reg(file_REG32, reg_R8); + case 6: + return x86_make_reg(file_REG32, reg_R9); + default: + return x86_make_disp(x86_make_reg(file_REG32, reg_SP), + p->stack_offset + (arg - 6) * 8); /* ??? */ + } + case X86_32: + return x86_make_disp(x86_make_reg(file_REG32, reg_SP), p->stack_offset + arg * 4); /* ??? */ + default: + abort(); + } } +static void x86_init_func_common( struct x86_function *p ) +{ + util_cpu_detect(); + p->caps = 0; + if(util_cpu_caps.has_mmx) + p->caps |= X86_MMX; + if(util_cpu_caps.has_mmx2) + p->caps |= X86_MMX2; + if(util_cpu_caps.has_sse) + p->caps |= X86_SSE; + if(util_cpu_caps.has_sse2) + p->caps |= X86_SSE2; + if(util_cpu_caps.has_sse3) + p->caps |= X86_SSE3; + if(util_cpu_caps.has_sse4_1) + p->caps |= X86_SSE4_1; + p->csr = p->store; + DUMP_START(); +} void x86_init_func( struct x86_function *p ) { p->size = 0; p->store = NULL; - p->csr = p->store; - DUMP_START(); + x86_init_func_common(p); } void x86_init_func_size( struct x86_function *p, unsigned code_size ) @@ -1728,8 +2170,7 @@ void x86_init_func_size( struct x86_function *p, unsigned code_size ) if (p->store == NULL) { p->store = p->error_overflow; } - p->csr = p->store; - DUMP_START(); + x86_init_func_common(p); } void x86_release_func( struct x86_function *p ) diff --git a/src/gallium/auxiliary/rtasm/rtasm_x86sse.h b/src/gallium/auxiliary/rtasm/rtasm_x86sse.h index 6208e8f707..2b9678b176 100644 --- a/src/gallium/auxiliary/rtasm/rtasm_x86sse.h +++ b/src/gallium/auxiliary/rtasm/rtasm_x86sse.h @@ -24,22 +24,31 @@ #ifndef _RTASM_X86SSE_H_ #define _RTASM_X86SSE_H_ +#include "pipe/p_compiler.h" #include "pipe/p_config.h" -#if defined(PIPE_ARCH_X86) +#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) /* It is up to the caller to ensure that instructions issued are * suitable for the host cpu. There are no checks made in this module * for mmx/sse/sse2 support on the cpu. */ struct x86_reg { - unsigned file:3; - unsigned idx:3; + unsigned file:2; + unsigned idx:4; unsigned mod:2; /* mod_REG if this is just a register */ int disp:24; /* only +/- 23bits of offset - should be enough... */ }; +#define X86_MMX 1 +#define X86_MMX2 2 +#define X86_SSE 4 +#define X86_SSE2 8 +#define X86_SSE3 0x10 +#define X86_SSE4_1 0x20 + struct x86_function { + unsigned caps; unsigned size; unsigned char *store; unsigned char *csr; @@ -75,7 +84,15 @@ enum x86_reg_name { reg_SP, reg_BP, reg_SI, - reg_DI + reg_DI, + reg_R8, + reg_R9, + reg_R10, + reg_R11, + reg_R12, + reg_R13, + reg_R14, + reg_R15 }; @@ -110,6 +127,29 @@ typedef void (*x86_func)(void); /* Begin/end/retrieve function creation: */ +enum x86_target +{ + X86_32, + X86_64_STD_ABI, + X86_64_WIN64_ABI +}; + +/* make this read a member of x86_function if target != host is desired */ +static INLINE enum x86_target x86_target( struct x86_function* p ) +{ +#ifdef PIPE_ARCH_X86 + return X86_32; +#elif defined(_WIN64) + return X86_64_WIN64_ABI; +#elif defined(PIPE_ARCH_X86_64) + return X86_64_STD_ABI; +#endif +} + +static INLINE unsigned x86_target_caps( struct x86_function* p ) +{ + return p->caps; +} void x86_init_func( struct x86_function *p ); void x86_init_func_size( struct x86_function *p, unsigned code_size ); @@ -138,6 +178,8 @@ struct x86_reg x86_get_base_reg( struct x86_reg reg ); */ int x86_get_label( struct x86_function *p ); +void x64_rexw(struct x86_function *p); + void x86_jcc( struct x86_function *p, enum x86_cc cc, int label ); @@ -178,18 +220,54 @@ void mmx_movq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void mmx_packssdw( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void mmx_packuswb( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_movd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_movq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_movdqu( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_movdqa( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_movsd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_movupd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_movapd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); + void sse2_cvtps2dq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse2_cvttps2dq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse2_cvtdq2ps( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_cvtsd2ss( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_cvtpd2ps( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); + void sse2_movd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse2_packssdw( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse2_packsswb( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse2_packuswb( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse2_pshufd( struct x86_function *p, struct x86_reg dest, struct x86_reg arg0, unsigned char shuf ); +void sse2_pshuflw( struct x86_function *p, struct x86_reg dest, struct x86_reg arg0, + unsigned char shuf ); +void sse2_pshufhw( struct x86_function *p, struct x86_reg dest, struct x86_reg arg0, + unsigned char shuf ); void sse2_rcpps( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse2_rcpss( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_punpcklbw( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_punpcklwd( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_punpckldq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void sse2_punpcklqdq( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); + +void sse2_psllw_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ); +void sse2_pslld_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ); +void sse2_psllq_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ); + +void sse2_psrlw_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ); +void sse2_psrld_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ); +void sse2_psrlq_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ); + +void sse2_psraw_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ); +void sse2_psrad_imm( struct x86_function *p, struct x86_reg dst, unsigned imm ); + +void sse2_por( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); + +void sse2_pshuflw( struct x86_function *p, struct x86_reg dst, struct x86_reg src, uint8_t imm ); +void sse2_pshufhw( struct x86_function *p, struct x86_reg dst, struct x86_reg src, uint8_t imm ); +void sse2_pshufd( struct x86_function *p, struct x86_reg dst, struct x86_reg src, uint8_t imm ); void sse_prefetchnta( struct x86_function *p, struct x86_reg ptr); void sse_prefetch0( struct x86_function *p, struct x86_reg ptr); @@ -227,7 +305,6 @@ void sse_shufps( struct x86_function *p, struct x86_reg dest, struct x86_reg arg void sse_unpckhps( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse_unpcklps( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse_pmovmskb( struct x86_function *p, struct x86_reg dest, struct x86_reg src ); -void sse2_punpcklbw( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void sse_movmskps( struct x86_function *p, struct x86_reg dst, struct x86_reg src); void x86_add( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); @@ -237,6 +314,14 @@ void x86_dec( struct x86_function *p, struct x86_reg reg ); void x86_inc( struct x86_function *p, struct x86_reg reg ); void x86_lea( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void x86_mov( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void x64_mov64( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void x86_mov8( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void x86_mov16( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void x86_movzx8(struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void x86_movzx16(struct x86_function *p, struct x86_reg dst, struct x86_reg src ); +void x86_mov_imm(struct x86_function *p, struct x86_reg dst, int imm ); +void x86_mov8_imm(struct x86_function *p, struct x86_reg dst, uint8_t imm ); +void x86_mov16_imm(struct x86_function *p, struct x86_reg dst, uint16_t imm ); void x86_mul( struct x86_function *p, struct x86_reg src ); void x86_imul( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void x86_or( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); @@ -250,7 +335,10 @@ void x86_test( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void x86_xor( struct x86_function *p, struct x86_reg dst, struct x86_reg src ); void x86_sahf( struct x86_function *p ); void x86_div( struct x86_function *p, struct x86_reg src ); - +void x86_bswap( struct x86_function *p, struct x86_reg src ); +void x86_shr_imm( struct x86_function *p, struct x86_reg reg, unsigned imm ); +void x86_sar_imm( struct x86_function *p, struct x86_reg reg, unsigned imm ); +void x86_shl_imm( struct x86_function *p, struct x86_reg reg, unsigned imm ); void x86_cdecl_caller_push_regs( struct x86_function *p ); void x86_cdecl_caller_pop_regs( struct x86_function *p ); diff --git a/src/gallium/auxiliary/tgsi/tgsi_dump.h b/src/gallium/auxiliary/tgsi/tgsi_dump.h index 4cd27317b3..dd78b36100 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_dump.h +++ b/src/gallium/auxiliary/tgsi/tgsi_dump.h @@ -28,6 +28,7 @@ #ifndef TGSI_DUMP_H #define TGSI_DUMP_H +#include "pipe/p_compiler.h" #include "pipe/p_shader_tokens.h" #if defined __cplusplus diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c index 298f3d0a8b..0757f05dfa 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_exec.c +++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c @@ -3239,6 +3239,8 @@ exec_instruction( if (mach->CallStackTop == 0) { /* returning from main() */ + mach->CondStackTop = 0; + mach->LoopStackTop = 0; *pc = -1; return; } @@ -3767,6 +3769,9 @@ tgsi_exec_machine_run( struct tgsi_exec_machine *mach ) } #endif + /* Strictly speaking, these assertions aren't really needed but they + * can potentially catch some bugs in the control flow code. + */ assert(mach->CondStackTop == 0); assert(mach->LoopStackTop == 0); assert(mach->ContStackTop == 0); diff --git a/src/gallium/auxiliary/tgsi/tgsi_info.h b/src/gallium/auxiliary/tgsi/tgsi_info.h index 50248884fd..1992d11bbe 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_info.h +++ b/src/gallium/auxiliary/tgsi/tgsi_info.h @@ -28,6 +28,7 @@ #ifndef TGSI_INFO_H #define TGSI_INFO_H +#include "pipe/p_compiler.h" #include "pipe/p_shader_tokens.h" #if defined __cplusplus diff --git a/src/gallium/auxiliary/tgsi/tgsi_parse.c b/src/gallium/auxiliary/tgsi/tgsi_parse.c index db9a342220..1891203abe 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_parse.c +++ b/src/gallium/auxiliary/tgsi/tgsi_parse.c @@ -282,17 +282,6 @@ tgsi_parse_token( } -unsigned -tgsi_num_tokens(const struct tgsi_token *tokens) -{ - struct tgsi_parse_context ctx; - if (tgsi_parse_init(&ctx, tokens) == TGSI_PARSE_OK) { - unsigned len = (ctx.FullHeader.Header.HeaderSize + - ctx.FullHeader.Header.BodySize); - return len; - } - return 0; -} /** @@ -319,3 +308,19 @@ tgsi_alloc_tokens(unsigned num_tokens) unsigned bytes = num_tokens * sizeof(struct tgsi_token); return (struct tgsi_token *) MALLOC(bytes); } + + +void +tgsi_dump_tokens(const struct tgsi_token *tokens) +{ + const unsigned *dwords = (const unsigned *)tokens; + int nr = tgsi_num_tokens(tokens); + int i; + + assert(sizeof(*tokens) == sizeof(unsigned)); + + debug_printf("const unsigned tokens[%d] = {\n", nr); + for (i = 0; i < nr; i++) + debug_printf("0x%08x,\n", dwords[i]); + debug_printf("};\n"); +} diff --git a/src/gallium/auxiliary/tgsi/tgsi_parse.h b/src/gallium/auxiliary/tgsi/tgsi_parse.h index 36de8807b4..d4df585176 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_parse.h +++ b/src/gallium/auxiliary/tgsi/tgsi_parse.h @@ -28,6 +28,7 @@ #ifndef TGSI_PARSE_H #define TGSI_PARSE_H +#include "pipe/p_compiler.h" #include "pipe/p_shader_tokens.h" #if defined __cplusplus @@ -132,8 +133,15 @@ void tgsi_parse_token( struct tgsi_parse_context *ctx ); -unsigned -tgsi_num_tokens(const struct tgsi_token *tokens); +static INLINE unsigned +tgsi_num_tokens(const struct tgsi_token *tokens) +{ + struct tgsi_header header = *(const struct tgsi_header *) tokens; + return header.HeaderSize + header.BodySize; +} + +void +tgsi_dump_tokens(const struct tgsi_token *tokens); struct tgsi_token * tgsi_dup_tokens(const struct tgsi_token *tokens); diff --git a/src/gallium/auxiliary/tgsi/tgsi_sse2.h b/src/gallium/auxiliary/tgsi/tgsi_sse2.h index d81ee3d00e..00aa8b84fe 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_sse2.h +++ b/src/gallium/auxiliary/tgsi/tgsi_sse2.h @@ -32,9 +32,12 @@ extern "C" { #endif +#include "pipe/p_compiler.h" + +struct tgsi_exec_machine; +struct tgsi_interp_coef; struct tgsi_token; struct x86_function; -struct tgsi_interp_coef; unsigned tgsi_emit_sse2( diff --git a/src/gallium/auxiliary/translate/translate.c b/src/gallium/auxiliary/translate/translate.c index fe638e211f..73287b667d 100644 --- a/src/gallium/auxiliary/translate/translate.c +++ b/src/gallium/auxiliary/translate/translate.c @@ -38,7 +38,7 @@ struct translate *translate_create( const struct translate_key *key ) { struct translate *translate = NULL; -#if defined(PIPE_ARCH_X86) +#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) translate = translate_sse2_create( key ); if (translate) return translate; diff --git a/src/gallium/auxiliary/translate/translate.h b/src/gallium/auxiliary/translate/translate.h index eb6f2cc486..a75380228b 100644 --- a/src/gallium/auxiliary/translate/translate.h +++ b/src/gallium/auxiliary/translate/translate.h @@ -85,6 +85,18 @@ struct translate { unsigned instance_id, void *output_buffer); + void (PIPE_CDECL *run_elts16)( struct translate *, + const uint16_t *elts, + unsigned count, + unsigned instance_id, + void *output_buffer); + + void (PIPE_CDECL *run_elts8)( struct translate *, + const uint8_t *elts, + unsigned count, + unsigned instance_id, + void *output_buffer); + void (PIPE_CDECL *run)( struct translate *, unsigned start, unsigned count, diff --git a/src/gallium/auxiliary/translate/translate_generic.c b/src/gallium/auxiliary/translate/translate_generic.c index 42cfd763e9..ad809db720 100644 --- a/src/gallium/auxiliary/translate/translate_generic.c +++ b/src/gallium/auxiliary/translate/translate_generic.c @@ -64,6 +64,14 @@ struct translate_generic { unsigned input_stride; unsigned max_index; + /* this value is set to -1 if this is a normal element with output_format != input_format: + * in this case, u_format is used to do a full conversion + * + * this value is set to the format size in bytes if output_format == input_format or for 32-bit instance ids: + * in this case, memcpy is used to copy this amount of bytes + */ + int copy_size; + } attrib[PIPE_MAX_ATTRIBS]; unsigned nr_attrib; @@ -354,7 +362,65 @@ static emit_func get_emit_func( enum pipe_format format ) } } +static ALWAYS_INLINE void PIPE_CDECL generic_run_one( struct translate_generic *tg, + unsigned elt, + unsigned instance_id, + void *vert ) +{ + unsigned nr_attrs = tg->nr_attrib; + unsigned attr; + + for (attr = 0; attr < nr_attrs; attr++) { + float data[4]; + uint8_t *dst = (uint8_t *)vert + tg->attrib[attr].output_offset; + + if (tg->attrib[attr].type == TRANSLATE_ELEMENT_NORMAL) { + const uint8_t *src; + unsigned index; + int copy_size; + + if (tg->attrib[attr].instance_divisor) { + index = instance_id / tg->attrib[attr].instance_divisor; + } + else { + index = elt; + } + + /* clamp to void going out of bounds */ + index = MIN2(index, tg->attrib[attr].max_index); + src = tg->attrib[attr].input_ptr + + tg->attrib[attr].input_stride * index; + + copy_size = tg->attrib[attr].copy_size; + if(likely(copy_size >= 0)) + memcpy(dst, src, copy_size); + else + { + tg->attrib[attr].fetch( data, src, 0, 0 ); + + if (0) + debug_printf("Fetch linear attr %d from %p stride %d index %d: " + " %f, %f, %f, %f \n", + attr, + tg->attrib[attr].input_ptr, + tg->attrib[attr].input_stride, + index, + data[0], data[1],data[2], data[3]); + + tg->attrib[attr].emit( data, dst ); + } + } else { + if(likely(tg->attrib[attr].copy_size >= 0)) + memcpy(data, &instance_id, 4); + else + { + data[0] = (float)instance_id; + tg->attrib[attr].emit( data, dst ); + } + } + } +} /** * Fetch vertex attributes for 'count' vertices. @@ -367,62 +433,45 @@ static void PIPE_CDECL generic_run_elts( struct translate *translate, { struct translate_generic *tg = translate_generic(translate); char *vert = output_buffer; - unsigned nr_attrs = tg->nr_attrib; - unsigned attr; unsigned i; - /* loop over vertex attributes (vertex shader inputs) - */ for (i = 0; i < count; i++) { - const unsigned elt = *elts++; - - for (attr = 0; attr < nr_attrs; attr++) { - float data[4]; - char *dst = vert + tg->attrib[attr].output_offset; - - if (tg->attrib[attr].type == TRANSLATE_ELEMENT_NORMAL) { - const uint8_t *src; - unsigned index; - - if (tg->attrib[attr].instance_divisor) { - index = instance_id / tg->attrib[attr].instance_divisor; - } else { - index = elt; - } - - /* clamp to void going out of bounds */ - index = MIN2(index, tg->attrib[attr].max_index); - - src = tg->attrib[attr].input_ptr + - tg->attrib[attr].input_stride * index; - - tg->attrib[attr].fetch( data, src, 0, 0 ); - - if (0) - debug_printf("Fetch elt attr %d from %p stride %d div %u max %u index %d: " - " %f, %f, %f, %f \n", - attr, - tg->attrib[attr].input_ptr, - tg->attrib[attr].input_stride, - tg->attrib[attr].instance_divisor, - tg->attrib[attr].max_index, - index, - data[0], data[1],data[2], data[3]); - } else { - data[0] = (float)instance_id; - } + generic_run_one(tg, *elts++, instance_id, vert); + vert += tg->translate.key.output_stride; + } +} - if (0) - debug_printf("vert %d/%d attr %d: %f %f %f %f\n", - i, elt, attr, data[0], data[1], data[2], data[3]); +static void PIPE_CDECL generic_run_elts16( struct translate *translate, + const uint16_t *elts, + unsigned count, + unsigned instance_id, + void *output_buffer ) +{ + struct translate_generic *tg = translate_generic(translate); + char *vert = output_buffer; + unsigned i; - tg->attrib[attr].emit( data, dst ); - } + for (i = 0; i < count; i++) { + generic_run_one(tg, *elts++, instance_id, vert); vert += tg->translate.key.output_stride; } } +static void PIPE_CDECL generic_run_elts8( struct translate *translate, + const uint8_t *elts, + unsigned count, + unsigned instance_id, + void *output_buffer ) +{ + struct translate_generic *tg = translate_generic(translate); + char *vert = output_buffer; + unsigned i; + for (i = 0; i < count; i++) { + generic_run_one(tg, *elts++, instance_id, vert); + vert += tg->translate.key.output_stride; + } +} static void PIPE_CDECL generic_run( struct translate *translate, unsigned start, @@ -432,57 +481,10 @@ static void PIPE_CDECL generic_run( struct translate *translate, { struct translate_generic *tg = translate_generic(translate); char *vert = output_buffer; - unsigned nr_attrs = tg->nr_attrib; - unsigned attr; unsigned i; - /* loop over vertex attributes (vertex shader inputs) - */ for (i = 0; i < count; i++) { - unsigned elt = start + i; - - for (attr = 0; attr < nr_attrs; attr++) { - float data[4]; - char *dst = vert + tg->attrib[attr].output_offset; - - if (tg->attrib[attr].type == TRANSLATE_ELEMENT_NORMAL) { - const uint8_t *src; - unsigned index; - - if (tg->attrib[attr].instance_divisor) { - index = instance_id / tg->attrib[attr].instance_divisor; - } - else { - index = elt; - } - - /* clamp to void going out of bounds */ - index = MIN2(index, tg->attrib[attr].max_index); - - src = tg->attrib[attr].input_ptr + - tg->attrib[attr].input_stride * index; - - tg->attrib[attr].fetch( data, src, 0, 0 ); - - if (0) - debug_printf("Fetch linear attr %d from %p stride %d index %d: " - " %f, %f, %f, %f \n", - attr, - tg->attrib[attr].input_ptr, - tg->attrib[attr].input_stride, - index, - data[0], data[1],data[2], data[3]); - } else { - data[0] = (float)instance_id; - } - - if (0) - debug_printf("vert %d attr %d: %f %f %f %f\n", - i, attr, data[0], data[1], data[2], data[3]); - - tg->attrib[attr].emit( data, dst ); - } - + generic_run_one(tg, start + i, instance_id, vert); vert += tg->translate.key.output_stride; } } @@ -528,6 +530,8 @@ struct translate *translate_generic_create( const struct translate_key *key ) tg->translate.release = generic_release; tg->translate.set_buffer = generic_set_buffer; tg->translate.run_elts = generic_run_elts; + tg->translate.run_elts16 = generic_run_elts16; + tg->translate.run_elts8 = generic_run_elts8; tg->translate.run = generic_run; for (i = 0; i < key->nr_elements; i++) { @@ -544,9 +548,28 @@ struct translate *translate_generic_create( const struct translate_key *key ) tg->attrib[i].input_offset = key->element[i].input_offset; tg->attrib[i].instance_divisor = key->element[i].instance_divisor; - tg->attrib[i].emit = get_emit_func(key->element[i].output_format); tg->attrib[i].output_offset = key->element[i].output_offset; + tg->attrib[i].copy_size = -1; + if (tg->attrib[i].type == TRANSLATE_ELEMENT_INSTANCE_ID) + { + if(key->element[i].output_format == PIPE_FORMAT_R32_USCALED + || key->element[i].output_format == PIPE_FORMAT_R32_SSCALED) + tg->attrib[i].copy_size = 4; + } + else + { + if(key->element[i].input_format == key->element[i].output_format + && format_desc->block.width == 1 + && format_desc->block.height == 1 + && !(format_desc->block.bits & 7)) + tg->attrib[i].copy_size = format_desc->block.bits >> 3; + } + + if(tg->attrib[i].copy_size < 0) + tg->attrib[i].emit = get_emit_func(key->element[i].output_format); + else + tg->attrib[i].emit = NULL; } tg->nr_attrib = key->nr_elements; diff --git a/src/gallium/auxiliary/translate/translate_sse.c b/src/gallium/auxiliary/translate/translate_sse.c index ef3aa674a3..f8bf5b4669 100644 --- a/src/gallium/auxiliary/translate/translate_sse.c +++ b/src/gallium/auxiliary/translate/translate_sse.c @@ -30,11 +30,12 @@ #include "pipe/p_compiler.h" #include "util/u_memory.h" #include "util/u_math.h" +#include "util/u_format.h" #include "translate.h" -#if defined(PIPE_ARCH_X86) +#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) #include "rtasm/rtasm_cpu.h" #include "rtasm/rtasm_x86sse.h" @@ -46,21 +47,9 @@ #define W 3 -typedef void (PIPE_CDECL *run_func)( struct translate *translate, - unsigned start, - unsigned count, - unsigned instance_id, - void *output_buffer); - -typedef void (PIPE_CDECL *run_elts_func)( struct translate *translate, - const unsigned *elts, - unsigned count, - unsigned instance_id, - void *output_buffer); - struct translate_buffer { const void *base_ptr; - unsigned stride; + uintptr_t stride; unsigned max_index; }; @@ -73,21 +62,43 @@ struct translate_buffer_varient { #define ELEMENT_BUFFER_INSTANCE_ID 1001 +#define NUM_CONSTS 7 + +enum +{ + CONST_IDENTITY, + CONST_INV_127, + CONST_INV_255, + CONST_INV_32767, + CONST_INV_65535, + CONST_INV_2147483647, + CONST_255 +}; + +#define C(v) {(float)(v), (float)(v), (float)(v), (float)(v)} +static float consts[NUM_CONSTS][4] = { + {0, 0, 0, 1}, + C(1.0 / 127.0), + C(1.0 / 255.0), + C(1.0 / 32767.0), + C(1.0 / 65535.0), + C(1.0 / 2147483647.0), + C(255.0) +}; +#undef C struct translate_sse { struct translate translate; struct x86_function linear_func; struct x86_function elt_func; + struct x86_function elt16_func; + struct x86_function elt8_func; struct x86_function *func; - boolean loaded_identity; - boolean loaded_255; - boolean loaded_inv_255; - - float identity[4]; - float float_255[4]; - float inv_255[4]; + PIPE_ALIGN_VAR(16) float consts[NUM_CONSTS][4]; + int8_t reg_to_const[16]; + int8_t const_to_reg[NUM_CONSTS]; struct translate_buffer buffer[PIPE_MAX_ATTRIBS]; unsigned nr_buffers; @@ -102,17 +113,16 @@ struct translate_sse { boolean use_instancing; unsigned instance_id; - run_func gen_run; - run_elts_func gen_run_elts; - /* these are actually known values, but putting them in a struct * like this is helpful to keep them in sync across the file. */ struct x86_reg tmp_EAX; - struct x86_reg idx_EBX; /* either start+i or &elt[i] */ - struct x86_reg outbuf_ECX; - struct x86_reg machine_EDX; - struct x86_reg count_ESI; /* decrements to zero */ + struct x86_reg tmp2_EDX; + struct x86_reg src_ECX; + struct x86_reg idx_ESI; /* either start+i or &elt[i] */ + struct x86_reg machine_EDI; + struct x86_reg outbuf_EBX; + struct x86_reg count_EBP; /* decrements to zero */ }; static int get_offset( const void *a, const void *b ) @@ -120,281 +130,950 @@ static int get_offset( const void *a, const void *b ) return (const char *)b - (const char *)a; } +static struct x86_reg get_const( struct translate_sse *p, unsigned id) +{ + struct x86_reg reg; + unsigned i; + if(p->const_to_reg[id] >= 0) + return x86_make_reg(file_XMM, p->const_to_reg[id]); -static struct x86_reg get_identity( struct translate_sse *p ) -{ - struct x86_reg reg = x86_make_reg(file_XMM, 6); - - if (!p->loaded_identity) { - p->loaded_identity = TRUE; - p->identity[0] = 0; - p->identity[1] = 0; - p->identity[2] = 0; - p->identity[3] = 1; - - sse_movups(p->func, reg, - x86_make_disp(p->machine_EDX, - get_offset(p, &p->identity[0]))); + for(i = 2; i < 8; ++i) + { + if(p->reg_to_const[i] < 0) + break; } + /* TODO: be smarter here */ + if(i == 8) + --i; + + reg = x86_make_reg(file_XMM, i); + + if(p->reg_to_const[i] >= 0) + p->const_to_reg[p->reg_to_const[i]] = -1; + + p->reg_to_const[i] = id; + p->const_to_reg[id] = i; + + /* TODO: this should happen outside the loop, if possible */ + sse_movaps(p->func, reg, + x86_make_disp(p->machine_EDI, + get_offset(p, &p->consts[id][0]))); + return reg; } -static struct x86_reg get_255( struct translate_sse *p ) +/* load the data in a SSE2 register, padding with zeros */ +static boolean emit_load_sse2( struct translate_sse *p, + struct x86_reg data, + struct x86_reg src, + unsigned size) { - struct x86_reg reg = x86_make_reg(file_XMM, 7); - - if (!p->loaded_255) { - p->loaded_255 = TRUE; - p->float_255[0] = - p->float_255[1] = - p->float_255[2] = - p->float_255[3] = 255.0f; - - sse_movups(p->func, reg, - x86_make_disp(p->machine_EDX, - get_offset(p, &p->float_255[0]))); + struct x86_reg tmpXMM = x86_make_reg(file_XMM, 1); + struct x86_reg tmp = p->tmp_EAX; + switch(size) + { + case 1: + x86_movzx8(p->func, tmp, src); + sse2_movd(p->func, data, tmp); + break; + case 2: + x86_movzx16(p->func, tmp, src); + sse2_movd(p->func, data, tmp); + break; + case 3: + x86_movzx8(p->func, tmp, x86_make_disp(src, 2)); + x86_shl_imm(p->func, tmp, 16); + x86_mov16(p->func, tmp, src); + sse2_movd(p->func, data, tmp); + break; + case 4: + sse2_movd(p->func, data, src); + break; + case 6: + sse2_movd(p->func, data, src); + x86_movzx16(p->func, tmp, x86_make_disp(src, 4)); + sse2_movd(p->func, tmpXMM, tmp); + sse2_punpckldq(p->func, data, tmpXMM); + break; + case 8: + sse2_movq(p->func, data, src); + break; + case 12: + sse2_movq(p->func, data, src); + sse2_movd(p->func, tmpXMM, x86_make_disp(src, 8)); + sse2_punpcklqdq(p->func, data, tmpXMM); + break; + case 16: + sse2_movdqu(p->func, data, src); + break; + default: + return FALSE; } - - return reg; + return TRUE; } -static struct x86_reg get_inv_255( struct translate_sse *p ) +/* this value can be passed for the out_chans argument */ +#define CHANNELS_0001 5 + +/* this function will load #chans float values, and will + * pad the register with zeroes at least up to out_chans. + * + * If out_chans is set to CHANNELS_0001, then the fourth + * value will be padded with 1. Only pass this value if + * chans < 4 or results are undefined. + */ +static void emit_load_float32( struct translate_sse *p, + struct x86_reg data, + struct x86_reg arg0, + unsigned out_chans, + unsigned chans) { - struct x86_reg reg = x86_make_reg(file_XMM, 5); - - if (!p->loaded_inv_255) { - p->loaded_inv_255 = TRUE; - p->inv_255[0] = - p->inv_255[1] = - p->inv_255[2] = - p->inv_255[3] = 1.0f / 255.0f; - - sse_movups(p->func, reg, - x86_make_disp(p->machine_EDX, - get_offset(p, &p->inv_255[0]))); + switch(chans) + { + case 1: + /* a 0 0 0 + * a 0 0 1 + */ + sse_movss(p->func, data, arg0); + if(out_chans == CHANNELS_0001) + sse_orps(p->func, data, get_const(p, CONST_IDENTITY) ); + break; + case 2: + /* 0 0 0 1 + * a b 0 1 + */ + if(out_chans == CHANNELS_0001) + sse_shufps(p->func, data, get_const(p, CONST_IDENTITY), SHUF(X, Y, Z, W) ); + else if(out_chans > 2) + sse_movlhps(p->func, data, get_const(p, CONST_IDENTITY) ); + sse_movlps(p->func, data, arg0); + break; + case 3: + /* Have to jump through some hoops: + * + * c 0 0 0 + * c 0 0 1 if out_chans == CHANNELS_0001 + * 0 0 c 0/1 + * a b c 0/1 + */ + sse_movss(p->func, data, x86_make_disp(arg0, 8)); + if(out_chans == CHANNELS_0001) + sse_shufps(p->func, data, get_const(p, CONST_IDENTITY), SHUF(X,Y,Z,W) ); + sse_shufps(p->func, data, data, SHUF(Y,Z,X,W) ); + sse_movlps(p->func, data, arg0); + break; + case 4: + sse_movups(p->func, data, arg0); + break; } - - return reg; } +/* this function behaves like emit_load_float32, but loads + 64-bit floating point numbers, converting them to 32-bit + ones */ +static void emit_load_float64to32( struct translate_sse *p, + struct x86_reg data, + struct x86_reg arg0, + unsigned out_chans, + unsigned chans) +{ + struct x86_reg tmpXMM = x86_make_reg(file_XMM, 1); + switch(chans) + { + case 1: + sse2_movsd(p->func, data, arg0); + if(out_chans > 1) + sse2_cvtpd2ps(p->func, data, data); + else + sse2_cvtsd2ss(p->func, data, data); + if(out_chans == CHANNELS_0001) + sse_shufps(p->func, data, get_const(p, CONST_IDENTITY), SHUF(X, Y, Z, W) ); + break; + case 2: + sse2_movupd(p->func, data, arg0); + sse2_cvtpd2ps(p->func, data, data); + if(out_chans == CHANNELS_0001) + sse_shufps(p->func, data, get_const(p, CONST_IDENTITY), SHUF(X, Y, Z, W) ); + else if(out_chans > 2) + sse_movlhps(p->func, data, get_const(p, CONST_IDENTITY) ); + break; + case 3: + sse2_movupd(p->func, data, arg0); + sse2_cvtpd2ps(p->func, data, data); + sse2_movsd(p->func, tmpXMM, x86_make_disp(arg0, 16)); + if(out_chans > 3) + sse2_cvtpd2ps(p->func, tmpXMM, tmpXMM); + else + sse2_cvtsd2ss(p->func, tmpXMM, tmpXMM); + sse_movlhps(p->func, data, tmpXMM); + if(out_chans == CHANNELS_0001) + sse_orps(p->func, data, get_const(p, CONST_IDENTITY) ); + break; + case 4: + sse2_movupd(p->func, data, arg0); + sse2_cvtpd2ps(p->func, data, data); + sse2_movupd(p->func, tmpXMM, x86_make_disp(arg0, 16)); + sse2_cvtpd2ps(p->func, tmpXMM, tmpXMM); + sse_movlhps(p->func, data, tmpXMM); + break; + } +} -static void emit_load_R32G32B32A32( struct translate_sse *p, - struct x86_reg data, - struct x86_reg arg0 ) +static void emit_mov64(struct translate_sse *p, struct x86_reg dst_gpr, struct x86_reg dst_xmm, struct x86_reg src_gpr, struct x86_reg src_xmm) { - sse_movups(p->func, data, arg0); + if(x86_target(p->func) != X86_32) + x64_mov64(p->func, dst_gpr, src_gpr); + else + { + /* TODO: when/on which CPUs is SSE2 actually better than SSE? */ + if(x86_target_caps(p->func) & X86_SSE2) + sse2_movq(p->func, dst_xmm, src_xmm); + else + sse_movlps(p->func, dst_xmm, src_xmm); + } } -static void emit_load_R32G32B32( struct translate_sse *p, - struct x86_reg data, - struct x86_reg arg0 ) +static void emit_load64(struct translate_sse *p, struct x86_reg dst_gpr, struct x86_reg dst_xmm, struct x86_reg src) { - /* Have to jump through some hoops: - * - * c 0 0 0 - * c 0 0 1 - * 0 0 c 1 - * a b c 1 - */ - sse_movss(p->func, data, x86_make_disp(arg0, 8)); - sse_shufps(p->func, data, get_identity(p), SHUF(X,Y,Z,W) ); - sse_shufps(p->func, data, data, SHUF(Y,Z,X,W) ); - sse_movlps(p->func, data, arg0); + emit_mov64(p, dst_gpr, dst_xmm, src, src); } -static void emit_load_R32G32( struct translate_sse *p, - struct x86_reg data, - struct x86_reg arg0 ) +static void emit_store64(struct translate_sse *p, struct x86_reg dst, struct x86_reg src_gpr, struct x86_reg src_xmm) { - /* 0 0 0 1 - * a b 0 1 - */ - sse_movups(p->func, data, get_identity(p) ); - sse_movlps(p->func, data, arg0); + emit_mov64(p, dst, dst, src_gpr, src_xmm); } +static void emit_mov128(struct translate_sse *p, struct x86_reg dst, struct x86_reg src) +{ + if(x86_target_caps(p->func) & X86_SSE2) + sse2_movdqu(p->func, dst, src); + else + sse_movups(p->func, dst, src); +} -static void emit_load_R32( struct translate_sse *p, - struct x86_reg data, - struct x86_reg arg0 ) +/* TODO: this uses unaligned accesses liberally, which is great on Nehalem, + * but may or may not be good on older processors + * TODO: may perhaps want to use non-temporal stores here if possible + */ +static void emit_memcpy(struct translate_sse *p, struct x86_reg dst, struct x86_reg src, unsigned size) { - /* a 0 0 0 - * a 0 0 1 - */ - sse_movss(p->func, data, arg0); - sse_orps(p->func, data, get_identity(p) ); + struct x86_reg dataXMM = x86_make_reg(file_XMM, 0); + struct x86_reg dataXMM2 = x86_make_reg(file_XMM, 1); + struct x86_reg dataGPR = p->tmp_EAX; + struct x86_reg dataGPR2 = p->tmp2_EDX; + + if(size < 8) + { + switch (size) + { + case 1: + x86_mov8(p->func, dataGPR, src); + x86_mov8(p->func, dst, dataGPR); + break; + case 2: + x86_mov16(p->func, dataGPR, src); + x86_mov16(p->func, dst, dataGPR); + break; + case 3: + x86_mov16(p->func, dataGPR, src); + x86_mov8(p->func, dataGPR2, x86_make_disp(src, 2)); + x86_mov16(p->func, dst, dataGPR); + x86_mov8(p->func, x86_make_disp(dst, 2), dataGPR2); + break; + case 4: + x86_mov(p->func, dataGPR, src); + x86_mov(p->func, dst, dataGPR); + break; + case 6: + x86_mov(p->func, dataGPR, src); + x86_mov16(p->func, dataGPR2, x86_make_disp(src, 4)); + x86_mov(p->func, dst, dataGPR); + x86_mov16(p->func, x86_make_disp(dst, 4), dataGPR2); + break; + } + } + else if(!(x86_target_caps(p->func) & X86_SSE)) + { + unsigned i = 0; + assert((size & 3) == 0); + for(i = 0; i < size; i += 4) + { + x86_mov(p->func, dataGPR, x86_make_disp(src, i)); + x86_mov(p->func, x86_make_disp(dst, i), dataGPR); + } + } + else + { + switch(size) + { + case 8: + emit_load64(p, dataGPR, dataXMM, src); + emit_store64(p, dst, dataGPR, dataXMM); + break; + case 12: + emit_load64(p, dataGPR2, dataXMM, src); + x86_mov(p->func, dataGPR, x86_make_disp(src, 8)); + emit_store64(p, dst, dataGPR2, dataXMM); + x86_mov(p->func, x86_make_disp(dst, 8), dataGPR); + break; + case 16: + emit_mov128(p, dataXMM, src); + emit_mov128(p, dst, dataXMM); + break; + case 24: + emit_mov128(p, dataXMM, src); + emit_load64(p, dataGPR, dataXMM2, x86_make_disp(src, 16)); + emit_mov128(p, dst, dataXMM); + emit_store64(p, x86_make_disp(dst, 16), dataGPR, dataXMM2); + break; + case 32: + emit_mov128(p, dataXMM, src); + emit_mov128(p, dataXMM2, x86_make_disp(src, 16)); + emit_mov128(p, dst, dataXMM); + emit_mov128(p, x86_make_disp(dst, 16), dataXMM2); + break; + default: + assert(0); + } + } } +static boolean translate_attr_convert( struct translate_sse *p, + const struct translate_element *a, + struct x86_reg src, + struct x86_reg dst) -static void emit_load_R8G8B8A8_UNORM( struct translate_sse *p, - struct x86_reg data, - struct x86_reg src ) { + const struct util_format_description* input_desc = util_format_description(a->input_format); + const struct util_format_description* output_desc = util_format_description(a->output_format); + unsigned i; + boolean id_swizzle = TRUE; + unsigned swizzle[4] = {UTIL_FORMAT_SWIZZLE_NONE, UTIL_FORMAT_SWIZZLE_NONE, UTIL_FORMAT_SWIZZLE_NONE, UTIL_FORMAT_SWIZZLE_NONE}; + unsigned needed_chans = 0; + unsigned imms[2] = {0, 0x3f800000}; - /* Load and unpack twice: - */ - sse_movss(p->func, data, src); - sse2_punpcklbw(p->func, data, get_identity(p)); - sse2_punpcklbw(p->func, data, get_identity(p)); + if(a->output_format == PIPE_FORMAT_NONE || a->input_format == PIPE_FORMAT_NONE) + return FALSE; - /* Convert to float: - */ - sse2_cvtdq2ps(p->func, data, data); + if(input_desc->channel[0].size & 7) + return FALSE; + if(input_desc->colorspace != output_desc->colorspace) + return FALSE; - /* Scale by 1/255.0 - */ - sse_mulps(p->func, data, get_inv_255(p)); -} + for(i = 1; i < input_desc->nr_channels; ++i) + { + if(memcmp(&input_desc->channel[i], &input_desc->channel[0], sizeof(input_desc->channel[0]))) + return FALSE; + } + for(i = 1; i < output_desc->nr_channels; ++i) + { + if(memcmp(&output_desc->channel[i], &output_desc->channel[0], sizeof(output_desc->channel[0]))) + return FALSE; + } + for(i = 0; i < output_desc->nr_channels; ++i) + { + if(output_desc->swizzle[i] < 4) + swizzle[output_desc->swizzle[i]] = input_desc->swizzle[i]; + } + if((x86_target_caps(p->func) & X86_SSE) && (0 + || a->output_format == PIPE_FORMAT_R32_FLOAT + || a->output_format == PIPE_FORMAT_R32G32_FLOAT + || a->output_format == PIPE_FORMAT_R32G32B32_FLOAT + || a->output_format == PIPE_FORMAT_R32G32B32A32_FLOAT)) + { + struct x86_reg dataXMM = x86_make_reg(file_XMM, 0); -static void emit_store_R32G32B32A32( struct translate_sse *p, - struct x86_reg dest, - struct x86_reg dataXMM ) -{ - sse_movups(p->func, dest, dataXMM); -} + for(i = 0; i < output_desc->nr_channels; ++i) + { + if(swizzle[i] == UTIL_FORMAT_SWIZZLE_0 && i >= input_desc->nr_channels) + swizzle[i] = i; + } -static void emit_store_R32G32B32( struct translate_sse *p, - struct x86_reg dest, - struct x86_reg dataXMM ) -{ - /* Emit two, shuffle, emit one. - */ - sse_movlps(p->func, dest, dataXMM); - sse_shufps(p->func, dataXMM, dataXMM, SHUF(Z,Z,Z,Z) ); /* NOTE! destructive */ - sse_movss(p->func, x86_make_disp(dest,8), dataXMM); -} + for(i = 0; i < output_desc->nr_channels; ++i) + { + if(swizzle[i] < 4) + needed_chans = MAX2(needed_chans, swizzle[i] + 1); + if(swizzle[i] < UTIL_FORMAT_SWIZZLE_0 && swizzle[i] != i) + id_swizzle = FALSE; + } -static void emit_store_R32G32( struct translate_sse *p, - struct x86_reg dest, - struct x86_reg dataXMM ) -{ - sse_movlps(p->func, dest, dataXMM); -} + if(needed_chans > 0) + { + switch(input_desc->channel[0].type) + { + case UTIL_FORMAT_TYPE_UNSIGNED: + if(!(x86_target_caps(p->func) & X86_SSE2)) + return FALSE; + emit_load_sse2(p, dataXMM, src, input_desc->channel[0].size * input_desc->nr_channels >> 3); + + /* TODO: add support for SSE4.1 pmovzx */ + switch(input_desc->channel[0].size) + { + case 8: + /* TODO: this may be inefficient due to get_identity() being used both as a float and integer register */ + sse2_punpcklbw(p->func, dataXMM, get_const(p, CONST_IDENTITY)); + sse2_punpcklbw(p->func, dataXMM, get_const(p, CONST_IDENTITY)); + break; + case 16: + sse2_punpcklwd(p->func, dataXMM, get_const(p, CONST_IDENTITY)); + break; + case 32: /* we lose precision here */ + sse2_psrld_imm(p->func, dataXMM, 1); + break; + default: + return FALSE; + } + sse2_cvtdq2ps(p->func, dataXMM, dataXMM); + if(input_desc->channel[0].normalized) + { + struct x86_reg factor; + switch(input_desc->channel[0].size) + { + case 8: + factor = get_const(p, CONST_INV_255); + break; + case 16: + factor = get_const(p, CONST_INV_65535); + break; + case 32: + factor = get_const(p, CONST_INV_2147483647); + break; + default: + assert(0); + factor.disp = 0; + factor.file = 0; + factor.idx = 0; + factor.mod = 0; + break; + } + sse_mulps(p->func, dataXMM, factor); + } + else if(input_desc->channel[0].size == 32) + sse_addps(p->func, dataXMM, dataXMM); /* compensate for the bit we threw away to fit u32 into s32 */ + break; + case UTIL_FORMAT_TYPE_SIGNED: + if(!(x86_target_caps(p->func) & X86_SSE2)) + return FALSE; + emit_load_sse2(p, dataXMM, src, input_desc->channel[0].size * input_desc->nr_channels >> 3); + + /* TODO: add support for SSE4.1 pmovsx */ + switch(input_desc->channel[0].size) + { + case 8: + sse2_punpcklbw(p->func, dataXMM, dataXMM); + sse2_punpcklbw(p->func, dataXMM, dataXMM); + sse2_psrad_imm(p->func, dataXMM, 24); + break; + case 16: + sse2_punpcklwd(p->func, dataXMM, dataXMM); + sse2_psrad_imm(p->func, dataXMM, 16); + break; + case 32: /* we lose precision here */ + break; + default: + return FALSE; + } + sse2_cvtdq2ps(p->func, dataXMM, dataXMM); + if(input_desc->channel[0].normalized) + { + struct x86_reg factor; + switch(input_desc->channel[0].size) + { + case 8: + factor = get_const(p, CONST_INV_127); + break; + case 16: + factor = get_const(p, CONST_INV_32767); + break; + case 32: + factor = get_const(p, CONST_INV_2147483647); + break; + default: + assert(0); + factor.disp = 0; + factor.file = 0; + factor.idx = 0; + factor.mod = 0; + break; + } + sse_mulps(p->func, dataXMM, factor); + } + break; + + break; + case UTIL_FORMAT_TYPE_FLOAT: + if(input_desc->channel[0].size != 32 && input_desc->channel[0].size != 64) + return FALSE; + if(swizzle[3] == UTIL_FORMAT_SWIZZLE_1 && input_desc->nr_channels <= 3) + { + swizzle[3] = UTIL_FORMAT_SWIZZLE_W; + needed_chans = CHANNELS_0001; + } + switch(input_desc->channel[0].size) + { + case 32: + emit_load_float32(p, dataXMM, src, needed_chans, input_desc->nr_channels); + break; + case 64: /* we lose precision here */ + if(!(x86_target_caps(p->func) & X86_SSE2)) + return FALSE; + emit_load_float64to32(p, dataXMM, src, needed_chans, input_desc->nr_channels); + break; + default: + return FALSE; + } + break; + default: + return FALSE; + } -static void emit_store_R32( struct translate_sse *p, - struct x86_reg dest, - struct x86_reg dataXMM ) -{ - sse_movss(p->func, dest, dataXMM); -} + if(!id_swizzle) + sse_shufps(p->func, dataXMM, dataXMM, SHUF(swizzle[0], swizzle[1], swizzle[2], swizzle[3]) ); + } + if(output_desc->nr_channels >= 4 + && swizzle[0] < UTIL_FORMAT_SWIZZLE_0 + && swizzle[1] < UTIL_FORMAT_SWIZZLE_0 + && swizzle[2] < UTIL_FORMAT_SWIZZLE_0 + && swizzle[3] < UTIL_FORMAT_SWIZZLE_0 + ) + sse_movups(p->func, dst, dataXMM); + else + { + if(output_desc->nr_channels >= 2 + && swizzle[0] < UTIL_FORMAT_SWIZZLE_0 + && swizzle[1] < UTIL_FORMAT_SWIZZLE_0) + sse_movlps(p->func, dst, dataXMM); + else + { + if(swizzle[0] < UTIL_FORMAT_SWIZZLE_0) + sse_movss(p->func, dst, dataXMM); + else + x86_mov_imm(p->func, dst, imms[swizzle[0] - UTIL_FORMAT_SWIZZLE_0]); + + if(output_desc->nr_channels >= 2) + { + if(swizzle[1] < UTIL_FORMAT_SWIZZLE_0) + { + sse_shufps(p->func, dataXMM, dataXMM, SHUF(1, 1, 2, 3)); + sse_movss(p->func, x86_make_disp(dst, 4), dataXMM); + } + else + x86_mov_imm(p->func, x86_make_disp(dst, 4), imms[swizzle[1] - UTIL_FORMAT_SWIZZLE_0]); + } + } + if(output_desc->nr_channels >= 3) + { + if(output_desc->nr_channels >= 4 + && swizzle[2] < UTIL_FORMAT_SWIZZLE_0 + && swizzle[3] < UTIL_FORMAT_SWIZZLE_0) + sse_movhps(p->func, x86_make_disp(dst, 8), dataXMM); + else + { + if(swizzle[2] < UTIL_FORMAT_SWIZZLE_0) + { + sse_shufps(p->func, dataXMM, dataXMM, SHUF(2, 2, 2, 3)); + sse_movss(p->func, x86_make_disp(dst, 8), dataXMM); + } + else + x86_mov_imm(p->func, x86_make_disp(dst, 8), imms[swizzle[2] - UTIL_FORMAT_SWIZZLE_0]); + + if(output_desc->nr_channels >= 4) + { + if(swizzle[3] < UTIL_FORMAT_SWIZZLE_0) + { + sse_shufps(p->func, dataXMM, dataXMM, SHUF(3, 3, 3, 3)); + sse_movss(p->func, x86_make_disp(dst, 12), dataXMM); + } + else + x86_mov_imm(p->func, x86_make_disp(dst, 12), imms[swizzle[3] - UTIL_FORMAT_SWIZZLE_0]); + } + } + } + } + return TRUE; + } + else if((x86_target_caps(p->func) & X86_SSE2) && input_desc->channel[0].size == 8 && output_desc->channel[0].size == 16 + && output_desc->channel[0].normalized == input_desc->channel[0].normalized + && (0 + || (input_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED && output_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED) + || (input_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED && output_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) + || (input_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED && output_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) + )) + { + struct x86_reg dataXMM = x86_make_reg(file_XMM, 0); + struct x86_reg tmpXMM = x86_make_reg(file_XMM, 1); + struct x86_reg tmp = p->tmp_EAX; + unsigned imms[2] = {0, 1}; + + for(i = 0; i < output_desc->nr_channels; ++i) + { + if(swizzle[i] == UTIL_FORMAT_SWIZZLE_0 && i >= input_desc->nr_channels) + swizzle[i] = i; + } -static void emit_store_R8G8B8A8_UNORM( struct translate_sse *p, - struct x86_reg dest, - struct x86_reg dataXMM ) -{ - /* Scale by 255.0 - */ - sse_mulps(p->func, dataXMM, get_255(p)); + for(i = 0; i < output_desc->nr_channels; ++i) + { + if(swizzle[i] < 4) + needed_chans = MAX2(needed_chans, swizzle[i] + 1); + if(swizzle[i] < UTIL_FORMAT_SWIZZLE_0 && swizzle[i] != i) + id_swizzle = FALSE; + } - /* Pack and emit: - */ - sse2_cvtps2dq(p->func, dataXMM, dataXMM); - sse2_packssdw(p->func, dataXMM, dataXMM); - sse2_packuswb(p->func, dataXMM, dataXMM); - sse_movss(p->func, dest, dataXMM); -} + if(needed_chans > 0) + { + emit_load_sse2(p, dataXMM, src, input_desc->channel[0].size * input_desc->nr_channels >> 3); + + switch(input_desc->channel[0].type) + { + case UTIL_FORMAT_TYPE_UNSIGNED: + if(input_desc->channel[0].normalized) + { + sse2_punpcklbw(p->func, dataXMM, dataXMM); + if(output_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) + sse2_psrlw_imm(p->func, dataXMM, 1); + } + else + sse2_punpcklbw(p->func, dataXMM, get_const(p, CONST_IDENTITY)); + break; + case UTIL_FORMAT_TYPE_SIGNED: + if(input_desc->channel[0].normalized) + { + sse2_movq(p->func, tmpXMM, get_const(p, CONST_IDENTITY)); + sse2_punpcklbw(p->func, tmpXMM, dataXMM); + sse2_psllw_imm(p->func, dataXMM, 9); + sse2_psrlw_imm(p->func, dataXMM, 8); + sse2_por(p->func, tmpXMM, dataXMM); + sse2_psrlw_imm(p->func, dataXMM, 7); + sse2_por(p->func, tmpXMM, dataXMM); + { + struct x86_reg t = dataXMM; + dataXMM = tmpXMM; + tmpXMM = t; + } + } + else + { + sse2_punpcklbw(p->func, dataXMM, dataXMM); + sse2_psraw_imm(p->func, dataXMM, 8); + } + break; + default: + assert(0); + } + if(output_desc->channel[0].normalized) + imms[1] = (output_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED) ? 0xffff : 0x7ffff; + if(!id_swizzle) + sse2_pshuflw(p->func, dataXMM, dataXMM, (swizzle[0] & 3) | ((swizzle[1] & 3) << 2) | ((swizzle[2] & 3) << 4) | ((swizzle[3] & 3) << 6)); + } + if(output_desc->nr_channels >= 4 + && swizzle[0] < UTIL_FORMAT_SWIZZLE_0 + && swizzle[1] < UTIL_FORMAT_SWIZZLE_0 + && swizzle[2] < UTIL_FORMAT_SWIZZLE_0 + && swizzle[3] < UTIL_FORMAT_SWIZZLE_0 + ) + sse2_movq(p->func, dst, dataXMM); + else + { + if(swizzle[0] < UTIL_FORMAT_SWIZZLE_0) + { + if(output_desc->nr_channels >= 2 && swizzle[1] < UTIL_FORMAT_SWIZZLE_0) + sse2_movd(p->func, dst, dataXMM); + else + { + sse2_movd(p->func, tmp, dataXMM); + x86_mov16(p->func, dst, tmp); + if(output_desc->nr_channels >= 2) + x86_mov16_imm(p->func, x86_make_disp(dst, 2), imms[swizzle[1] - UTIL_FORMAT_SWIZZLE_0]); + } + } + else + { + if(output_desc->nr_channels >= 2 && swizzle[1] >= UTIL_FORMAT_SWIZZLE_0) + x86_mov_imm(p->func, dst, (imms[swizzle[1] - UTIL_FORMAT_SWIZZLE_0] << 16) | imms[swizzle[0] - UTIL_FORMAT_SWIZZLE_0]); + else + { + x86_mov16_imm(p->func, dst, imms[swizzle[0] - UTIL_FORMAT_SWIZZLE_0]); + if(output_desc->nr_channels >= 2) + { + sse2_movd(p->func, tmp, dataXMM); + x86_shr_imm(p->func, tmp, 16); + x86_mov16(p->func, x86_make_disp(dst, 2), tmp); + } + } + } + if(output_desc->nr_channels >= 3) + { + if(swizzle[2] < UTIL_FORMAT_SWIZZLE_0) + { + if(output_desc->nr_channels >= 4 && swizzle[3] < UTIL_FORMAT_SWIZZLE_0) + { + sse2_psrlq_imm(p->func, dataXMM, 32); + sse2_movd(p->func, x86_make_disp(dst, 4), dataXMM); + } + else + { + sse2_psrlq_imm(p->func, dataXMM, 32); + sse2_movd(p->func, tmp, dataXMM); + x86_mov16(p->func, x86_make_disp(dst, 4), tmp); + if(output_desc->nr_channels >= 4) + { + x86_mov16_imm(p->func, x86_make_disp(dst, 6), imms[swizzle[3] - UTIL_FORMAT_SWIZZLE_0]); + } + } + } + else + { + if(output_desc->nr_channels >= 4 && swizzle[3] >= UTIL_FORMAT_SWIZZLE_0) + x86_mov_imm(p->func, x86_make_disp(dst, 4), (imms[swizzle[3] - UTIL_FORMAT_SWIZZLE_0] << 16) | imms[swizzle[2] - UTIL_FORMAT_SWIZZLE_0]); + else + { + x86_mov16_imm(p->func, x86_make_disp(dst, 4), imms[swizzle[2] - UTIL_FORMAT_SWIZZLE_0]); + + if(output_desc->nr_channels >= 4) + { + sse2_psrlq_imm(p->func, dataXMM, 48); + sse2_movd(p->func, tmp, dataXMM); + x86_mov16(p->func, x86_make_disp(dst, 6), tmp); + } + } + } + } + } + return TRUE; + } + else if(!memcmp(&output_desc->channel[0], &input_desc->channel[0], sizeof(output_desc->channel[0]))) + { + struct x86_reg tmp = p->tmp_EAX; + unsigned i; + if(input_desc->channel[0].size == 8 && input_desc->nr_channels == 4 && output_desc->nr_channels == 4 + && swizzle[0] == UTIL_FORMAT_SWIZZLE_W + && swizzle[1] == UTIL_FORMAT_SWIZZLE_Z + && swizzle[2] == UTIL_FORMAT_SWIZZLE_Y + && swizzle[3] == UTIL_FORMAT_SWIZZLE_X) + { + /* TODO: support movbe */ + x86_mov(p->func, tmp, src); + x86_bswap(p->func, tmp); + x86_mov(p->func, dst, tmp); + return TRUE; + } -/* Extended swizzles? Maybe later. - */ -static void emit_swizzle( struct translate_sse *p, - struct x86_reg dest, - struct x86_reg src, - unsigned char shuffle ) -{ - sse_shufps(p->func, dest, src, shuffle); -} + for(i = 0; i < output_desc->nr_channels; ++i) + { + switch(output_desc->channel[0].size) + { + case 8: + if(swizzle[i] >= UTIL_FORMAT_SWIZZLE_0) + { + unsigned v = 0; + if(swizzle[i] == UTIL_FORMAT_SWIZZLE_1) + { + switch(output_desc->channel[0].type) + { + case UTIL_FORMAT_TYPE_UNSIGNED: + v = output_desc->channel[0].normalized ? 0xff : 1; + break; + case UTIL_FORMAT_TYPE_SIGNED: + v = output_desc->channel[0].normalized ? 0x7f : 1; + break; + default: + return FALSE; + } + } + x86_mov8_imm(p->func, x86_make_disp(dst, i * 1), v); + } + else + { + x86_mov8(p->func, tmp, x86_make_disp(src, swizzle[i] * 1)); + x86_mov8(p->func, x86_make_disp(dst, i * 1), tmp); + } + break; + case 16: + if(swizzle[i] >= UTIL_FORMAT_SWIZZLE_0) + { + unsigned v = 0; + if(swizzle[i] == UTIL_FORMAT_SWIZZLE_1) + { + switch(output_desc->channel[1].type) + { + case UTIL_FORMAT_TYPE_UNSIGNED: + v = output_desc->channel[1].normalized ? 0xffff : 1; + break; + case UTIL_FORMAT_TYPE_SIGNED: + v = output_desc->channel[1].normalized ? 0x7fff : 1; + break; + case UTIL_FORMAT_TYPE_FLOAT: + v = 0x3c00; + break; + default: + return FALSE; + } + } + x86_mov16_imm(p->func, x86_make_disp(dst, i * 2), v); + } + else if(swizzle[i] == UTIL_FORMAT_SWIZZLE_0) + x86_mov16_imm(p->func, x86_make_disp(dst, i * 2), 0); + else + { + x86_mov16(p->func, tmp, x86_make_disp(src, swizzle[i] * 2)); + x86_mov16(p->func, x86_make_disp(dst, i * 2), tmp); + } + break; + case 32: + if(swizzle[i] >= UTIL_FORMAT_SWIZZLE_0) + { + unsigned v = 0; + if(swizzle[i] == UTIL_FORMAT_SWIZZLE_1) + { + switch(output_desc->channel[1].type) + { + case UTIL_FORMAT_TYPE_UNSIGNED: + v = output_desc->channel[1].normalized ? 0xffffffff : 1; + break; + case UTIL_FORMAT_TYPE_SIGNED: + v = output_desc->channel[1].normalized ? 0x7fffffff : 1; + break; + case UTIL_FORMAT_TYPE_FLOAT: + v = 0x3f800000; + break; + default: + return FALSE; + } + } + x86_mov_imm(p->func, x86_make_disp(dst, i * 4), v); + } + else + { + x86_mov(p->func, tmp, x86_make_disp(src, swizzle[i] * 4)); + x86_mov(p->func, x86_make_disp(dst, i * 4), tmp); + } + break; + case 64: + if(swizzle[i] >= UTIL_FORMAT_SWIZZLE_0) + { + unsigned l = 0; + unsigned h = 0; + if(swizzle[i] == UTIL_FORMAT_SWIZZLE_1) + { + switch(output_desc->channel[1].type) + { + case UTIL_FORMAT_TYPE_UNSIGNED: + h = output_desc->channel[1].normalized ? 0xffffffff : 0; + l = output_desc->channel[1].normalized ? 0xffffffff : 1; + break; + case UTIL_FORMAT_TYPE_SIGNED: + h = output_desc->channel[1].normalized ? 0x7fffffff : 0; + l = output_desc->channel[1].normalized ? 0xffffffff : 1; + break; + case UTIL_FORMAT_TYPE_FLOAT: + h = 0x3ff00000; + l = 0; + break; + default: + return FALSE; + } + } + x86_mov_imm(p->func, x86_make_disp(dst, i * 8), l); + x86_mov_imm(p->func, x86_make_disp(dst, i * 8 + 4), h); + } + else + { + if(x86_target_caps(p->func) & X86_SSE) + { + struct x86_reg tmpXMM = x86_make_reg(file_XMM, 0); + emit_load64(p, tmp, tmpXMM, x86_make_disp(src, swizzle[i] * 8)); + emit_store64(p, x86_make_disp(dst, i * 8), tmp, tmpXMM); + } + else + { + x86_mov(p->func, tmp, x86_make_disp(src, swizzle[i] * 8)); + x86_mov(p->func, x86_make_disp(dst, i * 8), tmp); + x86_mov(p->func, tmp, x86_make_disp(src, swizzle[i] * 8 + 4)); + x86_mov(p->func, x86_make_disp(dst, i * 8 + 4), tmp); + } + } + break; + default: + return FALSE; + } + } + return TRUE; + } + /* special case for draw's EMIT_4UB (RGBA) and EMIT_4UB_BGRA */ + else if((x86_target_caps(p->func) & X86_SSE2) && + a->input_format == PIPE_FORMAT_R32G32B32A32_FLOAT && (0 + || a->output_format == PIPE_FORMAT_B8G8R8A8_UNORM + || a->output_format == PIPE_FORMAT_R8G8B8A8_UNORM + )) + { + struct x86_reg dataXMM = x86_make_reg(file_XMM, 0); + /* load */ + sse_movups(p->func, dataXMM, src); -static boolean translate_attr( struct translate_sse *p, - const struct translate_element *a, - struct x86_reg srcECX, - struct x86_reg dstEAX) -{ - struct x86_reg dataXMM = x86_make_reg(file_XMM, 0); + if (a->output_format == PIPE_FORMAT_B8G8R8A8_UNORM) + sse_shufps(p->func, dataXMM, dataXMM, SHUF(2,1,0,3)); - switch (a->input_format) { - case PIPE_FORMAT_R32_FLOAT: - emit_load_R32(p, dataXMM, srcECX); - break; - case PIPE_FORMAT_R32G32_FLOAT: - emit_load_R32G32(p, dataXMM, srcECX); - break; - case PIPE_FORMAT_R32G32B32_FLOAT: - emit_load_R32G32B32(p, dataXMM, srcECX); - break; - case PIPE_FORMAT_R32G32B32A32_FLOAT: - emit_load_R32G32B32A32(p, dataXMM, srcECX); - break; - case PIPE_FORMAT_B8G8R8A8_UNORM: - emit_load_R8G8B8A8_UNORM(p, dataXMM, srcECX); - emit_swizzle(p, dataXMM, dataXMM, SHUF(Z,Y,X,W)); - break; - case PIPE_FORMAT_R8G8B8A8_UNORM: - emit_load_R8G8B8A8_UNORM(p, dataXMM, srcECX); - break; - default: - return FALSE; - } + /* scale by 255.0 */ + sse_mulps(p->func, dataXMM, get_const(p, CONST_255)); - switch (a->output_format) { - case PIPE_FORMAT_R32_FLOAT: - emit_store_R32(p, dstEAX, dataXMM); - break; - case PIPE_FORMAT_R32G32_FLOAT: - emit_store_R32G32(p, dstEAX, dataXMM); - break; - case PIPE_FORMAT_R32G32B32_FLOAT: - emit_store_R32G32B32(p, dstEAX, dataXMM); - break; - case PIPE_FORMAT_R32G32B32A32_FLOAT: - emit_store_R32G32B32A32(p, dstEAX, dataXMM); - break; - case PIPE_FORMAT_B8G8R8A8_UNORM: - emit_swizzle(p, dataXMM, dataXMM, SHUF(Z,Y,X,W)); - emit_store_R8G8B8A8_UNORM(p, dstEAX, dataXMM); - break; - case PIPE_FORMAT_R8G8B8A8_UNORM: - emit_store_R8G8B8A8_UNORM(p, dstEAX, dataXMM); - break; - default: - return FALSE; + /* pack and emit */ + sse2_cvtps2dq(p->func, dataXMM, dataXMM); + sse2_packssdw(p->func, dataXMM, dataXMM); + sse2_packuswb(p->func, dataXMM, dataXMM); + sse2_movd(p->func, dst, dataXMM); + + return TRUE; } - return TRUE; + return FALSE; } +static boolean translate_attr( struct translate_sse *p, + const struct translate_element *a, + struct x86_reg src, + struct x86_reg dst) +{ + if(a->input_format == a->output_format) + { + emit_memcpy(p, dst, src, util_format_get_stride(a->input_format, 1)); + return TRUE; + } + + return translate_attr_convert(p, a, src, dst); +} static boolean init_inputs( struct translate_sse *p, - boolean linear ) + unsigned index_size ) { unsigned i; - struct x86_reg instance_id = x86_make_disp(p->machine_EDX, + struct x86_reg instance_id = x86_make_disp(p->machine_EDI, get_offset(p, &p->instance_id)); for (i = 0; i < p->nr_buffer_varients; i++) { struct translate_buffer_varient *varient = &p->buffer_varient[i]; struct translate_buffer *buffer = &p->buffer[varient->buffer_index]; - if (linear || varient->instance_divisor) { - struct x86_reg buf_stride = x86_make_disp(p->machine_EDX, + if (!index_size || varient->instance_divisor) { + struct x86_reg buf_stride = x86_make_disp(p->machine_EDI, get_offset(p, &buffer->stride)); - struct x86_reg buf_ptr = x86_make_disp(p->machine_EDX, + struct x86_reg buf_ptr = x86_make_disp(p->machine_EDI, get_offset(p, &varient->ptr)); - struct x86_reg buf_base_ptr = x86_make_disp(p->machine_EDX, + struct x86_reg buf_base_ptr = x86_make_disp(p->machine_EDI, get_offset(p, &buffer->base_ptr)); - struct x86_reg elt = p->idx_EBX; + struct x86_reg elt = p->idx_ESI; struct x86_reg tmp_EAX = p->tmp_EAX; /* Calculate pointer to first attrib: @@ -406,20 +1085,16 @@ static boolean init_inputs( struct translate_sse *p, x86_mov(p->func, tmp_EAX, instance_id); if (varient->instance_divisor != 1) { - struct x86_reg tmp_EDX = p->machine_EDX; - struct x86_reg tmp_ECX = p->outbuf_ECX; + struct x86_reg tmp_EDX = p->tmp2_EDX; + struct x86_reg tmp_ECX = p->src_ECX; /* TODO: Add x86_shr() to rtasm and use it whenever * instance divisor is power of two. */ - x86_push(p->func, tmp_EDX); - x86_push(p->func, tmp_ECX); x86_xor(p->func, tmp_EDX, tmp_EDX); x86_mov_reg_imm(p->func, tmp_ECX, varient->instance_divisor); x86_div(p->func, tmp_ECX); /* EAX = EDX:EAX / ECX */ - x86_pop(p->func, tmp_ECX); - x86_pop(p->func, tmp_EDX); } } else { x86_mov(p->func, tmp_EAX, elt); @@ -430,16 +1105,23 @@ static boolean init_inputs( struct translate_sse *p, */ x86_imul(p->func, tmp_EAX, buf_stride); + x64_rexw(p->func); x86_add(p->func, tmp_EAX, buf_base_ptr); /* In the linear case, keep the buffer pointer instead of the * index number. */ - if (linear && p->nr_buffer_varients == 1) + if (!index_size && p->nr_buffer_varients == 1) + { + x64_rexw(p->func); x86_mov(p->func, elt, tmp_EAX); + } else + { + x64_rexw(p->func); x86_mov(p->func, buf_ptr, tmp_EAX); + } } } @@ -448,44 +1130,57 @@ static boolean init_inputs( struct translate_sse *p, static struct x86_reg get_buffer_ptr( struct translate_sse *p, - boolean linear, + unsigned index_size, unsigned var_idx, struct x86_reg elt ) { if (var_idx == ELEMENT_BUFFER_INSTANCE_ID) { - return x86_make_disp(p->machine_EDX, + return x86_make_disp(p->machine_EDI, get_offset(p, &p->instance_id)); } - if (linear && p->nr_buffer_varients == 1) { - return p->idx_EBX; + if (!index_size && p->nr_buffer_varients == 1) { + return p->idx_ESI; } - else if (linear || p->buffer_varient[var_idx].instance_divisor) { - struct x86_reg ptr = p->tmp_EAX; + else if (!index_size || p->buffer_varient[var_idx].instance_divisor) { + struct x86_reg ptr = p->src_ECX; struct x86_reg buf_ptr = - x86_make_disp(p->machine_EDX, + x86_make_disp(p->machine_EDI, get_offset(p, &p->buffer_varient[var_idx].ptr)); + x64_rexw(p->func); x86_mov(p->func, ptr, buf_ptr); return ptr; } else { - struct x86_reg ptr = p->tmp_EAX; + struct x86_reg ptr = p->src_ECX; const struct translate_buffer_varient *varient = &p->buffer_varient[var_idx]; struct x86_reg buf_stride = - x86_make_disp(p->machine_EDX, + x86_make_disp(p->machine_EDI, get_offset(p, &p->buffer[varient->buffer_index].stride)); struct x86_reg buf_base_ptr = - x86_make_disp(p->machine_EDX, + x86_make_disp(p->machine_EDI, get_offset(p, &p->buffer[varient->buffer_index].base_ptr)); /* Calculate pointer to current attrib: */ - x86_mov(p->func, ptr, buf_stride); - x86_imul(p->func, ptr, elt); + switch(index_size) + { + case 1: + x86_movzx8(p->func, ptr, elt); + break; + case 2: + x86_movzx16(p->func, ptr, elt); + break; + case 4: + x86_mov(p->func, ptr, elt); + break; + } + x86_imul(p->func, ptr, buf_stride); + x64_rexw(p->func); x86_add(p->func, ptr, buf_base_ptr); return ptr; } @@ -494,39 +1189,43 @@ static struct x86_reg get_buffer_ptr( struct translate_sse *p, static boolean incr_inputs( struct translate_sse *p, - boolean linear ) + unsigned index_size ) { - if (linear && p->nr_buffer_varients == 1) { - struct x86_reg stride = x86_make_disp(p->machine_EDX, + if (!index_size && p->nr_buffer_varients == 1) { + struct x86_reg stride = x86_make_disp(p->machine_EDI, get_offset(p, &p->buffer[0].stride)); if (p->buffer_varient[0].instance_divisor == 0) { - x86_add(p->func, p->idx_EBX, stride); - sse_prefetchnta(p->func, x86_make_disp(p->idx_EBX, 192)); + x64_rexw(p->func); + x86_add(p->func, p->idx_ESI, stride); + sse_prefetchnta(p->func, x86_make_disp(p->idx_ESI, 192)); } } - else if (linear) { + else if (!index_size) { unsigned i; /* Is this worthwhile?? */ for (i = 0; i < p->nr_buffer_varients; i++) { struct translate_buffer_varient *varient = &p->buffer_varient[i]; - struct x86_reg buf_ptr = x86_make_disp(p->machine_EDX, + struct x86_reg buf_ptr = x86_make_disp(p->machine_EDI, get_offset(p, &varient->ptr)); - struct x86_reg buf_stride = x86_make_disp(p->machine_EDX, + struct x86_reg buf_stride = x86_make_disp(p->machine_EDI, get_offset(p, &p->buffer[varient->buffer_index].stride)); if (varient->instance_divisor == 0) { - x86_mov(p->func, p->tmp_EAX, buf_ptr); - x86_add(p->func, p->tmp_EAX, buf_stride); + x86_mov(p->func, p->tmp_EAX, buf_stride); + x64_rexw(p->func); + x86_add(p->func, p->tmp_EAX, buf_ptr); if (i == 0) sse_prefetchnta(p->func, x86_make_disp(p->tmp_EAX, 192)); + x64_rexw(p->func); x86_mov(p->func, buf_ptr, p->tmp_EAX); } } } else { - x86_lea(p->func, p->idx_EBX, x86_make_disp(p->idx_EBX, 4)); + x64_rexw(p->func); + x86_lea(p->func, p->idx_ESI, x86_make_disp(p->idx_ESI, index_size)); } return TRUE; @@ -551,35 +1250,52 @@ static boolean incr_inputs( struct translate_sse *p, */ static boolean build_vertex_emit( struct translate_sse *p, struct x86_function *func, - boolean linear ) + unsigned index_size ) { int fixup, label; unsigned j; + memset(p->reg_to_const, 0xff, sizeof(p->reg_to_const)); + memset(p->const_to_reg, 0xff, sizeof(p->const_to_reg)); + p->tmp_EAX = x86_make_reg(file_REG32, reg_AX); - p->idx_EBX = x86_make_reg(file_REG32, reg_BX); - p->outbuf_ECX = x86_make_reg(file_REG32, reg_CX); - p->machine_EDX = x86_make_reg(file_REG32, reg_DX); - p->count_ESI = x86_make_reg(file_REG32, reg_SI); + p->idx_ESI = x86_make_reg(file_REG32, reg_SI); + p->outbuf_EBX = x86_make_reg(file_REG32, reg_BX); + p->machine_EDI = x86_make_reg(file_REG32, reg_DI); + p->count_EBP = x86_make_reg(file_REG32, reg_BP); + p->tmp2_EDX = x86_make_reg(file_REG32, reg_DX); + p->src_ECX = x86_make_reg(file_REG32, reg_CX); p->func = func; - p->loaded_inv_255 = FALSE; - p->loaded_255 = FALSE; - p->loaded_identity = FALSE; x86_init_func(p->func); - /* Push a few regs? - */ - x86_push(p->func, p->idx_EBX); - x86_push(p->func, p->count_ESI); + if(x86_target(p->func) == X86_64_WIN64_ABI) + { + /* the ABI guarantees a 16-byte aligned 32-byte "shadow space" above the return address */ + sse2_movdqa(p->func, x86_make_disp(x86_make_reg(file_REG32, reg_SP), 8), x86_make_reg(file_XMM, 6)); + sse2_movdqa(p->func, x86_make_disp(x86_make_reg(file_REG32, reg_SP), 24), x86_make_reg(file_XMM, 7)); + } - /* Load arguments into regs: - */ - x86_mov(p->func, p->machine_EDX, x86_fn_arg(p->func, 1)); - x86_mov(p->func, p->idx_EBX, x86_fn_arg(p->func, 2)); - x86_mov(p->func, p->count_ESI, x86_fn_arg(p->func, 3)); - x86_mov(p->func, p->outbuf_ECX, x86_fn_arg(p->func, 5)); + x86_push(p->func, p->outbuf_EBX); + x86_push(p->func, p->count_EBP); + +/* on non-Win64 x86-64, these are already in the right registers */ + if(x86_target(p->func) != X86_64_STD_ABI) + { + x86_push(p->func, p->machine_EDI); + x86_push(p->func, p->idx_ESI); + + x86_mov(p->func, p->machine_EDI, x86_fn_arg(p->func, 1)); + x86_mov(p->func, p->idx_ESI, x86_fn_arg(p->func, 2)); + } + + x86_mov(p->func, p->count_EBP, x86_fn_arg(p->func, 3)); + + if(x86_target(p->func) != X86_32) + x64_mov64(p->func, p->outbuf_EBX, x86_fn_arg(p->func, 5)); + else + x86_mov(p->func, p->outbuf_EBX, x86_fn_arg(p->func, 5)); /* Load instance ID. */ @@ -588,25 +1304,25 @@ static boolean build_vertex_emit( struct translate_sse *p, p->tmp_EAX, x86_fn_arg(p->func, 4)); x86_mov(p->func, - x86_make_disp(p->machine_EDX, get_offset(p, &p->instance_id)), + x86_make_disp(p->machine_EDI, get_offset(p, &p->instance_id)), p->tmp_EAX); } /* Get vertex count, compare to zero */ x86_xor(p->func, p->tmp_EAX, p->tmp_EAX); - x86_cmp(p->func, p->count_ESI, p->tmp_EAX); + x86_cmp(p->func, p->count_EBP, p->tmp_EAX); fixup = x86_jcc_forward(p->func, cc_E); /* always load, needed or not: */ - init_inputs(p, linear); + init_inputs(p, index_size); /* Note address for loop jump */ label = x86_get_label(p->func); { - struct x86_reg elt = linear ? p->idx_EBX : x86_deref(p->idx_EBX); + struct x86_reg elt = !index_size ? p->idx_ESI : x86_deref(p->idx_ESI); int last_varient = -1; struct x86_reg vb; @@ -618,30 +1334,31 @@ static boolean build_vertex_emit( struct translate_sse *p, */ if (varient != last_varient) { last_varient = varient; - vb = get_buffer_ptr(p, linear, varient, elt); + vb = get_buffer_ptr(p, index_size, varient, elt); } if (!translate_attr( p, a, x86_make_disp(vb, a->input_offset), - x86_make_disp(p->outbuf_ECX, a->output_offset))) + x86_make_disp(p->outbuf_EBX, a->output_offset))) return FALSE; } /* Next output vertex: */ + x64_rexw(p->func); x86_lea(p->func, - p->outbuf_ECX, - x86_make_disp(p->outbuf_ECX, + p->outbuf_EBX, + x86_make_disp(p->outbuf_EBX, p->translate.key.output_stride)); /* Incr index */ - incr_inputs( p, linear ); + incr_inputs( p, index_size ); } /* decr count, loop if not zero */ - x86_dec(p->func, p->count_ESI); + x86_dec(p->func, p->count_EBP); x86_jcc(p->func, cc_NZ, label); /* Exit mmx state? @@ -656,8 +1373,20 @@ static boolean build_vertex_emit( struct translate_sse *p, /* Pop regs and return */ - x86_pop(p->func, p->count_ESI); - x86_pop(p->func, p->idx_EBX); + if(x86_target(p->func) != X86_64_STD_ABI) + { + x86_pop(p->func, p->idx_ESI); + x86_pop(p->func, p->machine_EDI); + } + + x86_pop(p->func, p->count_EBP); + x86_pop(p->func, p->outbuf_EBX); + + if(x86_target(p->func) == X86_64_WIN64_ABI) + { + sse2_movdqa(p->func, x86_make_reg(file_XMM, 6), x86_make_disp(x86_make_reg(file_REG32, reg_SP), 8)); + sse2_movdqa(p->func, x86_make_reg(file_XMM, 7), x86_make_disp(x86_make_reg(file_REG32, reg_SP), 24)); + } x86_ret(p->func); return TRUE; @@ -697,37 +1426,7 @@ static void translate_sse_release( struct translate *translate ) x86_release_func( &p->linear_func ); x86_release_func( &p->elt_func ); - FREE(p); -} - -static void PIPE_CDECL translate_sse_run_elts( struct translate *translate, - const unsigned *elts, - unsigned count, - unsigned instance_id, - void *output_buffer ) -{ - struct translate_sse *p = (struct translate_sse *)translate; - - p->gen_run_elts( translate, - elts, - count, - instance_id, - output_buffer); -} - -static void PIPE_CDECL translate_sse_run( struct translate *translate, - unsigned start, - unsigned count, - unsigned instance_id, - void *output_buffer ) -{ - struct translate_sse *p = (struct translate_sse *)translate; - - p->gen_run( translate, - start, - count, - instance_id, - output_buffer); + os_free_aligned(p); } @@ -736,18 +1435,19 @@ struct translate *translate_sse2_create( const struct translate_key *key ) struct translate_sse *p = NULL; unsigned i; - if (!rtasm_cpu_has_sse() || !rtasm_cpu_has_sse2()) + /* this is misnamed, it actually refers to whether rtasm is enabled or not */ + if (!rtasm_cpu_has_sse()) goto fail; - p = CALLOC_STRUCT( translate_sse ); + p = os_malloc_aligned(sizeof(struct translate_sse), 16); if (p == NULL) goto fail; + memset(p, 0, sizeof(*p)); + memcpy(p->consts, consts, sizeof(consts)); p->translate.key = *key; p->translate.release = translate_sse_release; p->translate.set_buffer = translate_sse_set_buffer; - p->translate.run_elts = translate_sse_run_elts; - p->translate.run = translate_sse_run; for (i = 0; i < key->nr_elements; i++) { if (key->element[i].type == TRANSLATE_ELEMENT_NORMAL) { @@ -783,18 +1483,32 @@ struct translate *translate_sse2_create( const struct translate_key *key ) if (0) debug_printf("nr_buffers: %d\n", p->nr_buffers); - if (!build_vertex_emit(p, &p->linear_func, TRUE)) + if (!build_vertex_emit(p, &p->linear_func, 0)) + goto fail; + + if (!build_vertex_emit(p, &p->elt_func, 4)) + goto fail; + + if (!build_vertex_emit(p, &p->elt16_func, 2)) + goto fail; + + if (!build_vertex_emit(p, &p->elt8_func, 1)) + goto fail; + + p->translate.run = (void*)x86_get_func(&p->linear_func); + if (p->translate.run == NULL) goto fail; - if (!build_vertex_emit(p, &p->elt_func, FALSE)) + p->translate.run_elts = (void*)x86_get_func(&p->elt_func); + if (p->translate.run_elts == NULL) goto fail; - p->gen_run = (run_func)x86_get_func(&p->linear_func); - if (p->gen_run == NULL) + p->translate.run_elts16 = (void*)x86_get_func(&p->elt16_func); + if (p->translate.run_elts16 == NULL) goto fail; - p->gen_run_elts = (run_elts_func)x86_get_func(&p->elt_func); - if (p->gen_run_elts == NULL) + p->translate.run_elts8 = (void*)x86_get_func(&p->elt8_func); + if (p->translate.run_elts8 == NULL) goto fail; return &p->translate; diff --git a/src/gallium/auxiliary/util/u_bitmask.h b/src/gallium/auxiliary/util/u_bitmask.h index 87f1110296..98b85ddecd 100644 --- a/src/gallium/auxiliary/util/u_bitmask.h +++ b/src/gallium/auxiliary/util/u_bitmask.h @@ -36,6 +36,9 @@ #define U_HANDLE_BITMASK_H_ +#include "pipe/p_compiler.h" + + #ifdef __cplusplus extern "C" { #endif diff --git a/src/gallium/auxiliary/util/u_blit.c b/src/gallium/auxiliary/util/u_blit.c index 97fa99ec65..dfb142b9e1 100644 --- a/src/gallium/auxiliary/util/u_blit.c +++ b/src/gallium/auxiliary/util/u_blit.c @@ -42,6 +42,7 @@ #include "util/u_blit.h" #include "util/u_draw_quad.h" +#include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" #include "util/u_sampler.h" @@ -56,15 +57,18 @@ struct blit_state struct cso_context *cso; struct pipe_blend_state blend; - struct pipe_depth_stencil_alpha_state depthstencil; + struct pipe_depth_stencil_alpha_state depthstencil_keep; + struct pipe_depth_stencil_alpha_state depthstencil_write; struct pipe_rasterizer_state rasterizer; struct pipe_sampler_state sampler; struct pipe_viewport_state viewport; struct pipe_clip_state clip; struct pipe_vertex_element velem[2]; + enum pipe_texture_target internal_target; void *vs; void *fs[TGSI_WRITEMASK_XYZW + 1]; + void *fs_depth; struct pipe_resource *vbuf; /**< quad vertices */ unsigned vbuf_slot; @@ -95,7 +99,11 @@ util_create_blit(struct pipe_context *pipe, struct cso_context *cso) ctx->blend.rt[0].colormask = PIPE_MASK_RGBA; /* no-op depth/stencil/alpha */ - memset(&ctx->depthstencil, 0, sizeof(ctx->depthstencil)); + memset(&ctx->depthstencil_keep, 0, sizeof(ctx->depthstencil_keep)); + memset(&ctx->depthstencil_write, 0, sizeof(ctx->depthstencil_write)); + ctx->depthstencil_write.depth.enabled = 1; + ctx->depthstencil_write.depth.writemask = 1; + ctx->depthstencil_write.depth.func = PIPE_FUNC_ALWAYS; /* rasterizer */ memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer)); @@ -110,7 +118,6 @@ util_create_blit(struct pipe_context *pipe, struct cso_context *cso) ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; ctx->sampler.min_img_filter = 0; /* set later */ ctx->sampler.mag_img_filter = 0; /* set later */ - ctx->sampler.normalized_coords = 1; /* vertex elements state */ memset(&ctx->velem[0], 0, sizeof(ctx->velem[0]) * 2); @@ -145,6 +152,11 @@ util_create_blit(struct pipe_context *pipe, struct cso_context *cso) ctx->vertices[i][1][3] = 1.0f; /* q */ } + if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES)) + ctx->internal_target = PIPE_TEXTURE_2D; + else + ctx->internal_target = PIPE_TEXTURE_RECT; + return ctx; } @@ -164,6 +176,9 @@ util_destroy_blit(struct blit_state *ctx) if (ctx->fs[i]) pipe->delete_fs_state(pipe, ctx->fs[i]); + if (ctx->fs_depth) + pipe->delete_fs_state(pipe, ctx->fs_depth); + pipe_resource_reference(&ctx->vbuf, NULL); FREE(ctx); @@ -271,7 +286,7 @@ regions_overlap(int srcX0, int srcY0, * \param writemask controls which channels in the dest surface are sourced * from the src surface. Disabled channels are sourced * from (0,0,0,1). - * XXX need some control over blitting Z and/or stencil. + * XXX need some control over blitting stencil. */ void util_blit_pixels_writemask(struct blit_state *ctx, @@ -294,8 +309,9 @@ util_blit_pixels_writemask(struct blit_state *ctx, const int srcW = abs(srcX1 - srcX0); const int srcH = abs(srcY1 - srcY0); unsigned offset; - boolean overlap; + boolean overlap, dst_is_depth; float s0, t0, s1, t1; + boolean normalized; assert(filter == PIPE_TEX_MIPFILTER_NEAREST || filter == PIPE_TEX_MIPFILTER_LINEAR); @@ -335,7 +351,6 @@ util_blit_pixels_writemask(struct blit_state *ctx, return; } - /* Create a temporary texture when src and dest alias or when src * is anything other than a 2d texture. * XXX should just use appropriate shader to access 1d / 3d slice / cube face, @@ -347,7 +362,8 @@ util_blit_pixels_writemask(struct blit_state *ctx, dst->face == srcsub.face && dst->level == srcsub.level && dst->zslice == srcZ0) || - src_tex->target != PIPE_TEXTURE_2D) + (src_tex->target != PIPE_TEXTURE_2D && + src_tex->target != PIPE_TEXTURE_RECT)) { struct pipe_resource texTemp; struct pipe_resource *tex; @@ -372,7 +388,7 @@ util_blit_pixels_writemask(struct blit_state *ctx, /* create temp texture */ memset(&texTemp, 0, sizeof(texTemp)); - texTemp.target = PIPE_TEXTURE_2D; + texTemp.target = ctx->internal_target; texTemp.format = src_tex->format; texTemp.last_level = 0; texTemp.width0 = srcW; @@ -392,10 +408,19 @@ util_blit_pixels_writemask(struct blit_state *ctx, src_tex, srcsub, srcLeft, srcTop, srcZ0, /* src */ srcW, srcH); /* size */ - s0 = 0.0f; - s1 = 1.0f; - t0 = 0.0f; - t1 = 1.0f; + normalized = tex->target != PIPE_TEXTURE_RECT; + if(normalized) { + s0 = 0.0f; + s1 = 1.0f; + t0 = 0.0f; + t1 = 1.0f; + } + else { + s0 = 0; + s1 = srcW; + t0 = 0; + t1 = srcH; + } u_sampler_view_default_template(&sv_templ, tex, tex->format); sampler_view = pipe->create_sampler_view(pipe, tex, &sv_templ); @@ -415,20 +440,29 @@ util_blit_pixels_writemask(struct blit_state *ctx, return; } - s0 = srcX0 / (float)(u_minify(sampler_view->texture->width0, srcsub.level)); - s1 = srcX1 / (float)(u_minify(sampler_view->texture->width0, srcsub.level)); - t0 = srcY0 / (float)(u_minify(sampler_view->texture->height0, srcsub.level)); - t1 = srcY1 / (float)(u_minify(sampler_view->texture->height0, srcsub.level)); + s0 = srcX0; + s1 = srcX1; + t0 = srcY0; + t1 = srcY1; + normalized = sampler_view->texture->target != PIPE_TEXTURE_RECT; + if(normalized) + { + s0 /= (float)(u_minify(sampler_view->texture->width0, srcsub.level)); + s1 /= (float)(u_minify(sampler_view->texture->width0, srcsub.level)); + t0 /= (float)(u_minify(sampler_view->texture->height0, srcsub.level)); + t1 /= (float)(u_minify(sampler_view->texture->height0, srcsub.level)); + } } + dst_is_depth = util_format_is_depth_or_stencil(dst->format); - assert(screen->is_format_supported(screen, sampler_view->format, PIPE_TEXTURE_2D, + assert(screen->is_format_supported(screen, sampler_view->format, ctx->internal_target, sampler_view->texture->nr_samples, PIPE_BIND_SAMPLER_VIEW, 0)); - assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D, + assert(screen->is_format_supported(screen, dst->format, ctx->internal_target, dst->texture->nr_samples, - PIPE_BIND_RENDER_TARGET, 0)); - + dst_is_depth ? PIPE_BIND_DEPTH_STENCIL : + PIPE_BIND_RENDER_TARGET, 0)); /* save state (restored below) */ cso_save_blend(ctx->cso); cso_save_depth_stencil_alpha(ctx->cso); @@ -444,12 +478,15 @@ util_blit_pixels_writemask(struct blit_state *ctx, /* set misc state we care about */ cso_set_blend(ctx->cso, &ctx->blend); - cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil); + cso_set_depth_stencil_alpha(ctx->cso, + dst_is_depth ? &ctx->depthstencil_write : + &ctx->depthstencil_keep); cso_set_rasterizer(ctx->cso, &ctx->rasterizer); cso_set_clip(ctx->cso, &ctx->clip); cso_set_vertex_elements(ctx->cso, 2, ctx->velem); /* sampler */ + ctx->sampler.normalized_coords = normalized; ctx->sampler.min_img_filter = filter; ctx->sampler.mag_img_filter = filter; /* we've limited this already with the sampler view but you never know... */ @@ -472,22 +509,35 @@ util_blit_pixels_writemask(struct blit_state *ctx, /* texture */ cso_set_fragment_sampler_views(ctx->cso, 1, &sampler_view); - if (ctx->fs[writemask] == NULL) - ctx->fs[writemask] = - util_make_fragment_tex_shader_writemask(pipe, TGSI_TEXTURE_2D, - TGSI_INTERPOLATE_LINEAR, - writemask); - /* shaders */ - cso_set_fragment_shader_handle(ctx->cso, ctx->fs[writemask]); + if (dst_is_depth) { + if (ctx->fs_depth == NULL) + ctx->fs_depth = + util_make_fragment_tex_shader_writedepth(pipe, TGSI_TEXTURE_2D, + TGSI_INTERPOLATE_LINEAR); + + cso_set_fragment_shader_handle(ctx->cso, ctx->fs_depth); + } else { + if (ctx->fs[writemask] == NULL) + ctx->fs[writemask] = + util_make_fragment_tex_shader_writemask(pipe, TGSI_TEXTURE_2D, + TGSI_INTERPOLATE_LINEAR, + writemask); + + cso_set_fragment_shader_handle(ctx->cso, ctx->fs[writemask]); + } cso_set_vertex_shader_handle(ctx->cso, ctx->vs); /* drawing dest */ memset(&fb, 0, sizeof(fb)); fb.width = dst->width; fb.height = dst->height; - fb.nr_cbufs = 1; - fb.cbufs[0] = dst; + if (dst_is_depth) { + fb.zsbuf = dst; + } else { + fb.nr_cbufs = 1; + fb.cbufs[0] = dst; + } cso_set_framebuffer(ctx->cso, &fb); /* draw quad */ @@ -574,6 +624,7 @@ util_blit_pixels_tex(struct blit_state *ctx, int dstX1, int dstY1, float z, uint filter) { + boolean normalized = src_sampler_view->texture->target != PIPE_TEXTURE_RECT; struct pipe_framebuffer_state fb; float s0, t0, s1, t1; unsigned offset; @@ -586,10 +637,18 @@ util_blit_pixels_tex(struct blit_state *ctx, assert(tex->width0 != 0); assert(tex->height0 != 0); - s0 = srcX0 / (float)tex->width0; - s1 = srcX1 / (float)tex->width0; - t0 = srcY0 / (float)tex->height0; - t1 = srcY1 / (float)tex->height0; + s0 = srcX0; + s1 = srcX1; + t0 = srcY0; + t1 = srcY1; + + if(normalized) + { + s0 /= (float)tex->width0; + s1 /= (float)tex->width0; + t0 /= (float)tex->height0; + t1 /= (float)tex->height0; + } assert(ctx->pipe->screen->is_format_supported(ctx->pipe->screen, dst->format, PIPE_TEXTURE_2D, @@ -611,12 +670,13 @@ util_blit_pixels_tex(struct blit_state *ctx, /* set misc state we care about */ cso_set_blend(ctx->cso, &ctx->blend); - cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil); + cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil_keep); cso_set_rasterizer(ctx->cso, &ctx->rasterizer); cso_set_clip(ctx->cso, &ctx->clip); cso_set_vertex_elements(ctx->cso, 2, ctx->velem); /* sampler */ + ctx->sampler.normalized_coords = normalized; ctx->sampler.min_img_filter = filter; ctx->sampler.mag_img_filter = filter; cso_single_sampler(ctx->cso, 0, &ctx->sampler); diff --git a/src/gallium/auxiliary/util/u_blit.h b/src/gallium/auxiliary/util/u_blit.h index ef95134f32..b8a0dfce13 100644 --- a/src/gallium/auxiliary/util/u_blit.h +++ b/src/gallium/auxiliary/util/u_blit.h @@ -30,18 +30,20 @@ #define U_BLIT_H +#include "pipe/p_compiler.h" + + #ifdef __cplusplus extern "C" { #endif +struct cso_context; struct pipe_context; -struct pipe_surface; struct pipe_resource; -struct cso_context; - - -struct blit_state; +struct pipe_sampler_view; +struct pipe_subresource; +struct pipe_surface; extern struct blit_state * diff --git a/src/gallium/auxiliary/util/u_blitter.c b/src/gallium/auxiliary/util/u_blitter.c index b5b86b7214..f93ef26ae7 100644 --- a/src/gallium/auxiliary/util/u_blitter.c +++ b/src/gallium/auxiliary/util/u_blitter.c @@ -92,7 +92,7 @@ struct blitter_context_priv void *velem_state; /* Sampler state for clamping to a miplevel. */ - void *sampler_state[PIPE_MAX_TEXTURE_LEVELS]; + void *sampler_state[PIPE_MAX_TEXTURE_LEVELS * 2]; /* Rasterizer state. */ void *rs_state; @@ -254,6 +254,7 @@ void util_blitter_destroy(struct blitter_context *blitter) ctx->dsa_write_depth_keep_stencil); pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_write_depth_stencil); pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_write_stencil); + pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_flush_depth_stencil); pipe->delete_rasterizer_state(pipe, ctx->rs_state); pipe->delete_vs_state(pipe, ctx->vs_col); @@ -271,7 +272,7 @@ void util_blitter_destroy(struct blitter_context *blitter) if (ctx->fs_col[i]) pipe->delete_fs_state(pipe, ctx->fs_col[i]); - for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++) + for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS * 2; i++) if (ctx->sampler_state[i]) pipe->delete_sampler_state(pipe, ctx->sampler_state[i]); @@ -319,7 +320,7 @@ static void blitter_restore_CSOs(struct blitter_context_priv *ctx) */ if (ctx->base.saved_fb_state.nr_cbufs != ~0) { pipe->set_framebuffer_state(pipe, &ctx->base.saved_fb_state); - util_assign_framebuffer_state(&ctx->base.saved_fb_state, NULL); + util_unreference_framebuffer_state(&ctx->base.saved_fb_state); ctx->base.saved_fb_state.nr_cbufs = ~0; } @@ -417,16 +418,26 @@ static void blitter_set_clear_color(struct blitter_context_priv *ctx, } } -static void get_normalized_texcoords(struct pipe_resource *src, +static void get_texcoords(struct pipe_resource *src, struct pipe_subresource subsrc, unsigned x1, unsigned y1, unsigned x2, unsigned y2, - float out[4]) + boolean normalized, float out[4]) { - out[0] = x1 / (float)u_minify(src->width0, subsrc.level); - out[1] = y1 / (float)u_minify(src->height0, subsrc.level); - out[2] = x2 / (float)u_minify(src->width0, subsrc.level); - out[3] = y2 / (float)u_minify(src->height0, subsrc.level); + if(normalized) + { + out[0] = x1 / (float)u_minify(src->width0, subsrc.level); + out[1] = y1 / (float)u_minify(src->height0, subsrc.level); + out[2] = x2 / (float)u_minify(src->width0, subsrc.level); + out[3] = y2 / (float)u_minify(src->height0, subsrc.level); + } + else + { + out[0] = x1; + out[1] = y1; + out[2] = x2; + out[3] = y2; + } } static void set_texcoords_in_vertices(const float coord[4], @@ -454,7 +465,7 @@ static void blitter_set_texcoords_2d(struct blitter_context_priv *ctx, unsigned i; float coord[4]; - get_normalized_texcoords(src, subsrc, x1, y1, x2, y2, coord); + get_texcoords(src, subsrc, x1, y1, x2, y2, TRUE, coord); set_texcoords_in_vertices(coord, &ctx->vertices[0][1][0], 8); for (i = 0; i < 4; i++) { @@ -489,7 +500,7 @@ static void blitter_set_texcoords_cube(struct blitter_context_priv *ctx, float coord[4]; float st[4][2]; - get_normalized_texcoords(src, subsrc, x1, y1, x2, y2, coord); + get_texcoords(src, subsrc, x1, y1, x2, y2, TRUE, coord); set_texcoords_in_vertices(coord, &st[0][0], 2); util_map_texcoords2d_onto_cubemap(subsrc.face, @@ -523,7 +534,7 @@ static void blitter_draw_quad(struct blitter_context_priv *ctx) static INLINE void **blitter_get_sampler_state(struct blitter_context_priv *ctx, - int miplevel) + int miplevel, boolean normalized) { struct pipe_context *pipe = ctx->base.pipe; struct pipe_sampler_state *sampler_state = &ctx->template_sampler_state; @@ -531,18 +542,19 @@ void **blitter_get_sampler_state(struct blitter_context_priv *ctx, assert(miplevel < PIPE_MAX_TEXTURE_LEVELS); /* Create the sampler state on-demand. */ - if (!ctx->sampler_state[miplevel]) { + if (!ctx->sampler_state[miplevel * 2 + normalized]) { sampler_state->lod_bias = miplevel; sampler_state->min_lod = miplevel; sampler_state->max_lod = miplevel; + sampler_state->normalized_coords = normalized; - ctx->sampler_state[miplevel] = pipe->create_sampler_state(pipe, + ctx->sampler_state[miplevel * 2 + normalized] = pipe->create_sampler_state(pipe, sampler_state); } /* Return void** so that it can be passed to bind_fragment_sampler_states * directly. */ - return &ctx->sampler_state[miplevel]; + return &ctx->sampler_state[miplevel * 2 + normalized]; } static INLINE @@ -568,6 +580,8 @@ pipe_tex_to_tgsi_tex(enum pipe_texture_target pipe_tex_target) return TGSI_TEXTURE_1D; case PIPE_TEXTURE_2D: return TGSI_TEXTURE_2D; + case PIPE_TEXTURE_RECT: + return TGSI_TEXTURE_RECT; case PIPE_TEXTURE_3D: return TGSI_TEXTURE_3D; case PIPE_TEXTURE_CUBE: @@ -716,6 +730,7 @@ void util_blitter_copy_region(struct blitter_context *blitter, struct pipe_sampler_view viewTempl, *view; unsigned bind; boolean is_stencil, is_depth; + boolean normalized; /* Give up if textures are not set. */ assert(dst && src); @@ -787,6 +802,8 @@ void util_blitter_copy_region(struct blitter_context *blitter, fb_state.zsbuf = 0; } + normalized = src->target != PIPE_TEXTURE_RECT; + /* Initialize sampler view. */ u_sampler_view_default_template(&viewTempl, src, src->format); view = pipe->create_sampler_view(pipe, src, &viewTempl); @@ -795,7 +812,7 @@ void util_blitter_copy_region(struct blitter_context *blitter, pipe->bind_rasterizer_state(pipe, ctx->rs_state); pipe->bind_vs_state(pipe, ctx->vs_tex); pipe->bind_fragment_sampler_states(pipe, 1, - blitter_get_sampler_state(ctx, subsrc.level)); + blitter_get_sampler_state(ctx, subsrc.level, normalized)); pipe->bind_vertex_elements_state(pipe, ctx->velem_state); pipe->set_fragment_sampler_views(pipe, 1, &view); pipe->set_framebuffer_state(pipe, &fb_state); @@ -806,11 +823,12 @@ void util_blitter_copy_region(struct blitter_context *blitter, /* Draw the quad with the draw_rectangle callback. */ case PIPE_TEXTURE_1D: case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: { /* Set texture coordinates. */ float coord[4]; - get_normalized_texcoords(src, subsrc, srcx, srcy, - srcx+width, srcy+height, coord); + get_texcoords(src, subsrc, srcx, srcy, + srcx+width, srcy+height, normalized, coord); /* Draw. */ blitter->draw_rectangle(blitter, dstx, dsty, dstx+width, dsty+height, 0, diff --git a/src/gallium/auxiliary/util/u_blitter.h b/src/gallium/auxiliary/util/u_blitter.h index f316587dea..e33d2e283f 100644 --- a/src/gallium/auxiliary/util/u_blitter.h +++ b/src/gallium/auxiliary/util/u_blitter.h @@ -27,6 +27,7 @@ #ifndef U_BLITTER_H #define U_BLITTER_H +#include "util/u_framebuffer.h" #include "util/u_inlines.h" #include "util/u_memory.h" @@ -258,45 +259,12 @@ void util_blitter_save_vertex_shader(struct blitter_context *blitter, blitter->saved_vs = vs; } -/* XXX This should probably be moved elsewhere. */ -static INLINE -void util_assign_framebuffer_state(struct pipe_framebuffer_state *dst, - const struct pipe_framebuffer_state *src) -{ - unsigned i; - - if (src) { - /* Reference all surfaces. */ - for (i = 0; i < src->nr_cbufs; i++) { - pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]); - } - for (; i < dst->nr_cbufs; i++) { - pipe_surface_reference(&dst->cbufs[i], NULL); - } - - pipe_surface_reference(&dst->zsbuf, src->zsbuf); - - dst->nr_cbufs = src->nr_cbufs; - dst->width = src->width; - dst->height = src->height; - } else { - /* Set all surfaces to NULL. */ - for (i = 0; i < dst->nr_cbufs; i++) { - pipe_surface_reference(&dst->cbufs[i], NULL); - } - - pipe_surface_reference(&dst->zsbuf, NULL); - - dst->nr_cbufs = 0; - } -} - static INLINE void util_blitter_save_framebuffer(struct blitter_context *blitter, const struct pipe_framebuffer_state *state) { blitter->saved_fb_state.nr_cbufs = 0; /* It's ~0 now, meaning it's unsaved. */ - util_assign_framebuffer_state(&blitter->saved_fb_state, state); + util_copy_framebuffer_state(&blitter->saved_fb_state, state); } static INLINE diff --git a/src/gallium/auxiliary/util/u_cpu_detect.c b/src/gallium/auxiliary/util/u_cpu_detect.c index 5056351307..32519b148b 100644 --- a/src/gallium/auxiliary/util/u_cpu_detect.c +++ b/src/gallium/auxiliary/util/u_cpu_detect.c @@ -73,7 +73,9 @@ #endif +#ifdef DEBUG DEBUG_GET_ONCE_BOOL_OPTION(dump_cpu, "GALLIUM_DUMP_CPU", FALSE) +#endif struct util_cpu_caps util_cpu_caps; @@ -83,61 +85,6 @@ static int has_cpuid(void); #endif -#if defined(PIPE_ARCH_X86) - -/* The sigill handlers */ -#if defined(PIPE_OS_LINUX) /*&& defined(_POSIX_SOURCE) && defined(X86_FXSR_MAGIC)*/ -static void -sigill_handler_sse(int signal, struct sigcontext sc) -{ - /* Both the "xorps %%xmm0,%%xmm0" and "divps %xmm0,%%xmm1" - * instructions are 3 bytes long. We must increment the instruction - * pointer manually to avoid repeated execution of the offending - * instruction. - * - * If the SIGILL is caused by a divide-by-zero when unmasked - * exceptions aren't supported, the SIMD FPU status and control - * word will be restored at the end of the test, so we don't need - * to worry about doing it here. Besides, we may not be able to... - */ - sc.eip += 3; - - util_cpu_caps.has_sse=0; -} - -static void -sigfpe_handler_sse(int signal, struct sigcontext sc) -{ - if (sc.fpstate->magic != 0xffff) { - /* Our signal context has the extended FPU state, so reset the - * divide-by-zero exception mask and clear the divide-by-zero - * exception bit. - */ - sc.fpstate->mxcsr |= 0x00000200; - sc.fpstate->mxcsr &= 0xfffffffb; - } else { - /* If we ever get here, we're completely hosed. - */ - } -} -#endif /* PIPE_OS_LINUX && _POSIX_SOURCE && X86_FXSR_MAGIC */ - -#if defined(PIPE_OS_WINDOWS) -static LONG CALLBACK -win32_sig_handler_sse(EXCEPTION_POINTERS* ep) -{ - if(ep->ExceptionRecord->ExceptionCode==EXCEPTION_ILLEGAL_INSTRUCTION){ - ep->ContextRecord->Eip +=3; - util_cpu_caps.has_sse=0; - return EXCEPTION_CONTINUE_EXECUTION; - } - return EXCEPTION_CONTINUE_SEARCH; -} -#endif /* PIPE_OS_WINDOWS */ - -#endif /* PIPE_ARCH_X86 */ - - #if defined(PIPE_ARCH_PPC) && !defined(PIPE_OS_APPLE) static jmp_buf __lv_powerpc_jmpbuf; static volatile sig_atomic_t __lv_powerpc_canjump = 0; @@ -194,123 +141,8 @@ check_os_altivec_support(void) } #endif /* PIPE_ARCH_PPC */ -/* If we're running on a processor that can do SSE, let's see if we - * are allowed to or not. This will catch 2.4.0 or later kernels that - * haven't been configured for a Pentium III but are running on one, - * and RedHat patched 2.2 kernels that have broken exception handling - * support for user space apps that do SSE. - */ -#if defined(PIPE_ARCH_X86) || defined (PIPE_ARCH_X86_64) -static void -check_os_katmai_support(void) -{ -#if defined(PIPE_ARCH_X86) -#if defined(PIPE_OS_FREEBSD) - int has_sse=0, ret; - int len = sizeof (has_sse); - - ret = sysctlbyname("hw.instruction_sse", &has_sse, &len, NULL, 0); - if (ret || !has_sse) - util_cpu_caps.has_sse=0; - -#elif defined(PIPE_OS_NETBSD) || defined(PIPE_OS_OPENBSD) - int has_sse, has_sse2, ret, mib[2]; - int varlen; - - mib[0] = CTL_MACHDEP; - mib[1] = CPU_SSE; - varlen = sizeof (has_sse); - - ret = sysctl(mib, 2, &has_sse, &varlen, NULL, 0); - if (ret < 0 || !has_sse) { - util_cpu_caps.has_sse = 0; - } else { - util_cpu_caps.has_sse = 1; - } - - mib[1] = CPU_SSE2; - varlen = sizeof (has_sse2); - ret = sysctl(mib, 2, &has_sse2, &varlen, NULL, 0); - if (ret < 0 || !has_sse2) { - util_cpu_caps.has_sse2 = 0; - } else { - util_cpu_caps.has_sse2 = 1; - } - util_cpu_caps.has_sse = 0; /* FIXME ?!?!? */ - -#elif defined(PIPE_OS_WINDOWS) - LPTOP_LEVEL_EXCEPTION_FILTER exc_fil; - if (util_cpu_caps.has_sse) { - exc_fil = SetUnhandledExceptionFilter(win32_sig_handler_sse); -#if defined(PIPE_CC_GCC) - __asm __volatile ("xorps %xmm0, %xmm0"); -#elif defined(PIPE_CC_MSVC) - __asm { - xorps xmm0, xmm0 /* executing SSE instruction */ - } -#else -#error Unsupported compiler -#endif - SetUnhandledExceptionFilter(exc_fil); - } -#elif defined(PIPE_OS_LINUX) - struct sigaction saved_sigill; - struct sigaction saved_sigfpe; - - /* Save the original signal handlers. - */ - sigaction(SIGILL, NULL, &saved_sigill); - sigaction(SIGFPE, NULL, &saved_sigfpe); - - signal(SIGILL, (void (*)(int))sigill_handler_sse); - signal(SIGFPE, (void (*)(int))sigfpe_handler_sse); - - /* Emulate test for OSFXSR in CR4. The OS will set this bit if it - * supports the extended FPU save and restore required for SSE. If - * we execute an SSE instruction on a PIII and get a SIGILL, the OS - * doesn't support Streaming SIMD Exceptions, even if the processor - * does. - */ - if (util_cpu_caps.has_sse) { - __asm __volatile ("xorps %xmm1, %xmm0"); - } - - /* Emulate test for OSXMMEXCPT in CR4. The OS will set this bit if - * it supports unmasked SIMD FPU exceptions. If we unmask the - * exceptions, do a SIMD divide-by-zero and get a SIGILL, the OS - * doesn't support unmasked SIMD FPU exceptions. If we get a SIGFPE - * as expected, we're okay but we need to clean up after it. - * - * Are we being too stringent in our requirement that the OS support - * unmasked exceptions? Certain RedHat 2.2 kernels enable SSE by - * setting CR4.OSFXSR but don't support unmasked exceptions. Win98 - * doesn't even support them. We at least know the user-space SSE - * support is good in kernels that do support unmasked exceptions, - * and therefore to be safe I'm going to leave this test in here. - */ - if (util_cpu_caps.has_sse) { - /* test_os_katmai_exception_support(); */ - } - - /* Restore the original signal handlers. - */ - sigaction(SIGILL, &saved_sigill, NULL); - sigaction(SIGFPE, &saved_sigfpe, NULL); - -#else - /* We can't use POSIX signal handling to test the availability of - * SSE, so we disable it by default. - */ - util_cpu_caps.has_sse = 0; -#endif /* __linux__ */ -#endif - -#if defined(PIPE_ARCH_X86_64) - util_cpu_caps.has_sse = 1; -#endif -} - +#if defined(PIPE_ARCH_X86) || defined (PIPE_ARCH_X86_64) static int has_cpuid(void) { #if defined(PIPE_ARCH_X86) @@ -469,9 +301,6 @@ util_cpu_detect(void) util_cpu_caps.cacheline = regs2[2] & 0xFF; } - if (util_cpu_caps.has_sse) - check_os_katmai_support(); - if (!util_cpu_caps.has_sse) { util_cpu_caps.has_sse2 = 0; util_cpu_caps.has_sse3 = 0; diff --git a/src/gallium/auxiliary/util/u_debug_describe.c b/src/gallium/auxiliary/util/u_debug_describe.c new file mode 100644 index 0000000000..1c90ff3106 --- /dev/null +++ b/src/gallium/auxiliary/util/u_debug_describe.c @@ -0,0 +1,81 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <pipe/p_state.h> +#include <util/u_format.h> +#include <util/u_debug_describe.h> +#include <util/u_string.h> + +void +debug_describe_reference(char* buf, const struct pipe_reference*ptr) +{ + strcpy(buf, "pipe_object"); +} + +void +debug_describe_resource(char* buf, const struct pipe_resource *ptr) +{ + switch(ptr->target) + { + case PIPE_BUFFER: + util_sprintf(buf, "pipe_buffer<%u>", (unsigned)util_format_get_stride(ptr->format, ptr->width0)); + break; + case PIPE_TEXTURE_1D: + util_sprintf(buf, "pipe_texture1d<%u,%s,%u>", ptr->width0, util_format_short_name(ptr->format), ptr->last_level); + break; + case PIPE_TEXTURE_2D: + util_sprintf(buf, "pipe_texture2d<%u,%u,%s,%u>", ptr->width0, ptr->height0, util_format_short_name(ptr->format), ptr->last_level); + break; + case PIPE_TEXTURE_RECT: + util_sprintf(buf, "pipe_texture_rect<%u,%u,%s>", ptr->width0, ptr->height0, util_format_short_name(ptr->format)); + break; + case PIPE_TEXTURE_CUBE: + util_sprintf(buf, "pipe_texture_cube<%u,%u,%s,%u>", ptr->width0, ptr->height0, util_format_short_name(ptr->format), ptr->last_level); + break; + case PIPE_TEXTURE_3D: + util_sprintf(buf, "pipe_texture3d<%u,%u,%u,%s,%u>", ptr->width0, ptr->height0, ptr->depth0, util_format_short_name(ptr->format), ptr->last_level); + break; + default: + util_sprintf(buf, "pipe_martian_resource<%u>", ptr->target); + break; + } +} + +void +debug_describe_surface(char* buf, const struct pipe_surface *ptr) +{ + char res[128]; + debug_describe_resource(res, ptr->texture); + util_sprintf(buf, "pipe_surface<%s,%u,%u,%u>", res, ptr->face, ptr->level, ptr->zslice); +} + +void +debug_describe_sampler_view(char* buf, const struct pipe_sampler_view *ptr) +{ + char res[128]; + debug_describe_resource(res, ptr->texture); + util_sprintf(buf, "pipe_sampler_view<%s,%s>", res, util_format_short_name(ptr->format)); +} diff --git a/src/gallium/auxiliary/util/u_debug_describe.h b/src/gallium/auxiliary/util/u_debug_describe.h new file mode 100644 index 0000000000..26d1f803bf --- /dev/null +++ b/src/gallium/auxiliary/util/u_debug_describe.h @@ -0,0 +1,49 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef U_DEBUG_DESCRIBE_H_ +#define U_DEBUG_DESCRIBE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct pipe_reference; +struct pipe_resource; +struct pipe_surface; +struct pipe_sampler_view; + +/* a 256-byte buffer is necessary and sufficient */ +void debug_describe_reference(char* buf, const struct pipe_reference*ptr); +void debug_describe_resource(char* buf, const struct pipe_resource *ptr); +void debug_describe_surface(char* buf, const struct pipe_surface *ptr); +void debug_describe_sampler_view(char* buf, const struct pipe_sampler_view *ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* U_DEBUG_DESCRIBE_H_ */ diff --git a/src/gallium/auxiliary/util/u_debug_refcnt.c b/src/gallium/auxiliary/util/u_debug_refcnt.c new file mode 100644 index 0000000000..40a26c9c69 --- /dev/null +++ b/src/gallium/auxiliary/util/u_debug_refcnt.c @@ -0,0 +1,181 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#if defined(DEBUG) && (!defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_WINDOWS_USER)) + +/* see http://www.mozilla.org/performance/refcnt-balancer.html for what do with the output + * on Linux, use tools/addr2line.sh to postprocess it before anything else + **/ +#include <util/u_debug.h> +#include <util/u_debug_refcnt.h> +#include <util/u_debug_stack.h> +#include <util/u_debug_symbol.h> +#include <util/u_string.h> +#include <util/u_hash_table.h> +#include <os/os_thread.h> +#include <os/os_stream.h> + +int debug_refcnt_state; + +struct os_stream* stream; + +/* TODO: maybe move this serial machinery to a stand-alone module and expose it? */ +static pipe_mutex serials_mutex; +static struct util_hash_table* serials_hash; +static unsigned serials_last; + +static unsigned hash_ptr(void* p) +{ + return (unsigned)(uintptr_t)p; +} + +static int compare_ptr(void* a, void* b) +{ + if(a == b) + return 0; + else if(a < b) + return -1; + else + return 1; +} + +static boolean debug_serial(void* p, unsigned* pserial) +{ + unsigned serial; + boolean found = TRUE; + pipe_mutex_lock(serials_mutex); + if(!serials_hash) + serials_hash = util_hash_table_create(hash_ptr, compare_ptr); + serial = (unsigned)(uintptr_t)util_hash_table_get(serials_hash, p); + if(!serial) + { + /* time to stop logging... (you'll have a 100 GB logfile at least at this point) + * TODO: avoid this + */ + serial = ++serials_last; + if(!serial) + { + debug_error("More than 2^32 objects detected, aborting.\n"); + os_abort(); + } + + util_hash_table_set(serials_hash, p, (void*)(uintptr_t)serial); + found = FALSE; + } + pipe_mutex_unlock(serials_mutex); + *pserial = serial; + return found; +} + +static void debug_serial_delete(void* p) +{ + pipe_mutex_lock(serials_mutex); + util_hash_table_remove(serials_hash, p); + pipe_mutex_unlock(serials_mutex); +} + +#define STACK_LEN 64 + +static void dump_stack(const char* symbols[STACK_LEN]) +{ + unsigned i; + for(i = 0; i < STACK_LEN; ++i) + { + if(symbols[i]) + os_stream_printf(stream, "%s\n", symbols[i]); + } + os_stream_write(stream, "\n", 1); +} + +void debug_reference_slowpath(const struct pipe_reference* p, debug_reference_descriptor get_desc, int change) +{ + if(debug_refcnt_state < 0) + return; + + if(!debug_refcnt_state) + { + const char* filename = debug_get_option("GALLIUM_REFCNT_LOG", NULL); + if(filename && filename[0]) + stream = os_file_stream_create(filename); + + if(stream) + debug_refcnt_state = 1; + else + debug_refcnt_state = -1; + } + + if(debug_refcnt_state > 0) + { + struct debug_stack_frame frames[STACK_LEN]; + const char* symbols[STACK_LEN]; + char buf[1024]; + + unsigned i; + unsigned refcnt = p->count; + unsigned serial; + boolean existing = debug_serial((void*)p, &serial); + + debug_backtrace_capture(frames, 1, STACK_LEN); + for(i = 0; i < STACK_LEN; ++i) + { + if(frames[i].function) + symbols[i] = debug_symbol_name_cached(frames[i].function); + else + symbols[i] = 0; + } + + get_desc(buf, p); + + if(!existing) + { + os_stream_printf(stream, "<%s> %p %u Create\n", buf, p, serial); + dump_stack(symbols); + + /* this is there to provide a gradual change even if we don't see the initialization */ + for(i = 1; i <= refcnt - change; ++i) + { + os_stream_printf(stream, "<%s> %p %u AddRef %u\n", buf, p, serial, i); + dump_stack(symbols); + } + } + + if(change) + { + os_stream_printf(stream, "<%s> %p %u %s %u\n", buf, p, serial, change > 0 ? "AddRef" : "Release", refcnt); + dump_stack(symbols); + } + + if(!refcnt) + { + debug_serial_delete((void*)p); + os_stream_printf(stream, "<%s> %p %u Destroy\n", buf, p, serial); + dump_stack(symbols); + } + + os_stream_flush(stream); + } +} +#endif diff --git a/src/gallium/auxiliary/util/u_debug_refcnt.h b/src/gallium/auxiliary/util/u_debug_refcnt.h new file mode 100644 index 0000000000..bea2d1c478 --- /dev/null +++ b/src/gallium/auxiliary/util/u_debug_refcnt.h @@ -0,0 +1,63 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef U_DEBUG_REFCNT_H_ +#define U_DEBUG_REFCNT_H_ + +#include <pipe/p_config.h> +#include <pipe/p_state.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*debug_reference_descriptor)(char*, const struct pipe_reference*); + +#if defined(DEBUG) && (!defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_WINDOWS_USER)) + +extern int debug_refcnt_state; + +void debug_reference_slowpath(const struct pipe_reference* p, debug_reference_descriptor get_desc, int change); + +static INLINE void debug_reference(const struct pipe_reference* p, debug_reference_descriptor get_desc, int change) +{ + if (debug_refcnt_state >= 0) + debug_reference_slowpath(p, get_desc, change); +} + +#else + +static INLINE void debug_reference(const struct pipe_reference* p, debug_reference_descriptor get_desc, int change) +{ +} + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* U_DEBUG_REFCNT_H_ */ diff --git a/src/gallium/auxiliary/util/u_debug_symbol.c b/src/gallium/auxiliary/util/u_debug_symbol.c index 6e250575d6..332952af88 100644 --- a/src/gallium/auxiliary/util/u_debug_symbol.c +++ b/src/gallium/auxiliary/util/u_debug_symbol.c @@ -33,9 +33,12 @@ */ #include "pipe/p_compiler.h" +#include "os/os_thread.h" +#include "u_string.h" #include "u_debug.h" #include "u_debug_symbol.h" +#include "u_hash_table.h" #if defined(PIPE_SUBSYSTEM_WINDOWS_USER) && defined(PIPE_ARCH_X86) @@ -113,8 +116,8 @@ BOOL WINAPI j_SymGetSymFromAddr(HANDLE hProcess, DWORD Address, PDWORD Displacem } -static INLINE boolean -debug_symbol_print_imagehlp(const void *addr) +static INLINE void +debug_symbol_name_imagehlp(const void *addr, char* buf, unsigned size) { HANDLE hProcess; BYTE symbolBuffer[1024]; @@ -131,25 +134,95 @@ debug_symbol_print_imagehlp(const void *addr) if(j_SymInitialize(hProcess, NULL, TRUE)) bSymInitialized = TRUE; } - + if(!j_SymGetSymFromAddr(hProcess, (DWORD)addr, &dwDisplacement, pSymbol)) - return FALSE; + buf[0] = 0; + else + { + strncpy(buf, pSymbol->Name, size); + buf[size - 1] = 0; + } +} +#endif - debug_printf("\t%s\n", pSymbol->Name); +#ifdef __GLIBC__ +#include <execinfo.h> - return TRUE; - +/* This can only provide dynamic symbols, or binary offsets into a file. + * + * To fix this, post-process the output with tools/addr2line.sh + */ +static INLINE void +debug_symbol_name_glibc(const void *addr, char* buf, unsigned size) +{ + char** syms = backtrace_symbols((void**)&addr, 1); + strncpy(buf, syms[0], size); + buf[size - 1] = 0; + free(syms); } #endif - void -debug_symbol_print(const void *addr) +debug_symbol_name(const void *addr, char* buf, unsigned size) { #if defined(PIPE_SUBSYSTEM_WINDOWS_USER) && defined(PIPE_ARCH_X86) - if(debug_symbol_print_imagehlp(addr)) + debug_symbol_name_imagehlp(addr, buf, size); + if(buf[0]) return; #endif - - debug_printf("\t%p\n", addr); + +#ifdef __GLIBC__ + debug_symbol_name_glibc(addr, buf, size); + if(buf[0]) + return; +#endif + + util_snprintf(buf, size, "%p", addr); + buf[size - 1] = 0; +} + +void +debug_symbol_print(const void *addr) +{ + char buf[1024]; + debug_symbol_name(addr, buf, sizeof(buf)); + debug_printf("\t%s\n", buf); +} + +struct util_hash_table* symbols_hash; +pipe_mutex symbols_mutex; + +static unsigned hash_ptr(void* p) +{ + return (unsigned)(uintptr_t)p; +} + +static int compare_ptr(void* a, void* b) +{ + if(a == b) + return 0; + else if(a < b) + return -1; + else + return 1; +} + +const char* +debug_symbol_name_cached(const void *addr) +{ + const char* name; + pipe_mutex_lock(symbols_mutex); + if(!symbols_hash) + symbols_hash = util_hash_table_create(hash_ptr, compare_ptr); + name = util_hash_table_get(symbols_hash, (void*)addr); + if(!name) + { + char buf[1024]; + debug_symbol_name(addr, buf, sizeof(buf)); + name = strdup(buf); + + util_hash_table_set(symbols_hash, (void*)addr, (void*)name); + } + pipe_mutex_unlock(symbols_mutex); + return name; } diff --git a/src/gallium/auxiliary/util/u_debug_symbol.h b/src/gallium/auxiliary/util/u_debug_symbol.h index 021586987b..b247706c2a 100644 --- a/src/gallium/auxiliary/util/u_debug_symbol.h +++ b/src/gallium/auxiliary/util/u_debug_symbol.h @@ -43,8 +43,13 @@ extern "C" { void -debug_symbol_print(const void *addr); +debug_symbol_name(const void *addr, char* buf, unsigned size); + +const char* +debug_symbol_name_cached(const void *addr); +void +debug_symbol_print(const void *addr); #ifdef __cplusplus } diff --git a/src/gallium/auxiliary/util/u_dirty_surfaces.h b/src/gallium/auxiliary/util/u_dirty_surfaces.h index 99f260bf96..fd1bbe5ffd 100644 --- a/src/gallium/auxiliary/util/u_dirty_surfaces.h +++ b/src/gallium/auxiliary/util/u_dirty_surfaces.h @@ -1,9 +1,39 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #ifndef U_DIRTY_SURFACES_H_ #define U_DIRTY_SURFACES_H_ +#include "pipe/p_state.h" + #include "util/u_double_list.h" #include "util/u_math.h" +struct pipe_context; + typedef void (*util_dirty_surface_flush_t) (struct pipe_context *, struct pipe_surface *); struct util_dirty_surfaces diff --git a/src/gallium/auxiliary/util/u_draw.h b/src/gallium/auxiliary/util/u_draw.h index 2a91ea0f9a..f06d09ef91 100644 --- a/src/gallium/auxiliary/util/u_draw.h +++ b/src/gallium/auxiliary/util/u_draw.h @@ -31,6 +31,7 @@ #include "pipe/p_compiler.h" #include "pipe/p_context.h" +#include "pipe/p_state.h" static INLINE void diff --git a/src/gallium/auxiliary/util/u_dynarray.h b/src/gallium/auxiliary/util/u_dynarray.h index 9d1c1713a7..980cadf22d 100644 --- a/src/gallium/auxiliary/util/u_dynarray.h +++ b/src/gallium/auxiliary/util/u_dynarray.h @@ -106,6 +106,9 @@ util_dynarray_trim(struct util_dynarray *buf) #define util_dynarray_pop_ptr(buf, type) (type*)((char*)(buf)->data + ((buf)->size -= sizeof(type))) #define util_dynarray_pop(buf, type) *util_dynarray_pop_ptr(buf, type) #define util_dynarray_contains(buf, type) ((buf)->size >= sizeof(type)) +#define util_dynarray_element(buf, type, idx) ((type*)(buf)->data + (idx)) +#define util_dynarray_begin(buf) ((buf)->data) +#define util_dynarray_end(buf) ((void*)util_dynarray_element((buf), char, (buf)->size)) #endif /* U_DYNARRAY_H */ diff --git a/src/gallium/auxiliary/util/u_gen_mipmap.c b/src/gallium/auxiliary/util/u_gen_mipmap.c index b7fe2d3003..6a931a9581 100644 --- a/src/gallium/auxiliary/util/u_gen_mipmap.c +++ b/src/gallium/auxiliary/util/u_gen_mipmap.c @@ -1255,6 +1255,7 @@ fallback_gen_mipmap(struct gen_mipmap_state *ctx, make_1d_mipmap(ctx, pt, face, baseLevel, lastLevel); break; case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_CUBE: make_2d_mipmap(ctx, pt, face, baseLevel, lastLevel); break; diff --git a/src/gallium/auxiliary/util/u_inlines.h b/src/gallium/auxiliary/util/u_inlines.h index 540305c146..78473bf35a 100644 --- a/src/gallium/auxiliary/util/u_inlines.h +++ b/src/gallium/auxiliary/util/u_inlines.h @@ -33,6 +33,8 @@ #include "pipe/p_state.h" #include "pipe/p_screen.h" #include "util/u_debug.h" +#include "util/u_debug_describe.h" +#include "util/u_debug_refcnt.h" #include "util/u_atomic.h" #include "util/u_box.h" #include "util/u_math.h" @@ -67,7 +69,9 @@ pipe_is_referenced(struct pipe_reference *reference) * \return TRUE if the object's refcount hits zero and should be destroyed. */ static INLINE boolean -pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference) +pipe_reference_described(struct pipe_reference *ptr, + struct pipe_reference *reference, + debug_reference_descriptor get_desc) { boolean destroy = FALSE; @@ -76,6 +80,7 @@ pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference) if (reference) { assert(pipe_is_referenced(reference)); p_atomic_inc(&reference->count); + debug_reference(reference, get_desc, 1); } if (ptr) { @@ -83,41 +88,49 @@ pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference) if (p_atomic_dec_zero(&ptr->count)) { destroy = TRUE; } + debug_reference(ptr, get_desc, -1); } } return destroy; } +static INLINE boolean +pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference) +{ + return pipe_reference_described(ptr, reference, + (debug_reference_descriptor)debug_describe_reference); +} static INLINE void pipe_surface_reference(struct pipe_surface **ptr, struct pipe_surface *surf) { struct pipe_surface *old_surf = *ptr; - if (pipe_reference(&(*ptr)->reference, &surf->reference)) + if (pipe_reference_described(&(*ptr)->reference, &surf->reference, + (debug_reference_descriptor)debug_describe_surface)) old_surf->texture->screen->tex_surface_destroy(old_surf); *ptr = surf; } - static INLINE void pipe_resource_reference(struct pipe_resource **ptr, struct pipe_resource *tex) { struct pipe_resource *old_tex = *ptr; - if (pipe_reference(&(*ptr)->reference, &tex->reference)) + if (pipe_reference_described(&(*ptr)->reference, &tex->reference, + (debug_reference_descriptor)debug_describe_resource)) old_tex->screen->resource_destroy(old_tex->screen, old_tex); *ptr = tex; } - static INLINE void pipe_sampler_view_reference(struct pipe_sampler_view **ptr, struct pipe_sampler_view *view) { struct pipe_sampler_view *old_view = *ptr; - if (pipe_reference(&(*ptr)->reference, &view->reference)) + if (pipe_reference_described(&(*ptr)->reference, &view->reference, + (debug_reference_descriptor)debug_describe_sampler_view)) old_view->context->sampler_view_destroy(old_view->context, old_view); *ptr = view; } diff --git a/src/gallium/auxiliary/util/u_linkage.c b/src/gallium/auxiliary/util/u_linkage.c new file mode 100644 index 0000000000..2f6f41ba84 --- /dev/null +++ b/src/gallium/auxiliary/util/u_linkage.c @@ -0,0 +1,149 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "util/u_debug.h" +#include "pipe/p_shader_tokens.h" +#include "tgsi/tgsi_parse.h" +#include "tgsi/tgsi_scan.h" +#include "util/u_linkage.h" + +/* we must only record the registers that are actually used, not just declared */ +static INLINE boolean +util_semantic_set_test_and_set(struct util_semantic_set *set, unsigned value) +{ + unsigned mask = 1 << (value % (sizeof(long) * 8)); + unsigned long *p = &set->masks[value / (sizeof(long) * 8)]; + unsigned long v = *p & mask; + *p |= mask; + return !!v; +} + +unsigned +util_semantic_set_from_program_file(struct util_semantic_set *set, const struct tgsi_token *tokens, enum tgsi_file_type file) +{ + struct tgsi_shader_info info; + struct tgsi_parse_context parse; + unsigned count = 0; + ubyte *semantic_name; + ubyte *semantic_index; + + tgsi_scan_shader(tokens, &info); + + if(file == TGSI_FILE_INPUT) + { + semantic_name = info.input_semantic_name; + semantic_index = info.input_semantic_index; + } + else if(file == TGSI_FILE_OUTPUT) + { + semantic_name = info.output_semantic_name; + semantic_index = info.output_semantic_index; + } + else + { + assert(0); + semantic_name = NULL; + semantic_index = NULL; + } + + tgsi_parse_init(&parse, tokens); + + memset(set->masks, 0, sizeof(set->masks)); + while(!tgsi_parse_end_of_tokens(&parse)) + { + tgsi_parse_token(&parse); + + if(parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION) + { + const struct tgsi_full_instruction *finst = &parse.FullToken.FullInstruction; + unsigned i; + for(i = 0; i < finst->Instruction.NumDstRegs; ++i) + { + if(finst->Dst[i].Register.File == file) + { + unsigned idx = finst->Dst[i].Register.Index; + if(semantic_name[idx] == TGSI_SEMANTIC_GENERIC) + { + if(!util_semantic_set_test_and_set(set, semantic_index[idx])) + ++count; + } + } + } + + for(i = 0; i < finst->Instruction.NumSrcRegs; ++i) + { + if(finst->Src[i].Register.File == file) + { + unsigned idx = finst->Src[i].Register.Index; + if(semantic_name[idx] == TGSI_SEMANTIC_GENERIC) + { + if(!util_semantic_set_test_and_set(set, semantic_index[idx])) + ++count; + } + } + } + } + } + tgsi_parse_free(&parse); + + return count; +} + +#define UTIL_SEMANTIC_SET_FOR_EACH(i, set) for(i = 0; i < 256; ++i) if(set->masks[i / (sizeof(long) * 8)] & (1 << (i % (sizeof(long) * 8)))) + +void +util_semantic_layout_from_set(unsigned char *layout, const struct util_semantic_set *set, unsigned efficient_slots, unsigned num_slots) +{ + int first = -1; + int last = -1; + unsigned i; + + memset(layout, 0xff, num_slots); + + UTIL_SEMANTIC_SET_FOR_EACH(i, set) + { + if(first < 0) + first = i; + last = i; + } + + if(last < efficient_slots) + { + UTIL_SEMANTIC_SET_FOR_EACH(i, set) + layout[i] = i; + } + else if((last - first) < efficient_slots) + { + UTIL_SEMANTIC_SET_FOR_EACH(i, set) + layout[i - first] = i; + } + else + { + unsigned idx = 0; + UTIL_SEMANTIC_SET_FOR_EACH(i, set) + layout[idx++] = i; + } +} diff --git a/src/gallium/auxiliary/util/u_linkage.h b/src/gallium/auxiliary/util/u_linkage.h new file mode 100644 index 0000000000..4720e0ee60 --- /dev/null +++ b/src/gallium/auxiliary/util/u_linkage.h @@ -0,0 +1,66 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef U_LINKAGE_H_ +#define U_LINKAGE_H_ + +#include "pipe/p_compiler.h" +#include "pipe/p_shader_tokens.h" + +struct util_semantic_set +{ + unsigned long masks[256 / 8 / sizeof(unsigned long)]; +}; + +static INLINE bool +util_semantic_set_contains(struct util_semantic_set *set, unsigned char value) +{ + return !!(set->masks[value / (sizeof(long) * 8)] & (1 << (value / (sizeof(long) * 8)))); +} + +unsigned util_semantic_set_from_program_file(struct util_semantic_set *set, const struct tgsi_token *tokens, enum tgsi_file_type file); + +/* efficient_slots is the number of slots such that hardware performance is + * the same for using that amount, with holes, or less slots but with less + * holes. + * + * num_slots is the size of the layout array and hardware limit instead. + * + * efficient_slots == 0 or efficient_solts == num_slots are typical settings. + */ +void util_semantic_layout_from_set(unsigned char *layout, const struct util_semantic_set *set, unsigned efficient_slots, unsigned num_slots); + +static INLINE void +util_semantic_table_from_layout(unsigned char *table, unsigned char *layout, unsigned char first_slot_value, unsigned char num_slots) +{ + int i; + memset(table, 0xff, sizeof(table)); + + for(i = 0; i < num_slots; ++i) + table[layout[i]] = first_slot_value + i; +} + +#endif /* U_LINKAGE_H_ */ diff --git a/src/gallium/auxiliary/util/u_math.h b/src/gallium/auxiliary/util/u_math.h index fe19466436..69a7681494 100644 --- a/src/gallium/auxiliary/util/u_math.h +++ b/src/gallium/auxiliary/util/u_math.h @@ -361,16 +361,6 @@ util_is_inf_or_nan(float x) /** - * Test whether x is a power of two. - */ -static INLINE boolean -util_is_pot(unsigned x) -{ - return (x & (x - 1)) == 0; -} - - -/** * Find first bit set in word. Least significant bit is 1. * Return 0 if no bits set. */ @@ -566,6 +556,9 @@ util_bswap16(uint16_t n) #define MIN3( A, B, C ) MIN2( MIN2( A, B ), C ) #define MAX3( A, B, C ) MAX2( MAX2( A, B ), C ) +#define MIN4( A, B, C, D ) MIN2( MIN2( A, B ), MIN2(C, D) ) +#define MAX4( A, B, C, D ) MAX2( MAX2( A, B ), MAX2(C, D) ) + /** * Align a value, only works pot alignemnts. diff --git a/src/gallium/auxiliary/util/u_pack_color.h b/src/gallium/auxiliary/util/u_pack_color.h index 5f113f742b..aae8b8bdf1 100644 --- a/src/gallium/auxiliary/util/u_pack_color.h +++ b/src/gallium/auxiliary/util/u_pack_color.h @@ -42,12 +42,18 @@ #include "util/u_math.h" - +/** + * Helper union for packing pixel values. + * Will often contain values in formats which are too complex to be described + * in simple terms, hence might just effectively contain a number of bytes. + * Must be big enough to hold data for all formats (currently 256 bits). + */ union util_color { ubyte ub; ushort us; uint ui; float f[4]; + double d[4]; }; /** diff --git a/src/gallium/auxiliary/util/u_rect.c b/src/gallium/auxiliary/util/u_rect.c index 9bbcf1c8c4..56fcfac069 100644 --- a/src/gallium/auxiliary/util/u_rect.c +++ b/src/gallium/auxiliary/util/u_rect.c @@ -32,6 +32,7 @@ #include "util/u_format.h" #include "util/u_rect.h" +#include "util/u_pack_color.h" /** @@ -94,7 +95,7 @@ util_fill_rect(ubyte * dst, unsigned dst_y, unsigned width, unsigned height, - uint32_t value) + union util_color *uc) { unsigned i, j; unsigned width_size; @@ -110,40 +111,54 @@ util_fill_rect(ubyte * dst, dst_y /= blockheight; width = (width + blockwidth - 1)/blockwidth; height = (height + blockheight - 1)/blockheight; - + dst += dst_x * blocksize; dst += dst_y * dst_stride; width_size = width * blocksize; - + switch (blocksize) { case 1: if(dst_stride == width_size) - memset(dst, (ubyte) value, height * width_size); + memset(dst, uc->ub, height * width_size); else { - for (i = 0; i < height; i++) { - memset(dst, (ubyte) value, width_size); - dst += dst_stride; - } + for (i = 0; i < height; i++) { + memset(dst, uc->ub, width_size); + dst += dst_stride; + } } break; case 2: for (i = 0; i < height; i++) { - uint16_t *row = (uint16_t *)dst; - for (j = 0; j < width; j++) - *row++ = (uint16_t) value; - dst += dst_stride; + uint16_t *row = (uint16_t *)dst; + for (j = 0; j < width; j++) + *row++ = uc->us; + dst += dst_stride; } break; case 4: for (i = 0; i < height; i++) { - uint32_t *row = (uint32_t *)dst; - for (j = 0; j < width; j++) - *row++ = value; - dst += dst_stride; + uint32_t *row = (uint32_t *)dst; + for (j = 0; j < width; j++) + *row++ = uc->ui; + dst += dst_stride; + } + break; + case 8: + case 12: + case 16: + case 24: + case 32: + for (i = 0; i < height; i++) { + ubyte *row = dst; + for (j = 0; j < width; j++) { + memcpy(row, uc, blocksize); + row += blocksize; + } + dst += dst_stride; } break; default: - assert(0); - break; + assert(0); + break; } } diff --git a/src/gallium/auxiliary/util/u_rect.h b/src/gallium/auxiliary/util/u_rect.h index 40d57e662d..4cb90d3c31 100644 --- a/src/gallium/auxiliary/util/u_rect.h +++ b/src/gallium/auxiliary/util/u_rect.h @@ -26,17 +26,67 @@ **************************************************************************/ -/** - * Pipe copy/fill rect helpers. +#ifndef U_RECT_H +#define U_RECT_H + +#include "pipe/p_compiler.h" + +struct u_rect { + int x0, x1; + int y0, y1; +}; + +/* Do two rectangles intersect? */ +static INLINE boolean +u_rect_test_intersection(const struct u_rect *a, + const struct u_rect *b) +{ + return (!(a->x1 < b->x0 || + b->x1 < a->x0 || + a->y1 < b->y0 || + b->y1 < a->y0)); +} +/* Find the intersection of two rectangles known to intersect. + */ +static INLINE void +u_rect_find_intersection(const struct u_rect *a, + struct u_rect *b) +{ + /* Caller should verify intersection exists before calling. + */ + if (b->x0 < a->x0) b->x0 = a->x0; + if (b->x1 > a->x1) b->x1 = a->x1; + if (b->y0 < a->y0) b->y0 = a->y0; + if (b->y1 > a->y1) b->y1 = a->y1; +} -#ifndef U_RECT_H -#define U_RECT_H +static INLINE void +u_rect_possible_intersection(const struct u_rect *a, + struct u_rect *b) +{ + if (u_rect_test_intersection(a,b)) { + u_rect_find_intersection(a,b); + } + else { + b->x0 = b->x1 = b->y0 = b->y1 = 0; + } +} #include "pipe/p_format.h" +#include "util/u_pack_color.h" + + + +/********************************************************************** + * Pipe copy/fill rect helpers. + */ +/* These really should move to a different file: + */ +#include "pipe/p_format.h" extern void util_copy_rect(ubyte * dst, enum pipe_format format, @@ -47,7 +97,7 @@ util_copy_rect(ubyte * dst, enum pipe_format format, extern void util_fill_rect(ubyte * dst, enum pipe_format format, unsigned dst_stride, unsigned dst_x, unsigned dst_y, - unsigned width, unsigned height, uint32_t value); + unsigned width, unsigned height, union util_color *uc); #endif /* U_RECT_H */ diff --git a/src/gallium/auxiliary/util/u_simple_shaders.c b/src/gallium/auxiliary/util/u_simple_shaders.c index 5b682f496c..58ef68377f 100644 --- a/src/gallium/auxiliary/util/u_simple_shaders.c +++ b/src/gallium/auxiliary/util/u_simple_shaders.c @@ -37,6 +37,7 @@ #include "pipe/p_context.h" #include "pipe/p_shader_tokens.h" +#include "pipe/p_state.h" #include "util/u_simple_shaders.h" #include "util/u_debug.h" #include "tgsi/tgsi_ureg.h" diff --git a/src/gallium/auxiliary/util/u_split_prim.h b/src/gallium/auxiliary/util/u_split_prim.h index 206e1ec311..7f80fc1270 100644 --- a/src/gallium/auxiliary/util/u_split_prim.h +++ b/src/gallium/auxiliary/util/u_split_prim.h @@ -1,5 +1,12 @@ /* Originally written by Ben Skeggs for the nv50 driver*/ -#include <pipe/p_defines.h> + +#ifndef U_SPLIT_PRIM_H +#define U_SPLIT_PRIM_H + +#include "pipe/p_defines.h" +#include "pipe/p_compiler.h" + +#include "util/u_debug.h" struct util_split_prim { void *priv; @@ -48,7 +55,7 @@ util_split_prim_next(struct util_split_prim *s, unsigned max_verts) } } - if (s->p_start + s->close_first + max_verts >= s->p_end) { + if ((s->p_end - s->p_start) + s->close_first <= max_verts) { s->emit(s->priv, s->p_start, s->p_end - s->p_start); if (s->close_first) s->emit(s->priv, s->start, 1); @@ -103,3 +110,5 @@ util_split_prim_next(struct util_split_prim *s, unsigned max_verts) s->p_start += (max_verts - repeat); return FALSE; } + +#endif /* U_SPLIT_PRIM_H */ diff --git a/src/gallium/auxiliary/util/u_staging.c b/src/gallium/auxiliary/util/u_staging.c index 607c31f5ee..c5d68f8df8 100644 --- a/src/gallium/auxiliary/util/u_staging.c +++ b/src/gallium/auxiliary/util/u_staging.c @@ -1,3 +1,29 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #include "util/u_staging.h" #include "pipe/p_context.h" #include "util/u_memory.h" @@ -8,7 +34,7 @@ util_staging_resource_template(struct pipe_resource *pt, unsigned width, unsigne { memset(template, 0, sizeof(struct pipe_resource)); if(pt->target != PIPE_BUFFER && depth <= 1) - template->target = PIPE_TEXTURE_2D; + template->target = PIPE_TEXTURE_RECT; else template->target = pt->target; template->format = pt->format; @@ -23,20 +49,16 @@ util_staging_resource_template(struct pipe_resource *pt, unsigned width, unsigne } struct util_staging_transfer * -util_staging_transfer_new(struct pipe_context *pipe, +util_staging_transfer_init(struct pipe_context *pipe, struct pipe_resource *pt, struct pipe_subresource sr, unsigned usage, const struct pipe_box *box, - bool direct) + bool direct, struct util_staging_transfer *tx) { struct pipe_screen *pscreen = pipe->screen; - struct util_staging_transfer *tx; - struct pipe_resource staging_resource_template; - tx = CALLOC_STRUCT(util_staging_transfer); - if (!tx) - return NULL; + struct pipe_resource staging_resource_template; pipe_resource_reference(&tx->base.resource, pt); tx->base.sr = sr; diff --git a/src/gallium/auxiliary/util/u_staging.h b/src/gallium/auxiliary/util/u_staging.h index 602faa2971..1aab78cc88 100644 --- a/src/gallium/auxiliary/util/u_staging.h +++ b/src/gallium/auxiliary/util/u_staging.h @@ -1,3 +1,29 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + /* Direct3D 10/11 has no concept of transfers. Applications instead * create resources with a STAGING or DYNAMIC usage, copy between them * and the real resource and use Map to map the STAGING/DYNAMIC resource. @@ -21,15 +47,15 @@ struct util_staging_transfer { }; /* user must be stride, slice_stride and offset */ -/* pt->usage == PIPE_USAGE_DYNAMIC should be a good value to pass for direct */ -/* staging resource is currently created with PIPE_USAGE_DYNAMIC */ +/* pt->usage == PIPE_USAGE_DYNAMIC || pt->usage == PIPE_USAGE_STAGING should be a good value to pass for direct */ +/* staging resource is currently created with PIPE_USAGE_STAGING */ struct util_staging_transfer * -util_staging_transfer_new(struct pipe_context *pipe, +util_staging_transfer_init(struct pipe_context *pipe, struct pipe_resource *pt, struct pipe_subresource sr, unsigned usage, const struct pipe_box *box, - bool direct); + bool direct, struct util_staging_transfer *tx); void util_staging_transfer_destroy(struct pipe_context *pipe, struct pipe_transfer *ptx); diff --git a/src/gallium/auxiliary/util/u_surface.c b/src/gallium/auxiliary/util/u_surface.c index cab7691c70..af99163b2e 100644 --- a/src/gallium/auxiliary/util/u_surface.c +++ b/src/gallium/auxiliary/util/u_surface.c @@ -216,7 +216,7 @@ util_clear_render_target(struct pipe_context *pipe, assert(dst->texture); if (!dst->texture) return; - util_pack_color(rgba, dst->texture->format, &uc); + dst_trans = pipe_get_transfer(pipe, dst->texture, dst->face, @@ -232,46 +232,10 @@ util_clear_render_target(struct pipe_context *pipe, if (dst_map) { assert(dst_trans->stride > 0); - switch (util_format_get_blocksize(dst->texture->format)) { - case 1: - case 2: - case 4: - util_pack_color(rgba, dst->texture->format, &uc); - util_fill_rect(dst_map, dst->texture->format, - dst_trans->stride, - 0, 0, width, height, uc.ui); - break; - case 8: - { - /* expand the 4-byte clear value to an 8-byte value */ - /* should probably not convert back from ubyte but not - sure what this code really achieved since it doesn't even - check for format type... */ - ushort *row = (ushort *) dst_map; - ushort val0 = UBYTE_TO_USHORT((uc.ui >> 0) & 0xff); - ushort val1 = UBYTE_TO_USHORT((uc.ui >> 8) & 0xff); - ushort val2 = UBYTE_TO_USHORT((uc.ui >> 16) & 0xff); - ushort val3 = UBYTE_TO_USHORT((uc.ui >> 24) & 0xff); - unsigned i, j; - val0 = (val0 << 8) | val0; - val1 = (val1 << 8) | val1; - val2 = (val2 << 8) | val2; - val3 = (val3 << 8) | val3; - for (i = 0; i < height; i++) { - for (j = 0; j < width; j++) { - row[j*4+0] = val0; - row[j*4+1] = val1; - row[j*4+2] = val2; - row[j*4+3] = val3; - } - row += dst_trans->stride/2; - } - } - break; - default: - assert(0); - break; - } + util_pack_color(rgba, dst->texture->format, &uc); + util_fill_rect(dst_map, dst->texture->format, + dst_trans->stride, + 0, 0, width, height, &uc); } pipe->transfer_unmap(pipe, dst_trans); diff --git a/src/gallium/auxiliary/util/u_surfaces.c b/src/gallium/auxiliary/util/u_surfaces.c index 7733ad24d0..404e121995 100644 --- a/src/gallium/auxiliary/util/u_surfaces.c +++ b/src/gallium/auxiliary/util/u_surfaces.c @@ -1,3 +1,29 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #include "u_surfaces.h" #include "util/u_hash_table.h" #include "util/u_inlines.h" diff --git a/src/gallium/auxiliary/util/u_surfaces.h b/src/gallium/auxiliary/util/u_surfaces.h index af978c7057..17d8a5d3a5 100644 --- a/src/gallium/auxiliary/util/u_surfaces.h +++ b/src/gallium/auxiliary/util/u_surfaces.h @@ -1,3 +1,29 @@ +/************************************************************************** + * + * Copyright 2010 Luca Barbieri + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #ifndef U_SURFACES_H_ #define U_SURFACES_H_ @@ -22,7 +48,7 @@ struct pipe_surface *util_surfaces_do_get(struct util_surfaces *us, unsigned sur static INLINE struct pipe_surface * util_surfaces_get(struct util_surfaces *us, unsigned surface_struct_size, struct pipe_screen *pscreen, struct pipe_resource *pt, unsigned face, unsigned level, unsigned zslice, unsigned flags) { - if(likely(pt->target == PIPE_TEXTURE_2D && us->u.array)) + if(likely((pt->target == PIPE_TEXTURE_2D || pt->target == PIPE_TEXTURE_RECT) && us->u.array)) { struct pipe_surface *ps = us->u.array[level]; if(ps) @@ -52,7 +78,7 @@ void util_surfaces_do_detach(struct util_surfaces *us, struct pipe_surface *ps); static INLINE void util_surfaces_detach(struct util_surfaces *us, struct pipe_surface *ps) { - if(likely(ps->texture->target == PIPE_TEXTURE_2D)) + if(likely(ps->texture->target == PIPE_TEXTURE_2D || ps->texture->target == PIPE_TEXTURE_RECT)) { us->u.array[ps->level] = 0; return; diff --git a/src/gallium/auxiliary/util/u_tile.h b/src/gallium/auxiliary/util/u_tile.h index 986eee0743..558351d0ce 100644 --- a/src/gallium/auxiliary/util/u_tile.h +++ b/src/gallium/auxiliary/util/u_tile.h @@ -29,7 +29,10 @@ #define P_TILE_H #include "pipe/p_compiler.h" +#include "pipe/p_format.h" +#include "pipe/p_state.h" +struct pipe_context; struct pipe_transfer; /** diff --git a/src/gallium/auxiliary/util/u_transfer.h b/src/gallium/auxiliary/util/u_transfer.h index eb07945d15..e3a38730f2 100644 --- a/src/gallium/auxiliary/util/u_transfer.h +++ b/src/gallium/auxiliary/util/u_transfer.h @@ -8,6 +8,7 @@ #include "pipe/p_state.h" struct pipe_context; +struct winsys_handle; boolean u_default_resource_get_handle(struct pipe_screen *screen, struct pipe_resource *resource, diff --git a/src/gallium/auxiliary/util/u_upload_mgr.h b/src/gallium/auxiliary/util/u_upload_mgr.h index a124924fc8..de016df02e 100644 --- a/src/gallium/auxiliary/util/u_upload_mgr.h +++ b/src/gallium/auxiliary/util/u_upload_mgr.h @@ -32,11 +32,8 @@ #ifndef U_UPLOAD_MGR_H #define U_UPLOAD_MGR_H -#include "pipe/p_defines.h" - -struct pipe_screen; +struct pipe_context; struct pipe_resource; -struct u_upload_mgr; struct u_upload_mgr *u_upload_create( struct pipe_context *pipe, diff --git a/src/gallium/docs/source/context.rst b/src/gallium/docs/source/context.rst index f241411a00..8250c30f2a 100644 --- a/src/gallium/docs/source/context.rst +++ b/src/gallium/docs/source/context.rst @@ -63,7 +63,9 @@ objects. They all follow simple, one-method binding calls, e.g. * ``set_scissor_state`` sets the bounds for the scissor test, which culls pixels before blending to render targets. If the :ref:`Rasterizer` does not have the scissor test enabled, then the scissor bounds never need to - be set since they will not be used. + be set since they will not be used. Note that scissor xmin and ymin are + inclusive, but xmax and ymax are exclusive. The inclusive ranges in x + and y would be [xmin..xmax-1] and [ymin..ymax-1]. * ``set_viewport_state`` diff --git a/src/gallium/docs/source/debugging.rst b/src/gallium/docs/source/debugging.rst index 42bda5aee9..e081cbf74e 100644 --- a/src/gallium/docs/source/debugging.rst +++ b/src/gallium/docs/source/debugging.rst @@ -21,6 +21,10 @@ This option controls if the debug variables should be printed to stderr. This is probably the most useful variable, since it allows you to find which variables a driver uses. +.. envvar:: GALLIUM_GALAHAD <bool> (false) + +Controls if the :ref:`galahad` sanity checker module should be used. + .. envvar:: GALLIUM_RBUG <bool> (false) Controls if the :ref:`rbug` should be used. diff --git a/src/gallium/docs/source/distro.rst b/src/gallium/docs/source/distro.rst index 70d75b51e6..08c8eab890 100644 --- a/src/gallium/docs/source/distro.rst +++ b/src/gallium/docs/source/distro.rst @@ -79,6 +79,15 @@ Rbug Wrapper driver. :ref:`rbug` driver used with stand alone rbug-gui. +.. _galahad: + +Galahad +^^^^^^^ + +Wrapper driver. Sanity checker for the internal gallium state. Normally +a driver should n't have to sanity check the input it gets from a state +tracker. Any wrong state received should be perceived as a state tracker bug. + State Trackers -------------- diff --git a/src/gallium/docs/source/index.rst b/src/gallium/docs/source/index.rst index 6c19842dac..2a73e3ab59 100644 --- a/src/gallium/docs/source/index.rst +++ b/src/gallium/docs/source/index.rst @@ -15,6 +15,7 @@ Contents: debugging tgsi screen + resources context cso distro diff --git a/src/gallium/docs/source/resources.rst b/src/gallium/docs/source/resources.rst new file mode 100644 index 0000000000..c8a5766821 --- /dev/null +++ b/src/gallium/docs/source/resources.rst @@ -0,0 +1,195 @@ +Resources and derived objects +============================= + +Resources represent objects that hold data: textures and buffers. + +They are mostly modelled after the resources in Direct3D 10/11, but with a +different transfer/update mechanism, and more features for OpenGL support. + +Resources can be used in several ways, and it is required to specify all planned uses through an appropriate set of bind flags. + +TODO: write much more on resources + +Transfers +--------- + +Transfers are the mechanism used to access resources with the CPU. + +OpenGL: OpenGL supports mapping buffers and has inline transfer functions for both buffers and textures + +D3D11: D3D11 lacks transfers, but has special resource types that are mappable to the CPU address space + +TODO: write much more on transfers + +Resource targets +---------------- + +Resource targets determine the type of a resource. + +Note that drivers may not actually have the restrictions listed regarding +coordinate normalization and wrap modes, and in fact efficient OpenCL +support will probably require drivers that don't have any of them, which +will probably be advertised with an appropriate cap. + +TODO: document all targets. Note that both 3D and cube have restrictions +that depend on the hardware generation. + +TODO: can buffers have a non-R8 format? + +PIPE_BUFFER +^^^^^^^^^^^ + +Buffer resource: can be used as a vertex, index, constant buffer (appropriate bind flags must be requested). + +They can be bound to stream output if supported. +TODO: what about the restrictions lifted by the several later GL transform feedback extensions? How does one advertise that in Gallium? + +They can be also be bound to a shader stage as usual. +TODO: are all drivers supposed to support this? how does this work exactly? are there size limits? + +They can be also be bound to the framebuffer as usual. +TODO: are all drivers supposed to support this? how does this work exactly? are there size limits? +TODO: is there any chance of supporting GL pixel buffer object acceleration with this? + +- depth0 must be 1 +- last_level must be 0 +- TODO: what about normalization? +- TODO: wrap modes/other sampling state? +- TODO: are arbitrary formats supported? in which cases? + +OpenGL: vertex buffers in GL 1.5 or GL_ARB_vertex_buffer_object + +- Binding to stream out requires GL 3.0 or GL_NV_transform_feedback +- Binding as constant buffers requires GL 3.1 or GL_ARB_uniform_buffer_object +- Binding to a sampling stage requires GL 3.1 or GL_ARB_texture_buffer_object +- TODO: can they be bound to an FBO? + +D3D11: buffer resources +- Binding to a render target requires D3D_FEATURE_LEVEL_10_0 + +PIPE_TEXTURE_1D +^^^^^^^^^^^^^^^ +1D surface accessed with normalized coordinates. + +UNIMPLEMENTED: 1D texture arrays not supported + +- If PIPE_CAP_NPOT_TEXTURES is not supported, + width must be a power of two +- height0 must be 1 +- depth0 must be 1 +- Mipmaps can be used +- Must use normalized coordinates + +OpenGL: GL_TEXTURE_1D in GL 1.0 + +- PIPE_CAP_NPOT_TEXTURES is equivalent to GL 2.0 or GL_ARB_texture_non_power_of_two + +D3D11: 1D textures in D3D_FEATURE_LEVEL_10_0 + +PIPE_TEXTURE_RECT +^^^^^^^^^^^^^^^^^ +2D surface with OpenGL GL_TEXTURE_RECTANGLE semantics. + +- depth0 must be 1 +- last_level must be 0 +- Must use unnormalized coordinates +- Must use a clamp wrap mode + +OpenGL: GL_TEXTURE_RECTANGLE in GL 3.1 or GL_ARB_texture_rectangle or GL_NV_texture_rectangle + +OpenCL: can create OpenCL images based on this, that can then be sampled arbitrarily + +D3D11: not supported (only PIPE_TEXTURE_2D with normalized coordinates is supported) + +PIPE_TEXTURE_2D +^^^^^^^^^^^^^^^ +2D surface accessed with normalized coordinates. + +UNIMPLEMENTED: 2D texture arrays not supported + +- If PIPE_CAP_NPOT_TEXTURES is not supported, + width and height must be powers of two +- depth0 must be 1 +- Mipmaps can be used +- Must use normalized coordinates +- No special restrictions on wrap modes + +OpenGL: GL_TEXTURE_2D in GL 1.0 + +- PIPE_CAP_NPOT_TEXTURES is equivalent to GL 2.0 or GL_ARB_texture_non_power_of_two + +OpenCL: can create OpenCL images based on this, that can then be sampled arbitrarily + +D3D11: 2D textures + +- PIPE_CAP_NPOT_TEXTURES is equivalent to D3D_FEATURE_LEVEL_9_3 + +PIPE_TEXTURE_3D +^^^^^^^^^^^^^^^ + +3-dimensional array of texels. +Mipmap dimensions are reduced in all 3 coordinates. + +- If PIPE_CAP_NPOT_TEXTURES is not supported, + width, height and depth must be powers of two +- Must use normalized coordinates + +OpenGL: GL_TEXTURE_3D in GL 1.2 or GL_EXT_texture3D + +- PIPE_CAP_NPOT_TEXTURES is equivalent to GL 2.0 or GL_ARB_texture_non_power_of_two + +D3D11: 3D textures + +- PIPE_CAP_NPOT_TEXTURES is equivalent to D3D_FEATURE_LEVEL_10_0 + +PIPE_TEXTURE_CUBE +^^^^^^^^^^^^^^^^^ + +Cube maps consist of 6 2D faces. +The 6 surfaces form an imaginary cube, and sampling happens by mapping an +input 3-vector to the point of the cube surface in that direction. + +Sampling may be optionally seamless, resulting in filtering taking samples +from multiple surfaces near to the edge. +UNIMPLEMENTED: seamless cube map sampling not supported + +UNIMPLEMENTED: cube map arrays not supported + +- Width and height must be equal +- If PIPE_CAP_NPOT_TEXTURES is not supported, + width and height must be powers of two +- Must use normalized coordinates + +OpenGL: GL_TEXTURE_CUBE_MAP in GL 1.3 or EXT_texture_cube_map + +- PIPE_CAP_NPOT_TEXTURES is equivalent to GL 2.0 or GL_ARB_texture_non_power_of_two +- Seamless cube maps require GL 3.2 or GL_ARB_seamless_cube_map or GL_AMD_seamless_cubemap_per_texture +- Cube map arrays require GL 4.0 or GL_ARB_texture_cube_map_array + +D3D11: 2D array textures with the D3D11_RESOURCE_MISC_TEXTURECUBE flag + +- PIPE_CAP_NPOT_TEXTURES is equivalent to D3D_FEATURE_LEVEL_10_0 +- Cube map arrays require D3D_FEATURE_LEVEL_10_1 +- TODO: are (non)seamless cube maps supported in D3D11? how? + +Surfaces +-------- + +Surfaces are views of a resource that can be bound as a framebuffer to serve as the render target or depth buffer. + +TODO: write much more on surfaces + +OpenGL: FBOs are collections of surfaces in GL 3.0 or GL_ARB_framebuffer_object + +D3D11: render target views and depth/stencil views + +Sampler views +------------- + +Sampler views are views of a resource that can be bound to a pipeline stage to be sampled from shaders. + +TODO: write much more on sampler views + +OpenGL: texture objects are actually sampler view and resource in a single unit + +D3D11: shader resource views diff --git a/src/gallium/drivers/cell/ppu/cell_draw_arrays.c b/src/gallium/drivers/cell/ppu/cell_draw_arrays.c index 4adef5b8c0..a367fa3fe1 100644 --- a/src/gallium/drivers/cell/ppu/cell_draw_arrays.c +++ b/src/gallium/drivers/cell/ppu/cell_draw_arrays.c @@ -78,20 +78,13 @@ cell_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) draw_set_mapped_vertex_buffer(draw, i, buf); } /* Map index buffer, if present */ - if (info->indexed && cell->index_buffer.buffer) { + if (info->indexed && cell->index_buffer.buffer) mapped_indices = cell_resource(cell->index_buffer.buffer)->data; - mapped_indices += cell->index_buffer.offset; - } - draw_set_mapped_element_buffer_range(draw, (mapped_indices) ? - lp->index_buffer.index_size : 0, - info->index_bias, - info->min_index, - info->max_index, - mapped_indices); + draw_set_mapped_index_buffer(draw, mapped_indices); /* draw! */ - draw_arrays(draw, info->mode, info->start, info->count); + draw_vbo(draw, info); /* * unmap vertex/index buffers - will cause draw module to flush @@ -100,7 +93,7 @@ cell_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) draw_set_mapped_vertex_buffer(draw, i, NULL); } if (mapped_indices) { - draw_set_mapped_element_buffer(draw, 0, 0, NULL); + draw_set_mapped_index_buffer(draw, NULL); } /* diff --git a/src/gallium/drivers/cell/ppu/cell_state_vertex.c b/src/gallium/drivers/cell/ppu/cell_state_vertex.c index 4e3701cd0a..a065d68b5a 100644 --- a/src/gallium/drivers/cell/ppu/cell_state_vertex.c +++ b/src/gallium/drivers/cell/ppu/cell_state_vertex.c @@ -102,7 +102,7 @@ cell_set_index_buffer(struct pipe_context *pipe, else memset(&cell->index_buffer, 0, sizeof(cell->index_buffer)); - /* TODO make this more like a state */ + draw_set_index_buffer(cell->draw, ib); } diff --git a/src/gallium/drivers/galahad/glhd_context.c b/src/gallium/drivers/galahad/glhd_context.c index fe14a287ef..383c448926 100644 --- a/src/gallium/drivers/galahad/glhd_context.c +++ b/src/gallium/drivers/galahad/glhd_context.c @@ -185,6 +185,12 @@ galahad_bind_fragment_sampler_states(struct pipe_context *_pipe, struct galahad_context *glhd_pipe = galahad_context(_pipe); struct pipe_context *pipe = glhd_pipe->pipe; + if (num_samplers > PIPE_MAX_SAMPLERS) { + glhd_error("%u fragment samplers requested, " + "but only %u are permitted by API", + num_samplers, PIPE_MAX_SAMPLERS); + } + pipe->bind_fragment_sampler_states(pipe, num_samplers, samplers); @@ -198,6 +204,12 @@ galahad_bind_vertex_sampler_states(struct pipe_context *_pipe, struct galahad_context *glhd_pipe = galahad_context(_pipe); struct pipe_context *pipe = glhd_pipe->pipe; + if (num_samplers > PIPE_MAX_VERTEX_SAMPLERS) { + glhd_error("%u vertex samplers requested, " + "but only %u are permitted by API", + num_samplers, PIPE_MAX_VERTEX_SAMPLERS); + } + pipe->bind_vertex_sampler_states(pipe, num_samplers, samplers); @@ -447,6 +459,19 @@ galahad_set_constant_buffer(struct pipe_context *_pipe, struct pipe_resource *unwrapped_resource; struct pipe_resource *resource = NULL; + if (shader >= PIPE_SHADER_TYPES) { + glhd_error("Unknown shader type %u", shader); + } + + if (index && + index >= + pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_CONST_BUFFERS)) { + glhd_error("Access to constant buffer %u requested, " + "but only %d are supported", + index, + pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_CONST_BUFFERS)); + } + /* XXX hmm? unwrap the input state */ if (_resource) { unwrapped_resource = galahad_resource_unwrap(_resource); @@ -972,5 +997,7 @@ galahad_context_create(struct pipe_screen *_screen, struct pipe_context *pipe) glhd_pipe->pipe = pipe; + glhd_warn("Created context %p", glhd_pipe); + return &glhd_pipe->base; } diff --git a/src/gallium/drivers/galahad/glhd_screen.c b/src/gallium/drivers/galahad/glhd_screen.c index 4117485702..75e4c2d82e 100644 --- a/src/gallium/drivers/galahad/glhd_screen.c +++ b/src/gallium/drivers/galahad/glhd_screen.c @@ -30,6 +30,7 @@ #include "pipe/p_screen.h" #include "pipe/p_state.h" #include "util/u_memory.h" +#include "util/u_math.h" #include "glhd_public.h" #include "glhd_screen.h" @@ -134,6 +135,33 @@ galahad_screen_resource_create(struct pipe_screen *_screen, struct pipe_screen *screen = glhd_screen->screen; struct pipe_resource *result; + if (templat->target >= PIPE_MAX_TEXTURE_TYPES) + glhd_warn("Received bogus resource target %d", templat->target); + + if(templat->target != PIPE_TEXTURE_RECT && templat->target != PIPE_BUFFER && !screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) + { + if(!util_is_power_of_two(templat->width0) || !util_is_power_of_two(templat->height0)) + glhd_warn("Requested NPOT (%ux%u) non-rectangle texture without NPOT support", templat->width0, templat->height0); + } + + if(templat->target == PIPE_TEXTURE_RECT && templat->last_level) + glhd_warn("Rectangle textures cannot have mipmaps, but last_level = %u", templat->last_level); + + if(templat->target == PIPE_BUFFER && templat->last_level) + glhd_warn("Buffers cannot have mipmaps, but last_level = %u", templat->last_level); + + if(templat->target != PIPE_TEXTURE_3D && templat->depth0 != 1) + glhd_warn("Only 3D textures can have depth != 1, but received target %u and depth %u", templat->target, templat->depth0); + + if(templat->target == PIPE_TEXTURE_1D && templat->height0 != 1) + glhd_warn("1D textures must have height 1 but got asked for height %u", templat->height0); + + if(templat->target == PIPE_BUFFER && templat->height0 != 1) + glhd_warn("Buffers must have height 1 but got asked for height %u", templat->height0); + + if(templat->target == PIPE_TEXTURE_CUBE && templat->width0 != templat->height0) + glhd_warn("Cube maps must be square, but got asked for %ux%u", templat->width0, templat->height0); + result = screen->resource_create(screen, templat); @@ -330,5 +358,7 @@ galahad_screen_create(struct pipe_screen *screen) glhd_screen->screen = screen; + glhd_warn("Created screen %p", glhd_screen); + return &glhd_screen->base; } diff --git a/src/gallium/drivers/i915/i915_context.c b/src/gallium/drivers/i915/i915_context.c index 2beb9e3091..847dd6dd47 100644 --- a/src/gallium/drivers/i915/i915_context.c +++ b/src/gallium/drivers/i915/i915_context.c @@ -66,18 +66,9 @@ i915_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) /* * Map index buffer, if present */ - if (info->indexed && i915->index_buffer.buffer) { - char *indices = (char *) i915_buffer(i915->index_buffer.buffer)->data; - mapped_indices = (void *) (indices + i915->index_buffer.offset); - } - - draw_set_mapped_element_buffer_range(draw, (mapped_indices) ? - i915->index_buffer.index_size : 0, - info->index_bias, - info->min_index, - info->max_index, - mapped_indices); - + if (info->indexed && i915->index_buffer.buffer) + mapped_indices = i915_buffer(i915->index_buffer.buffer)->data; + draw_set_mapped_index_buffer(draw, mapped_indices); draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, i915->current.constants[PIPE_SHADER_VERTEX], @@ -87,7 +78,7 @@ i915_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) /* * Do the drawing */ - draw_arrays(i915->draw, info->mode, info->start, info->count); + draw_vbo(i915->draw, info); /* * unmap vertex/index buffers @@ -96,9 +87,8 @@ i915_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) draw_set_mapped_vertex_buffer(draw, i, NULL); } - if (mapped_indices) { - draw_set_mapped_element_buffer(draw, 0, 0, NULL); - } + if (mapped_indices) + draw_set_mapped_index_buffer(draw, NULL); } diff --git a/src/gallium/drivers/i915/i915_resource_texture.c b/src/gallium/drivers/i915/i915_resource_texture.c index 752ddaae7b..c5c6179b16 100644 --- a/src/gallium/drivers/i915/i915_resource_texture.c +++ b/src/gallium/drivers/i915/i915_resource_texture.c @@ -360,6 +360,7 @@ i915_texture_layout(struct i915_texture * tex) switch (pt->target) { case PIPE_TEXTURE_1D: case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: if (!i9x5_special_layout(tex)) i915_texture_layout_2d(tex); break; @@ -605,6 +606,7 @@ i945_texture_layout(struct i915_texture * tex) switch (pt->target) { case PIPE_TEXTURE_1D: case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: if (!i9x5_special_layout(tex)) i945_texture_layout_2d(tex); break; @@ -829,7 +831,8 @@ i915_texture_from_handle(struct pipe_screen * screen, buffer = iws->buffer_from_handle(iws, whandle, &stride); /* Only supports one type */ - if (template->target != PIPE_TEXTURE_2D || + if ((template->target != PIPE_TEXTURE_2D && + template->target != PIPE_TEXTURE_RECT) || template->last_level != 0 || template->depth0 != 1) { return NULL; diff --git a/src/gallium/drivers/i915/i915_state.c b/src/gallium/drivers/i915/i915_state.c index 385c3b2d2d..bbfcff6bc4 100644 --- a/src/gallium/drivers/i915/i915_state.c +++ b/src/gallium/drivers/i915/i915_state.c @@ -294,8 +294,6 @@ static void i915_bind_sampler_states(struct pipe_context *pipe, struct i915_context *i915 = i915_context(pipe); unsigned i; - assert(num <= PIPE_MAX_SAMPLERS); - /* Check for no-op */ if (num == i915->num_samplers && !memcmp(i915->sampler, sampler, num * sizeof(void *))) @@ -529,9 +527,6 @@ static void i915_set_constant_buffer(struct pipe_context *pipe, struct i915_context *i915 = i915_context(pipe); draw_flush(i915->draw); - assert(shader < PIPE_SHADER_TYPES); - assert(index == 0); - /* Make a copy of shader constants. * During fragment program translation we may add additional * constants to the array. @@ -822,7 +817,8 @@ static void i915_set_index_buffer(struct pipe_context *pipe, else memset(&i915->index_buffer, 0, sizeof(i915->index_buffer)); - /* TODO make this more like a state */ + /* pass-through to draw module */ + draw_set_index_buffer(i915->draw, ib); } static void diff --git a/src/gallium/drivers/i965/brw_batchbuffer.c b/src/gallium/drivers/i965/brw_batchbuffer.c index 8b3f46f2c1..e80067f3b1 100644 --- a/src/gallium/drivers/i965/brw_batchbuffer.c +++ b/src/gallium/drivers/i965/brw_batchbuffer.c @@ -162,7 +162,7 @@ brw_batchbuffer_emit_reloc(struct brw_batchbuffer *batch, if (batch->ptr - batch->map > batch->buf->size) { debug_printf("bad relocation ptr %p map %p offset %li size %i\n", - batch->ptr, batch->map, batch->ptr - batch->map, batch->buf->size); + batch->ptr, batch->map, (long) (batch->ptr - batch->map), batch->buf->size); return PIPE_ERROR_OUT_OF_MEMORY; } diff --git a/src/gallium/drivers/i965/brw_resource_texture.c b/src/gallium/drivers/i965/brw_resource_texture.c index ffd0f38672..3860d18a7a 100644 --- a/src/gallium/drivers/i965/brw_resource_texture.c +++ b/src/gallium/drivers/i965/brw_resource_texture.c @@ -66,6 +66,7 @@ static GLuint translate_tex_target( unsigned target ) return BRW_SURFACE_1D; case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: return BRW_SURFACE_2D; case PIPE_TEXTURE_3D: @@ -498,7 +499,8 @@ brw_texture_from_handle(struct pipe_screen *screen, unsigned pitch; GLuint format; - if (template->target != PIPE_TEXTURE_2D || + if ((template->target != PIPE_TEXTURE_2D + && template->target != PIPE_TEXTURE_RECT) || template->last_level != 0 || template->depth0 != 1) return NULL; diff --git a/src/gallium/drivers/i965/brw_wm_debug.c b/src/gallium/drivers/i965/brw_wm_debug.c index e2767264e7..1b2aa93bef 100644 --- a/src/gallium/drivers/i965/brw_wm_debug.c +++ b/src/gallium/drivers/i965/brw_wm_debug.c @@ -101,16 +101,16 @@ void brw_wm_print_value( struct brw_wm_compile *c, debug_printf("undef"); else if( value - c->vreg >= 0 && value - c->vreg < BRW_WM_MAX_VREG) - debug_printf("r%d", value - c->vreg); + debug_printf("r%ld", (long) (value - c->vreg)); else if (value - c->creg >= 0 && value - c->creg < BRW_WM_MAX_PARAM) - debug_printf("c%d", value - c->creg); + debug_printf("c%ld", (long) (value - c->creg)); else if (value - c->payload.input_interp >= 0 && value - c->payload.input_interp < PIPE_MAX_SHADER_INPUTS) - debug_printf("i%d", value - c->payload.input_interp); + debug_printf("i%ld", (long) (value - c->payload.input_interp)); else if (value - c->payload.depth >= 0 && value - c->payload.depth < PIPE_MAX_SHADER_INPUTS) - debug_printf("d%d", value - c->payload.depth); + debug_printf("d%ld", (long) (value - c->payload.depth)); else debug_printf("?"); } diff --git a/src/gallium/drivers/llvmpipe/Makefile b/src/gallium/drivers/llvmpipe/Makefile index 2892b62920..dec874623e 100644 --- a/src/gallium/drivers/llvmpipe/Makefile +++ b/src/gallium/drivers/llvmpipe/Makefile @@ -27,6 +27,8 @@ C_SOURCES = \ lp_scene_queue.c \ lp_screen.c \ lp_setup.c \ + lp_setup_coef.c \ + lp_setup_coef_intrin.c \ lp_setup_line.c \ lp_setup_point.c \ lp_setup_tri.c \ diff --git a/src/gallium/drivers/llvmpipe/SConscript b/src/gallium/drivers/llvmpipe/SConscript index 5583fca38e..8d57db72cf 100644 --- a/src/gallium/drivers/llvmpipe/SConscript +++ b/src/gallium/drivers/llvmpipe/SConscript @@ -63,6 +63,8 @@ llvmpipe = env.ConvenienceLibrary( 'lp_setup_line.c', 'lp_setup_point.c', 'lp_setup_tri.c', + 'lp_setup_coef.c', + 'lp_setup_coef_intrin.c', 'lp_setup_vbuf.c', 'lp_state_blend.c', 'lp_state_clip.c', diff --git a/src/gallium/drivers/llvmpipe/lp_context.c b/src/gallium/drivers/llvmpipe/lp_context.c index 7543bd7b2b..39f2c6085e 100644 --- a/src/gallium/drivers/llvmpipe/lp_context.c +++ b/src/gallium/drivers/llvmpipe/lp_context.c @@ -85,6 +85,14 @@ static void llvmpipe_destroy( struct pipe_context *pipe ) align_free( llvmpipe ); } +static void +do_flush( struct pipe_context *pipe, + unsigned flags, + struct pipe_fence_handle **fence) +{ + llvmpipe_flush(pipe, flags, fence, __FUNCTION__); +} + struct pipe_context * llvmpipe_create_context( struct pipe_screen *screen, void *priv ) @@ -109,7 +117,7 @@ llvmpipe_create_context( struct pipe_screen *screen, void *priv ) llvmpipe->pipe.destroy = llvmpipe_destroy; llvmpipe->pipe.set_framebuffer_state = llvmpipe_set_framebuffer_state; llvmpipe->pipe.clear = llvmpipe_clear; - llvmpipe->pipe.flush = llvmpipe_flush; + llvmpipe->pipe.flush = do_flush; llvmpipe_init_blend_funcs(llvmpipe); llvmpipe_init_clip_funcs(llvmpipe); @@ -147,9 +155,13 @@ llvmpipe_create_context( struct pipe_screen *screen, void *priv ) draw_install_aapoint_stage(llvmpipe->draw, &llvmpipe->pipe); draw_install_pstipple_stage(llvmpipe->draw, &llvmpipe->pipe); - /* convert points and lines into triangles: */ - draw_wide_point_threshold(llvmpipe->draw, 0.0); - draw_wide_line_threshold(llvmpipe->draw, 0.0); + /* convert points and lines into triangles: + * (otherwise, draw points and lines natively) + */ + draw_wide_point_sprites(llvmpipe->draw, FALSE); + draw_enable_point_sprites(llvmpipe->draw, FALSE); + draw_wide_point_threshold(llvmpipe->draw, 10000.0); + draw_wide_line_threshold(llvmpipe->draw, 10000.0); #if USE_DRAW_STAGE_PSTIPPLE /* Do polygon stipple w/ texture map + frag prog? */ diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h index 50f9091c3c..34fa20e204 100644 --- a/src/gallium/drivers/llvmpipe/lp_context.h +++ b/src/gallium/drivers/llvmpipe/lp_context.h @@ -101,6 +101,9 @@ struct llvmpipe_context { /** Vertex format */ struct vertex_info vertex_info; + + /** Which vertex shader output slot contains point size */ + int psize_slot; /** Fragment shader input interpolation info */ unsigned num_inputs; diff --git a/src/gallium/drivers/llvmpipe/lp_debug.h b/src/gallium/drivers/llvmpipe/lp_debug.h index 92fb2b3ee5..a928ee38be 100644 --- a/src/gallium/drivers/llvmpipe/lp_debug.h +++ b/src/gallium/drivers/llvmpipe/lp_debug.h @@ -46,6 +46,8 @@ st_print_current(void); #define DEBUG_SHOW_TILES 0x200 #define DEBUG_SHOW_SUBTILES 0x400 #define DEBUG_COUNTERS 0x800 +#define DEBUG_SCENE 0x1000 +#define DEBUG_FENCE 0x2000 #ifdef DEBUG diff --git a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c index e73b431cb4..3af5c8d5c5 100644 --- a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c +++ b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c @@ -68,25 +68,17 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) } /* Map index buffer, if present */ - if (info->indexed && lp->index_buffer.buffer) { - char *indices = (char *) llvmpipe_resource_data(lp->index_buffer.buffer); - mapped_indices = (void *) (indices + lp->index_buffer.offset); - } + if (info->indexed && lp->index_buffer.buffer) + mapped_indices = llvmpipe_resource_data(lp->index_buffer.buffer); - draw_set_mapped_element_buffer_range(draw, (mapped_indices) ? - lp->index_buffer.index_size : 0, - info->index_bias, - info->min_index, - info->max_index, - mapped_indices); + draw_set_mapped_index_buffer(draw, mapped_indices); llvmpipe_prepare_vertex_sampling(lp, lp->num_vertex_sampler_views, lp->vertex_sampler_views); /* draw! */ - draw_arrays_instanced(draw, info->mode, info->start, info->count, - info->start_instance, info->instance_count); + draw_vbo(draw, info); /* * unmap vertex/index buffers @@ -95,7 +87,7 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) draw_set_mapped_vertex_buffer(draw, i, NULL); } if (mapped_indices) { - draw_set_mapped_element_buffer(draw, 0, 0, NULL); + draw_set_mapped_index_buffer(draw, NULL); } llvmpipe_cleanup_vertex_sampling(lp); diff --git a/src/gallium/drivers/llvmpipe/lp_fence.c b/src/gallium/drivers/llvmpipe/lp_fence.c index f9805e5d68..3a55e76bc3 100644 --- a/src/gallium/drivers/llvmpipe/lp_fence.c +++ b/src/gallium/drivers/llvmpipe/lp_fence.c @@ -44,6 +44,7 @@ struct lp_fence * lp_fence_create(unsigned rank) { + static int fence_id; struct lp_fence *fence = CALLOC_STRUCT(lp_fence); pipe_reference_init(&fence->reference, 1); @@ -51,8 +52,12 @@ lp_fence_create(unsigned rank) pipe_mutex_init(fence->mutex); pipe_condvar_init(fence->signalled); + fence->id = fence_id++; fence->rank = rank; + if (LP_DEBUG & DEBUG_FENCE) + debug_printf("%s %d\n", __FUNCTION__, fence->id); + return fence; } @@ -61,6 +66,9 @@ lp_fence_create(unsigned rank) void lp_fence_destroy(struct lp_fence *fence) { + if (LP_DEBUG & DEBUG_FENCE) + debug_printf("%s %d\n", __FUNCTION__, fence->id); + pipe_mutex_destroy(fence->mutex); pipe_condvar_destroy(fence->signalled); FREE(fence); @@ -68,82 +76,49 @@ lp_fence_destroy(struct lp_fence *fence) /** - * For reference counting. - * This is a Gallium API function. - */ -static void -llvmpipe_fence_reference(struct pipe_screen *screen, - struct pipe_fence_handle **ptr, - struct pipe_fence_handle *fence) -{ - struct lp_fence **old = (struct lp_fence **) ptr; - struct lp_fence *f = (struct lp_fence *) fence; - - lp_fence_reference(old, f); -} - - -/** - * Has the fence been executed/finished? - * This is a Gallium API function. - */ -static int -llvmpipe_fence_signalled(struct pipe_screen *screen, - struct pipe_fence_handle *fence, - unsigned flag) -{ - struct lp_fence *f = (struct lp_fence *) fence; - - return f->count == f->rank; -} - - -/** - * Wait for the fence to finish. - * This is a Gallium API function. - */ -static int -llvmpipe_fence_finish(struct pipe_screen *screen, - struct pipe_fence_handle *fence_handle, - unsigned flag) -{ - struct lp_fence *fence = (struct lp_fence *) fence_handle; - - pipe_mutex_lock(fence->mutex); - while (fence->count < fence->rank) { - pipe_condvar_wait(fence->signalled, fence->mutex); - } - pipe_mutex_unlock(fence->mutex); - - return 0; -} - - -/** * Called by the rendering threads to increment the fence counter. * When the counter == the rank, the fence is finished. */ void lp_fence_signal(struct lp_fence *fence) { + if (LP_DEBUG & DEBUG_FENCE) + debug_printf("%s %d\n", __FUNCTION__, fence->id); + pipe_mutex_lock(fence->mutex); fence->count++; assert(fence->count <= fence->rank); - LP_DBG(DEBUG_RAST, "%s count=%u rank=%u\n", __FUNCTION__, - fence->count, fence->rank); + if (LP_DEBUG & DEBUG_FENCE) + debug_printf("%s count=%u rank=%u\n", __FUNCTION__, + fence->count, fence->rank); - pipe_condvar_signal(fence->signalled); + /* Wakeup all threads waiting on the mutex: + */ + pipe_condvar_broadcast(fence->signalled); pipe_mutex_unlock(fence->mutex); } +boolean +lp_fence_signalled(struct lp_fence *f) +{ + return f->count == f->rank; +} void -llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen) +lp_fence_wait(struct lp_fence *f) { - screen->fence_reference = llvmpipe_fence_reference; - screen->fence_signalled = llvmpipe_fence_signalled; - screen->fence_finish = llvmpipe_fence_finish; + if (LP_DEBUG & DEBUG_FENCE) + debug_printf("%s %d\n", __FUNCTION__, f->id); + + pipe_mutex_lock(f->mutex); + assert(f->issued); + while (f->count < f->rank) { + pipe_condvar_wait(f->signalled, f->mutex); + } + pipe_mutex_unlock(f->mutex); } + + diff --git a/src/gallium/drivers/llvmpipe/lp_fence.h b/src/gallium/drivers/llvmpipe/lp_fence.h index 13358fb99f..3c59118780 100644 --- a/src/gallium/drivers/llvmpipe/lp_fence.h +++ b/src/gallium/drivers/llvmpipe/lp_fence.h @@ -41,10 +41,12 @@ struct pipe_screen; struct lp_fence { struct pipe_reference reference; + unsigned id; pipe_mutex mutex; pipe_condvar signalled; + boolean issued; unsigned rank; unsigned count; }; @@ -57,6 +59,11 @@ lp_fence_create(unsigned rank); void lp_fence_signal(struct lp_fence *fence); +boolean +lp_fence_signalled(struct lp_fence *fence); + +void +lp_fence_wait(struct lp_fence *fence); void llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen); @@ -78,5 +85,11 @@ lp_fence_reference(struct lp_fence **ptr, *ptr = f; } +static INLINE boolean +lp_fence_issued(const struct lp_fence *fence) +{ + return fence->issued; +} + #endif /* LP_FENCE_H */ diff --git a/src/gallium/drivers/llvmpipe/lp_flush.c b/src/gallium/drivers/llvmpipe/lp_flush.c index 845292f4ab..e2c723b7a8 100644 --- a/src/gallium/drivers/llvmpipe/lp_flush.c +++ b/src/gallium/drivers/llvmpipe/lp_flush.c @@ -31,6 +31,7 @@ #include "pipe/p_defines.h" +#include "pipe/p_screen.h" #include "util/u_string.h" #include "draw/draw_context.h" #include "lp_flush.h" @@ -45,14 +46,15 @@ void llvmpipe_flush( struct pipe_context *pipe, unsigned flags, - struct pipe_fence_handle **fence ) + struct pipe_fence_handle **fence, + const char *reason) { struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe); draw_flush(llvmpipe->draw); /* ask the setup module to flush */ - lp_setup_flush(llvmpipe->setup, flags, fence); + lp_setup_flush(llvmpipe->setup, flags, fence, reason); /* Enable to dump BMPs of the color/depth buffers each frame */ if (0) { @@ -76,6 +78,17 @@ llvmpipe_flush( struct pipe_context *pipe, } } +void +llvmpipe_finish( struct pipe_context *pipe, + const char *reason ) +{ + struct pipe_fence_handle *fence = NULL; + llvmpipe_flush(pipe, 0, &fence, reason); + if (fence) { + pipe->screen->fence_finish(pipe->screen, fence, 0); + pipe->screen->fence_reference(pipe->screen, &fence, NULL); + } +} /** * Flush context if necessary. @@ -93,7 +106,8 @@ llvmpipe_flush_resource(struct pipe_context *pipe, unsigned flush_flags, boolean read_only, boolean cpu_access, - boolean do_not_block) + boolean do_not_block, + const char *reason) { unsigned referenced; @@ -106,31 +120,16 @@ llvmpipe_flush_resource(struct pipe_context *pipe, /* * Flush and wait. */ - - struct pipe_fence_handle *fence = NULL; - if (do_not_block) return FALSE; - /* - * Do the unswizzling in parallel. - * - * XXX: Don't abuse the PIPE_FLUSH_FRAME flag for this. - */ - flush_flags |= PIPE_FLUSH_FRAME; - - llvmpipe_flush(pipe, flush_flags, &fence); - - if (fence) { - pipe->screen->fence_finish(pipe->screen, fence, 0); - pipe->screen->fence_reference(pipe->screen, &fence, NULL); - } + llvmpipe_finish(pipe, reason); } else { /* * Just flush. */ - llvmpipe_flush(pipe, flush_flags, NULL); + llvmpipe_flush(pipe, flush_flags, NULL, reason); } } diff --git a/src/gallium/drivers/llvmpipe/lp_flush.h b/src/gallium/drivers/llvmpipe/lp_flush.h index 7b605681a9..bb538b2bd8 100644 --- a/src/gallium/drivers/llvmpipe/lp_flush.h +++ b/src/gallium/drivers/llvmpipe/lp_flush.h @@ -34,8 +34,14 @@ struct pipe_context; struct pipe_fence_handle; void -llvmpipe_flush(struct pipe_context *pipe, unsigned flags, - struct pipe_fence_handle **fence); +llvmpipe_flush(struct pipe_context *pipe, + unsigned flags, + struct pipe_fence_handle **fence, + const char *reason); + +void +llvmpipe_finish( struct pipe_context *pipe, + const char *reason ); boolean llvmpipe_flush_resource(struct pipe_context *pipe, @@ -45,6 +51,7 @@ llvmpipe_flush_resource(struct pipe_context *pipe, unsigned flush_flags, boolean read_only, boolean cpu_access, - boolean do_not_block); + boolean do_not_block, + const char *reason); #endif diff --git a/src/gallium/drivers/llvmpipe/lp_perf.c b/src/gallium/drivers/llvmpipe/lp_perf.c index 083e7e30a5..e22532f25c 100644 --- a/src/gallium/drivers/llvmpipe/lp_perf.c +++ b/src/gallium/drivers/llvmpipe/lp_perf.c @@ -46,7 +46,7 @@ lp_print_counters(void) { if (LP_DEBUG & DEBUG_COUNTERS) { unsigned total_64, total_16, total_4; - float p1, p2, p3, p4; + float p1, p2, p3, p5, p6; debug_printf("llvmpipe: nr_triangles: %9u\n", lp_count.nr_tris); debug_printf("llvmpipe: nr_culled_triangles: %9u\n", lp_count.nr_culled_tris); @@ -58,11 +58,15 @@ lp_print_counters(void) p1 = 100.0 * (float) lp_count.nr_empty_64 / (float) total_64; p2 = 100.0 * (float) lp_count.nr_fully_covered_64 / (float) total_64; p3 = 100.0 * (float) lp_count.nr_partially_covered_64 / (float) total_64; - p4 = 100.0 * (float) lp_count.nr_shade_opaque_64 / (float) total_64; + p5 = 100.0 * (float) lp_count.nr_shade_opaque_64 / (float) total_64; + p6 = 100.0 * (float) lp_count.nr_shade_64 / (float) total_64; debug_printf("llvmpipe: nr_64x64: %9u\n", total_64); debug_printf("llvmpipe: nr_fully_covered_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_fully_covered_64, p2, total_64); - debug_printf("llvmpipe: nr_shade_opaque_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_shade_opaque_64, p4, total_64); + debug_printf("llvmpipe: nr_shade_opaque_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_shade_opaque_64, p5, total_64); + debug_printf("llvmpipe: nr_pure_shade_opaque: %9u (%3.0f%% of %u)\n", lp_count.nr_pure_shade_opaque_64, 0.0, lp_count.nr_shade_opaque_64); + debug_printf("llvmpipe: nr_shade_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_shade_64, p6, total_64); + debug_printf("llvmpipe: nr_pure_shade: %9u (%3.0f%% of %u)\n", lp_count.nr_pure_shade_64, 0.0, lp_count.nr_shade_64); debug_printf("llvmpipe: nr_partially_covered_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_partially_covered_64, p3, total_64); debug_printf("llvmpipe: nr_empty_64x64: %9u (%3.0f%% of %u)\n", lp_count.nr_empty_64, p1, total_64); @@ -79,12 +83,17 @@ lp_print_counters(void) debug_printf("llvmpipe: nr_partially_covered_16x16: %9u (%3.0f%% of %u)\n", lp_count.nr_partially_covered_16, p3, total_16); debug_printf("llvmpipe: nr_empty_16x16: %9u (%3.0f%% of %u)\n", lp_count.nr_empty_16, p1, total_16); - total_4 = (lp_count.nr_empty_4 + lp_count.nr_non_empty_4); + total_4 = (lp_count.nr_empty_4 + + lp_count.nr_fully_covered_4 + + lp_count.nr_partially_covered_4); p1 = 100.0 * (float) lp_count.nr_empty_4 / (float) total_4; - p2 = 100.0 * (float) lp_count.nr_non_empty_4 / (float) total_4; + p2 = 100.0 * (float) lp_count.nr_fully_covered_4 / (float) total_4; + p3 = 100.0 * (float) lp_count.nr_partially_covered_4 / (float) total_4; - debug_printf("llvmpipe: nr_4x4: %9u\n", total_4); + debug_printf("llvmpipe: nr_tri_4x4: %9u\n", total_4); + debug_printf("llvmpipe: nr_fully_covered_4x4: %9u (%3.0f%% of %u)\n", lp_count.nr_fully_covered_4, p2, total_4); + debug_printf("llvmpipe: nr_partially_covered_4x4: %9u (%3.0f%% of %u)\n", lp_count.nr_partially_covered_4, p3, total_4); debug_printf("llvmpipe: nr_empty_4x4: %9u (%3.0f%% of %u)\n", lp_count.nr_empty_4, p1, total_4); debug_printf("llvmpipe: nr_non_empty_4x4: %9u (%3.0f%% of %u)\n", lp_count.nr_non_empty_4, p2, total_4); diff --git a/src/gallium/drivers/llvmpipe/lp_perf.h b/src/gallium/drivers/llvmpipe/lp_perf.h index 4774f64550..c28652fc30 100644 --- a/src/gallium/drivers/llvmpipe/lp_perf.h +++ b/src/gallium/drivers/llvmpipe/lp_perf.h @@ -44,11 +44,16 @@ struct lp_counters unsigned nr_empty_64; unsigned nr_fully_covered_64; unsigned nr_partially_covered_64; + unsigned nr_pure_shade_opaque_64; + unsigned nr_pure_shade_64; + unsigned nr_shade_64; unsigned nr_shade_opaque_64; unsigned nr_empty_16; unsigned nr_fully_covered_16; unsigned nr_partially_covered_16; unsigned nr_empty_4; + unsigned nr_fully_covered_4; + unsigned nr_partially_covered_4; unsigned nr_non_empty_4; unsigned nr_llvm_compiles; int64_t llvm_compile_time; /**< total, in microseconds */ @@ -66,9 +71,11 @@ extern struct lp_counters lp_count; #ifdef DEBUG #define LP_COUNT(counter) lp_count.counter++ #define LP_COUNT_ADD(counter, incr) lp_count.counter += (incr) +#define LP_COUNT_GET(counter) (lp_count.counter) #else #define LP_COUNT(counter) #define LP_COUNT_ADD(counter, incr) (void) incr +#define LP_COUNT_GET(counter) 0 #endif diff --git a/src/gallium/drivers/llvmpipe/lp_query.c b/src/gallium/drivers/llvmpipe/lp_query.c index 02eeaf6487..67fd797af2 100644 --- a/src/gallium/drivers/llvmpipe/lp_query.c +++ b/src/gallium/drivers/llvmpipe/lp_query.c @@ -35,9 +35,8 @@ #include "util/u_memory.h" #include "lp_context.h" #include "lp_flush.h" +#include "lp_fence.h" #include "lp_query.h" -#include "lp_rast.h" -#include "lp_rast_priv.h" #include "lp_state.h" @@ -69,12 +68,7 @@ llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q) struct llvmpipe_query *pq = llvmpipe_query(q); /* query might still be in process if we never waited for the result */ if (!pq->done) { - struct pipe_fence_handle *fence = NULL; - llvmpipe_flush(pipe, 0, &fence); - if (fence) { - pipe->screen->fence_finish(pipe->screen, fence, 0); - pipe->screen->fence_reference(pipe->screen, &fence, NULL); - } + llvmpipe_finish(pipe, __FUNCTION__); } pipe_mutex_destroy(pq->mutex); @@ -93,16 +87,11 @@ llvmpipe_get_query_result(struct pipe_context *pipe, if (!pq->done) { if (wait) { - struct pipe_fence_handle *fence = NULL; - llvmpipe_flush(pipe, 0, &fence); - if (fence) { - pipe->screen->fence_finish(pipe->screen, fence, 0); - pipe->screen->fence_reference(pipe->screen, &fence, NULL); - } + llvmpipe_finish(pipe, __FUNCTION__); } /* this is a bit inconsequent but should be ok */ else { - llvmpipe_flush(pipe, 0, NULL); + llvmpipe_flush(pipe, 0, NULL, __FUNCTION__); } } @@ -125,12 +114,7 @@ llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q) * frame of rendering. */ if (pq->binned) { - struct pipe_fence_handle *fence; - llvmpipe_flush(pipe, 0, &fence); - if (fence) { - pipe->screen->fence_finish(pipe->screen, fence, 0); - pipe->screen->fence_reference(pipe->screen, &fence, NULL); - } + llvmpipe_finish(pipe, __FUNCTION__); } lp_setup_begin_query(llvmpipe->setup, pq); diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c index 3215d0f652..b1c306bbe9 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast.c +++ b/src/gallium/drivers/llvmpipe/lp_rast.c @@ -316,43 +316,6 @@ lp_rast_clear_zstencil(struct lp_rasterizer_task *task, } -/** - * Load tile color from the framebuffer surface. - * This is a bin command called during bin processing. - */ -#if 0 -void -lp_rast_load_color(struct lp_rasterizer_task *task, - const union lp_rast_cmd_arg arg) -{ - struct lp_rasterizer *rast = task->rast; - unsigned buf; - enum lp_texture_usage usage; - - LP_DBG(DEBUG_RAST, "%s at %u, %u\n", __FUNCTION__, x, y); - - if (scene->has_color_clear) - usage = LP_TEX_USAGE_WRITE_ALL; - else - usage = LP_TEX_USAGE_READ_WRITE; - - /* Get pointers to color tile(s). - * This will convert linear data to tiled if needed. - */ - for (buf = 0; buf < rast->state.nr_cbufs; buf++) { - struct pipe_surface *cbuf = rast->curr_scene->fb.cbufs[buf]; - struct llvmpipe_texture *lpt; - assert(cbuf); - lpt = llvmpipe_texture(cbuf->texture); - task->color_tiles[buf] = llvmpipe_get_texture_tile(lpt, - cbuf->face + cbuf->zslice, - cbuf->level, - usage, - task->x, task->y); - assert(task->color_tiles[buf]); - } -} -#endif /** diff --git a/src/gallium/drivers/llvmpipe/lp_rast.h b/src/gallium/drivers/llvmpipe/lp_rast.h index 44319a0ad6..b4564ef33b 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast.h +++ b/src/gallium/drivers/llvmpipe/lp_rast.h @@ -120,7 +120,7 @@ struct lp_rast_triangle { float v[3][2]; #endif - struct lp_rast_plane plane[7]; /* NOTE: may allocate fewer planes */ + struct lp_rast_plane plane[8]; /* NOTE: may allocate fewer planes */ }; @@ -236,6 +236,8 @@ void lp_rast_triangle_6( struct lp_rasterizer_task *, const union lp_rast_cmd_arg ); void lp_rast_triangle_7( struct lp_rasterizer_task *, const union lp_rast_cmd_arg ); +void lp_rast_triangle_8( struct lp_rasterizer_task *, + const union lp_rast_cmd_arg ); void lp_rast_shade_tile( struct lp_rasterizer_task *, const union lp_rast_cmd_arg ); @@ -256,5 +258,9 @@ void lp_rast_begin_query(struct lp_rasterizer_task *, void lp_rast_end_query(struct lp_rasterizer_task *, const union lp_rast_cmd_arg ); +void +lp_rast_triangle_3_16(struct lp_rasterizer_task *task, + const union lp_rast_cmd_arg arg); + #endif diff --git a/src/gallium/drivers/llvmpipe/lp_rast_tri.c b/src/gallium/drivers/llvmpipe/lp_rast_tri.c index 980c18c024..dbaa8e023a 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast_tri.c +++ b/src/gallium/drivers/llvmpipe/lp_rast_tri.c @@ -67,7 +67,7 @@ block_full_16(struct lp_rasterizer_task *task, block_full_4(task, tri, x + ix, y + iy); } - +#if !defined(PIPE_ARCH_SSE) static INLINE unsigned build_mask(int c, int dcdx, int dcdy) { @@ -98,6 +98,7 @@ build_mask(int c, int dcdx, int dcdy) return mask; } + static INLINE unsigned build_mask_linear(int c, int dcdx, int dcdy) { @@ -129,6 +130,137 @@ build_mask_linear(int c, int dcdx, int dcdy) } +static INLINE void +build_masks(int c, + int cdiff, + int dcdx, + int dcdy, + unsigned *outmask, + unsigned *partmask) +{ + *outmask |= build_mask_linear(c, dcdx, dcdy); + *partmask |= build_mask_linear(c + cdiff, dcdx, dcdy); +} + +#else +#include <emmintrin.h> +#include "util/u_sse.h" + + +static INLINE void +build_masks(int c, + int cdiff, + int dcdx, + int dcdy, + unsigned *outmask, + unsigned *partmask) +{ + __m128i cstep0 = _mm_setr_epi32(c, c+dcdx, c+dcdx*2, c+dcdx*3); + __m128i xdcdy = _mm_set1_epi32(dcdy); + + /* Get values across the quad + */ + __m128i cstep1 = _mm_add_epi32(cstep0, xdcdy); + __m128i cstep2 = _mm_add_epi32(cstep1, xdcdy); + __m128i cstep3 = _mm_add_epi32(cstep2, xdcdy); + + { + __m128i cstep01, cstep23, result; + + cstep01 = _mm_packs_epi32(cstep0, cstep1); + cstep23 = _mm_packs_epi32(cstep2, cstep3); + result = _mm_packs_epi16(cstep01, cstep23); + + *outmask |= _mm_movemask_epi8(result); + } + + + { + __m128i cio4 = _mm_set1_epi32(cdiff); + __m128i cstep01, cstep23, result; + + cstep0 = _mm_add_epi32(cstep0, cio4); + cstep1 = _mm_add_epi32(cstep1, cio4); + cstep2 = _mm_add_epi32(cstep2, cio4); + cstep3 = _mm_add_epi32(cstep3, cio4); + + cstep01 = _mm_packs_epi32(cstep0, cstep1); + cstep23 = _mm_packs_epi32(cstep2, cstep3); + result = _mm_packs_epi16(cstep01, cstep23); + + *partmask |= _mm_movemask_epi8(result); + } +} + + +static INLINE unsigned +build_mask_linear(int c, int dcdx, int dcdy) +{ + __m128i cstep0 = _mm_setr_epi32(c, c+dcdx, c+dcdx*2, c+dcdx*3); + __m128i xdcdy = _mm_set1_epi32(dcdy); + + /* Get values across the quad + */ + __m128i cstep1 = _mm_add_epi32(cstep0, xdcdy); + __m128i cstep2 = _mm_add_epi32(cstep1, xdcdy); + __m128i cstep3 = _mm_add_epi32(cstep2, xdcdy); + + /* pack pairs of results into epi16 + */ + __m128i cstep01 = _mm_packs_epi32(cstep0, cstep1); + __m128i cstep23 = _mm_packs_epi32(cstep2, cstep3); + + /* pack into epi8, preserving sign bits + */ + __m128i result = _mm_packs_epi16(cstep01, cstep23); + + /* extract sign bits to create mask + */ + return _mm_movemask_epi8(result); +} + +static INLINE unsigned +build_mask(int c, int dcdx, int dcdy) +{ + __m128i step = _mm_setr_epi32(0, dcdx, dcdy, dcdx + dcdy); + __m128i c0 = _mm_set1_epi32(c); + + /* Get values across the quad + */ + __m128i cstep0 = _mm_add_epi32(c0, step); + + /* Scale up step for moving between quads. + */ + __m128i step4 = _mm_add_epi32(step, step); + + /* Get values for the remaining quads: + */ + __m128i cstep1 = _mm_add_epi32(cstep0, + _mm_shuffle_epi32(step4, _MM_SHUFFLE(1,1,1,1))); + __m128i cstep2 = _mm_add_epi32(cstep0, + _mm_shuffle_epi32(step4, _MM_SHUFFLE(2,2,2,2))); + __m128i cstep3 = _mm_add_epi32(cstep2, + _mm_shuffle_epi32(step4, _MM_SHUFFLE(1,1,1,1))); + + /* pack pairs of results into epi16 + */ + __m128i cstep01 = _mm_packs_epi32(cstep0, cstep1); + __m128i cstep23 = _mm_packs_epi32(cstep2, cstep3); + + /* pack into epi8, preserving sign bits + */ + __m128i result = _mm_packs_epi16(cstep01, cstep23); + + /* extract sign bits to create mask + */ + return _mm_movemask_epi8(result); +} + +#endif + + + + #define TAG(x) x##_1 #define NR_PLANES 1 #include "lp_rast_tri_tmp.h" @@ -157,3 +289,92 @@ build_mask_linear(int c, int dcdx, int dcdy) #define NR_PLANES 7 #include "lp_rast_tri_tmp.h" +#define TAG(x) x##_8 +#define NR_PLANES 8 +#include "lp_rast_tri_tmp.h" + + +/* Special case for 3 plane triangle which is contained entirely + * within a 16x16 block. + */ +void +lp_rast_triangle_3_16(struct lp_rasterizer_task *task, + const union lp_rast_cmd_arg arg) +{ + const struct lp_rast_triangle *tri = arg.triangle.tri; + const struct lp_rast_plane *plane = tri->plane; + unsigned mask = arg.triangle.plane_mask; + const int x = task->x + (mask & 0xf) * 16; + const int y = task->y + (mask >> 4) * 16; + unsigned outmask, inmask, partmask, partial_mask; + unsigned j; + int c[3]; + + outmask = 0; /* outside one or more trivial reject planes */ + partmask = 0; /* outside one or more trivial accept planes */ + + for (j = 0; j < 3; j++) { + c[j] = plane[j].c + plane[j].dcdy * y - plane[j].dcdx * x; + + { + const int dcdx = -plane[j].dcdx * 4; + const int dcdy = plane[j].dcdy * 4; + const int cox = plane[j].eo * 4; + const int cio = plane[j].ei * 4 - 1; + + build_masks(c[j] + cox, + cio - cox, + dcdx, dcdy, + &outmask, /* sign bits from c[i][0..15] + cox */ + &partmask); /* sign bits from c[i][0..15] + cio */ + } + } + + if (outmask == 0xffff) + return; + + /* Mask of sub-blocks which are inside all trivial accept planes: + */ + inmask = ~partmask & 0xffff; + + /* Mask of sub-blocks which are inside all trivial reject planes, + * but outside at least one trivial accept plane: + */ + partial_mask = partmask & ~outmask; + + assert((partial_mask & inmask) == 0); + + /* Iterate over partials: + */ + while (partial_mask) { + int i = ffs(partial_mask) - 1; + int ix = (i & 3) * 4; + int iy = (i >> 2) * 4; + int px = x + ix; + int py = y + iy; + int cx[3]; + + partial_mask &= ~(1 << i); + + for (j = 0; j < 3; j++) + cx[j] = (c[j] + - plane[j].dcdx * ix + + plane[j].dcdy * iy); + + do_block_4_3(task, tri, plane, px, py, cx); + } + + /* Iterate over fulls: + */ + while (inmask) { + int i = ffs(inmask) - 1; + int ix = (i & 3) * 4; + int iy = (i >> 2) * 4; + int px = x + ix; + int py = y + iy; + + inmask &= ~(1 << i); + + block_full_4(task, tri, px, py); + } +} diff --git a/src/gallium/drivers/llvmpipe/lp_rast_tri_tmp.h b/src/gallium/drivers/llvmpipe/lp_rast_tri_tmp.h index 43f72d8ca8..99a0bae45d 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast_tri_tmp.h +++ b/src/gallium/drivers/llvmpipe/lp_rast_tri_tmp.h @@ -32,7 +32,7 @@ /** - * Prototype for a 7 plane rasterizer function. Will codegenerate + * Prototype for a 8 plane rasterizer function. Will codegenerate * several of these. * * XXX: Varients for more/fewer planes. @@ -81,11 +81,14 @@ TAG(do_block_16)(struct lp_rasterizer_task *task, for (j = 0; j < NR_PLANES; j++) { const int dcdx = -plane[j].dcdx * 4; const int dcdy = plane[j].dcdy * 4; - const int cox = c[j] + plane[j].eo * 4; - const int cio = c[j] + plane[j].ei * 4 - 1; - - outmask |= build_mask_linear(cox, dcdx, dcdy); - partmask |= build_mask_linear(cio, dcdx, dcdy); + const int cox = plane[j].eo * 4; + const int cio = plane[j].ei * 4 - 1; + + build_masks(c[j] + cox, + cio - cox, + dcdx, dcdy, + &outmask, /* sign bits from c[i][0..15] + cox */ + &partmask); /* sign bits from c[i][0..15] + cio */ } if (outmask == 0xffff) @@ -102,6 +105,8 @@ TAG(do_block_16)(struct lp_rasterizer_task *task, assert((partial_mask & inmask) == 0); + LP_COUNT_ADD(nr_empty_4, util_bitcount(0xffff & ~(partial_mask | inmask))); + /* Iterate over partials: */ while (partial_mask) { @@ -114,6 +119,8 @@ TAG(do_block_16)(struct lp_rasterizer_task *task, partial_mask &= ~(1 << i); + LP_COUNT(nr_partially_covered_4); + for (j = 0; j < NR_PLANES; j++) cx[j] = (c[j] - plane[j].dcdx * ix @@ -133,6 +140,7 @@ TAG(do_block_16)(struct lp_rasterizer_task *task, inmask &= ~(1 << i); + LP_COUNT(nr_fully_covered_4); block_full_4(task, tri, px, py); } } @@ -166,11 +174,14 @@ TAG(lp_rast_triangle)(struct lp_rasterizer_task *task, { const int dcdx = -plane[j].dcdx * 16; const int dcdy = plane[j].dcdy * 16; - const int cox = c[j] + plane[j].eo * 16; - const int cio = c[j] + plane[j].ei * 16 - 1; - - outmask |= build_mask_linear(cox, dcdx, dcdy); - partmask |= build_mask_linear(cio, dcdx, dcdy); + const int cox = plane[j].eo * 16; + const int cio = plane[j].ei * 16 - 1; + + build_masks(c[j] + cox, + cio - cox, + dcdx, dcdy, + &outmask, /* sign bits from c[i][0..15] + cox */ + &partmask); /* sign bits from c[i][0..15] + cio */ } j++; @@ -190,6 +201,8 @@ TAG(lp_rast_triangle)(struct lp_rasterizer_task *task, assert((partial_mask & inmask) == 0); + LP_COUNT_ADD(nr_empty_16, util_bitcount(0xffff & ~(partial_mask | inmask))); + /* Iterate over partials: */ while (partial_mask) { diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c index f88a759fe7..15a09b7100 100644 --- a/src/gallium/drivers/llvmpipe/lp_scene.c +++ b/src/gallium/drivers/llvmpipe/lp_scene.c @@ -163,12 +163,15 @@ lp_scene_reset(struct lp_scene *scene ) /* Free all but last binner command lists: */ - for (i = 0; i < TILES_X; i++) { - for (j = 0; j < TILES_Y; j++) { + for (i = 0; i < scene->tiles_x; i++) { + for (j = 0; j < scene->tiles_y; j++) { lp_scene_bin_reset(scene, i, j); } } + /* If there are any bins which weren't cleared by the loop above, + * they will be caught (on debug builds at least) by this assert: + */ assert(lp_scene_is_empty(scene)); /* Free all but last binned data block: diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c index 167cb2ee2e..1e65a91fc6 100644 --- a/src/gallium/drivers/llvmpipe/lp_screen.c +++ b/src/gallium/drivers/llvmpipe/lp_screen.c @@ -61,6 +61,8 @@ static const struct debug_named_value lp_debug_flags[] = { { "show_tiles", DEBUG_SHOW_TILES, NULL }, { "show_subtiles", DEBUG_SHOW_SUBTILES, NULL }, { "counters", DEBUG_COUNTERS, NULL }, + { "scene", DEBUG_SCENE, NULL }, + { "fence", DEBUG_FENCE, NULL }, DEBUG_NAMED_VALUE_END }; #endif @@ -87,7 +89,14 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param) case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS: return PIPE_MAX_SAMPLERS; case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS: - return PIPE_MAX_VERTEX_SAMPLERS; + /* At this time, the draw module and llvmpipe driver only + * support vertex shader texture lookups when LLVM is enabled in + * the draw module. + */ + if (debug_get_bool_option("DRAW_USE_LLVM", TRUE)) + return PIPE_MAX_VERTEX_SAMPLERS; + else + return 0; case PIPE_CAP_MAX_COMBINED_SAMPLERS: return PIPE_MAX_SAMPLERS + PIPE_MAX_VERTEX_SAMPLERS; case PIPE_CAP_NPOT_TEXTURES: @@ -230,6 +239,7 @@ llvmpipe_is_format_supported( struct pipe_screen *_screen, assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_2D || + target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE); @@ -314,6 +324,51 @@ llvmpipe_destroy_screen( struct pipe_screen *_screen ) + +/** + * Fence reference counting. + */ +static void +llvmpipe_fence_reference(struct pipe_screen *screen, + struct pipe_fence_handle **ptr, + struct pipe_fence_handle *fence) +{ + struct lp_fence **old = (struct lp_fence **) ptr; + struct lp_fence *f = (struct lp_fence *) fence; + + lp_fence_reference(old, f); +} + + +/** + * Has the fence been executed/finished? + */ +static int +llvmpipe_fence_signalled(struct pipe_screen *screen, + struct pipe_fence_handle *fence, + unsigned flag) +{ + struct lp_fence *f = (struct lp_fence *) fence; + return lp_fence_signalled(f); +} + + +/** + * Wait for the fence to finish. + */ +static int +llvmpipe_fence_finish(struct pipe_screen *screen, + struct pipe_fence_handle *fence_handle, + unsigned flag) +{ + struct lp_fence *f = (struct lp_fence *) fence_handle; + + lp_fence_wait(f); + return 0; +} + + + /** * Create a new pipe_screen object * Note: we're not presently subclassing pipe_screen (no llvmpipe_screen). @@ -351,9 +406,11 @@ llvmpipe_create_screen(struct sw_winsys *winsys) screen->base.context_create = llvmpipe_create_context; screen->base.flush_frontbuffer = llvmpipe_flush_frontbuffer; + screen->base.fence_reference = llvmpipe_fence_reference; + screen->base.fence_signalled = llvmpipe_fence_signalled; + screen->base.fence_finish = llvmpipe_fence_finish; llvmpipe_init_screen_resource_funcs(&screen->base); - llvmpipe_init_screen_fence_funcs(&screen->base); lp_jit_screen_init(screen); diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c index 556e571585..3da9097154 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.c +++ b/src/gallium/drivers/llvmpipe/lp_setup.c @@ -275,9 +275,10 @@ set_scene_state( struct lp_setup_context *setup, void lp_setup_flush( struct lp_setup_context *setup, unsigned flags, - struct pipe_fence_handle **fence) + struct pipe_fence_handle **fence, + const char *reason) { - LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); + LP_DBG(DEBUG_SETUP, "%s %s\n", __FUNCTION__, reason); if (setup->scene) { if (fence) { @@ -287,6 +288,8 @@ lp_setup_flush( struct lp_setup_context *setup, *fence = lp_setup_fence( setup ); } + if (setup->scene->fence) + setup->scene->fence->issued = TRUE; } set_scene_state( setup, SETUP_FLUSHED ); @@ -312,6 +315,11 @@ lp_setup_bind_framebuffer( struct lp_setup_context *setup, * scene. */ util_copy_framebuffer_state(&setup->fb, fb); + setup->framebuffer.x0 = 0; + setup->framebuffer.y0 = 0; + setup->framebuffer.x1 = fb->width-1; + setup->framebuffer.y1 = fb->height-1; + setup->dirty |= LP_SETUP_NEW_SCISSOR; } @@ -469,11 +477,35 @@ lp_setup_set_triangle_state( struct lp_setup_context *setup, setup->ccw_is_frontface = ccw_is_frontface; setup->cullmode = cull_mode; setup->triangle = first_triangle; - setup->scissor_test = scissor; setup->pixel_offset = gl_rasterization_rules ? 0.5f : 0.0f; + + if (setup->scissor_test != scissor) { + setup->dirty |= LP_SETUP_NEW_SCISSOR; + setup->scissor_test = scissor; + } } +void +lp_setup_set_line_state( struct lp_setup_context *setup, + float line_width) +{ + LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); + setup->line_width = line_width; +} + +void +lp_setup_set_point_state( struct lp_setup_context *setup, + float point_size, + boolean point_size_per_vertex, + uint sprite) +{ + LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); + + setup->point_size = point_size; + setup->sprite = sprite; + setup->point_size_per_vertex = point_size_per_vertex; +} void lp_setup_set_fs_inputs( struct lp_setup_context *setup, @@ -559,10 +591,11 @@ lp_setup_set_scissor( struct lp_setup_context *setup, assert(scissor); - if (memcmp(&setup->scissor.current, scissor, sizeof(*scissor)) != 0) { - setup->scissor.current = *scissor; /* struct copy */ - setup->dirty |= LP_SETUP_NEW_SCISSOR; - } + setup->scissor.x0 = scissor->minx; + setup->scissor.x1 = scissor->maxx-1; + setup->scissor.y0 = scissor->miny; + setup->scissor.y1 = scissor->maxy-1; + setup->dirty |= LP_SETUP_NEW_SCISSOR; } @@ -713,6 +746,12 @@ lp_setup_update_state( struct lp_setup_context *setup ) */ { struct llvmpipe_context *lp = llvmpipe_context(scene->pipe); + + /* Will probably need to move this somewhere else, just need + * to know about vertex shader point size attribute. + */ + setup->psize = lp->psize_slot; + if (lp->dirty) { llvmpipe_update_derived(lp); } @@ -806,6 +845,14 @@ lp_setup_update_state( struct lp_setup_context *setup ) } } + if (setup->dirty & LP_SETUP_NEW_SCISSOR) { + setup->draw_region = setup->framebuffer; + if (setup->scissor_test) { + u_rect_possible_intersection(&setup->scissor, + &setup->draw_region); + } + } + setup->dirty = 0; assert(setup->fs.stored); diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h index 73b1c85325..821ebb1087 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.h +++ b/src/gallium/drivers/llvmpipe/lp_setup.h @@ -85,7 +85,8 @@ lp_setup_fence( struct lp_setup_context *setup ); void lp_setup_flush( struct lp_setup_context *setup, unsigned flags, - struct pipe_fence_handle **fence); + struct pipe_fence_handle **fence, + const char *reason); void @@ -99,6 +100,16 @@ lp_setup_set_triangle_state( struct lp_setup_context *setup, boolean scissor, boolean gl_rasterization_rules ); +void +lp_setup_set_line_state( struct lp_setup_context *setup, + float line_width); + +void +lp_setup_set_point_state( struct lp_setup_context *setup, + float point_size, + boolean point_size_per_vertex, + uint sprite); + void lp_setup_set_fs_inputs( struct lp_setup_context *setup, const struct lp_shader_input *interp, diff --git a/src/gallium/drivers/llvmpipe/lp_setup_coef.c b/src/gallium/drivers/llvmpipe/lp_setup_coef.c new file mode 100644 index 0000000000..95e3e8fffe --- /dev/null +++ b/src/gallium/drivers/llvmpipe/lp_setup_coef.c @@ -0,0 +1,258 @@ +/************************************************************************** + * + * Copyright 2010, VMware. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Binning code for triangles + */ + +#include "util/u_math.h" +#include "util/u_memory.h" +#include "lp_perf.h" +#include "lp_setup_context.h" +#include "lp_setup_coef.h" +#include "lp_rast.h" +#include "lp_state_fs.h" + +#if !defined(PIPE_ARCH_SSE) + +/** + * Compute a0 for a constant-valued coefficient (GL_FLAT shading). + */ +static void constant_coef( struct lp_rast_shader_inputs *inputs, + unsigned slot, + const float value, + unsigned i ) +{ + inputs->a0[slot][i] = value; + inputs->dadx[slot][i] = 0.0f; + inputs->dady[slot][i] = 0.0f; +} + + + +static void linear_coef( struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info, + unsigned slot, + unsigned vert_attr, + unsigned i) +{ + float a0 = info->v0[vert_attr][i]; + float a1 = info->v1[vert_attr][i]; + float a2 = info->v2[vert_attr][i]; + + float da01 = a0 - a1; + float da20 = a2 - a0; + float dadx = (da01 * info->dy20_ooa - info->dy01_ooa * da20); + float dady = (da20 * info->dx01_ooa - info->dx20_ooa * da01); + + inputs->dadx[slot][i] = dadx; + inputs->dady[slot][i] = dady; + + /* calculate a0 as the value which would be sampled for the + * fragment at (0,0), taking into account that we want to sample at + * pixel centers, in other words (0.5, 0.5). + * + * this is neat but unfortunately not a good way to do things for + * triangles with very large values of dadx or dady as it will + * result in the subtraction and re-addition from a0 of a very + * large number, which means we'll end up loosing a lot of the + * fractional bits and precision from a0. the way to fix this is + * to define a0 as the sample at a pixel center somewhere near vmin + * instead - i'll switch to this later. + */ + inputs->a0[slot][i] = a0 - (dadx * info->x0_center + + dady * info->y0_center); +} + + +/** + * Compute a0, dadx and dady for a perspective-corrected interpolant, + * for a triangle. + * We basically multiply the vertex value by 1/w before computing + * the plane coefficients (a0, dadx, dady). + * Later, when we compute the value at a particular fragment position we'll + * divide the interpolated value by the interpolated W at that fragment. + */ +static void perspective_coef( struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info, + unsigned slot, + unsigned vert_attr, + unsigned i) +{ + /* premultiply by 1/w (v[0][3] is always 1/w): + */ + float a0 = info->v0[vert_attr][i] * info->v0[0][3]; + float a1 = info->v1[vert_attr][i] * info->v1[0][3]; + float a2 = info->v2[vert_attr][i] * info->v2[0][3]; + float da01 = a0 - a1; + float da20 = a2 - a0; + float dadx = da01 * info->dy20_ooa - info->dy01_ooa * da20; + float dady = da20 * info->dx01_ooa - info->dx20_ooa * da01; + + inputs->dadx[slot][i] = dadx; + inputs->dady[slot][i] = dady; + inputs->a0[slot][i] = a0 - (dadx * info->x0_center + + dady * info->y0_center); +} + + +/** + * Special coefficient setup for gl_FragCoord. + * X and Y are trivial + * Z and W are copied from position_coef which should have already been computed. + * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask. + */ +static void +setup_fragcoord_coef(struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info, + unsigned slot, + unsigned usage_mask) +{ + /*X*/ + if (usage_mask & TGSI_WRITEMASK_X) { + inputs->a0[slot][0] = 0.0; + inputs->dadx[slot][0] = 1.0; + inputs->dady[slot][0] = 0.0; + } + + /*Y*/ + if (usage_mask & TGSI_WRITEMASK_Y) { + inputs->a0[slot][1] = 0.0; + inputs->dadx[slot][1] = 0.0; + inputs->dady[slot][1] = 1.0; + } + + /*Z*/ + if (usage_mask & TGSI_WRITEMASK_Z) { + linear_coef(inputs, info, slot, 0, 2); + } + + /*W*/ + if (usage_mask & TGSI_WRITEMASK_W) { + linear_coef(inputs, info, slot, 0, 3); + } +} + + +/** + * Setup the fragment input attribute with the front-facing value. + * \param frontface is the triangle front facing? + */ +static void setup_facing_coef( struct lp_rast_shader_inputs *inputs, + unsigned slot, + boolean frontface, + unsigned usage_mask) +{ + /* convert TRUE to 1.0 and FALSE to -1.0 */ + if (usage_mask & TGSI_WRITEMASK_X) + constant_coef( inputs, slot, 2.0f * frontface - 1.0f, 0 ); + + if (usage_mask & TGSI_WRITEMASK_Y) + constant_coef( inputs, slot, 0.0f, 1 ); /* wasted */ + + if (usage_mask & TGSI_WRITEMASK_Z) + constant_coef( inputs, slot, 0.0f, 2 ); /* wasted */ + + if (usage_mask & TGSI_WRITEMASK_W) + constant_coef( inputs, slot, 0.0f, 3 ); /* wasted */ +} + + +/** + * Compute the tri->coef[] array dadx, dady, a0 values. + */ +void lp_setup_tri_coef( struct lp_setup_context *setup, + struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info) +{ + unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ; + unsigned slot; + unsigned i; + + /* setup interpolation for all the remaining attributes: + */ + for (slot = 0; slot < setup->fs.nr_inputs; slot++) { + unsigned vert_attr = setup->fs.input[slot].src_index; + unsigned usage_mask = setup->fs.input[slot].usage_mask; + + switch (setup->fs.input[slot].interp) { + case LP_INTERP_CONSTANT: + if (setup->flatshade_first) { + for (i = 0; i < NUM_CHANNELS; i++) + if (usage_mask & (1 << i)) + constant_coef(inputs, slot+1, info->v0[vert_attr][i], i); + } + else { + for (i = 0; i < NUM_CHANNELS; i++) + if (usage_mask & (1 << i)) + constant_coef(inputs, slot+1, info->v2[vert_attr][i], i); + } + break; + + case LP_INTERP_LINEAR: + for (i = 0; i < NUM_CHANNELS; i++) + if (usage_mask & (1 << i)) + linear_coef(inputs, info, slot+1, vert_attr, i); + break; + + case LP_INTERP_PERSPECTIVE: + for (i = 0; i < NUM_CHANNELS; i++) + if (usage_mask & (1 << i)) + perspective_coef(inputs, info, slot+1, vert_attr, i); + fragcoord_usage_mask |= TGSI_WRITEMASK_W; + break; + + case LP_INTERP_POSITION: + /* + * The generated pixel interpolators will pick up the coeffs from + * slot 0, so all need to ensure that the usage mask is covers all + * usages. + */ + fragcoord_usage_mask |= usage_mask; + break; + + case LP_INTERP_FACING: + setup_facing_coef(inputs, slot+1, info->frontfacing, usage_mask); + break; + + default: + assert(0); + } + } + + /* The internal position input is in slot zero: + */ + setup_fragcoord_coef(inputs, info, 0, fragcoord_usage_mask); +} + +#else +extern void lp_setup_coef_dummy(void); +void lp_setup_coef_dummy(void) +{ +} + +#endif diff --git a/src/glsl/pp/sl_pp_dict.h b/src/gallium/drivers/llvmpipe/lp_setup_coef.h index 875217bd30..d68b39c603 100644 --- a/src/glsl/pp/sl_pp_dict.h +++ b/src/gallium/drivers/llvmpipe/lp_setup_coef.h @@ -1,8 +1,8 @@ /************************************************************************** - * - * Copyright 2009 VMware, Inc. + * + * Copyright 2010 VMware, Inc. * All Rights Reserved. - * + * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including @@ -10,68 +10,52 @@ * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * + * **************************************************************************/ -#ifndef SL_PP_DICT_H -#define SL_PP_DICT_H +/** + * The setup code is concerned with point/line/triangle setup and + * putting commands/data into the bins. + */ -struct sl_pp_context; -struct sl_pp_dict { - int all; +#ifndef LP_SETUP_COEF_H +#define LP_SETUP_COEF_H - int require; - int enable; - int warn; - int disable; - int defined; +struct lp_tri_info { - int ___LINE__; - int ___FILE__; - int ___VERSION__; + float x0_center; + float y0_center; - int optimize; - int debug; + /* turn these into an aligned float[4] */ + float dy01_ooa; + float dy20_ooa; + float dx01_ooa; + float dx20_ooa; - int off; - int on; + const float (*v0)[4]; + const float (*v1)[4]; + const float (*v2)[4]; - int define; - int elif; - int _else; - int endif; - int error; - int extension; - int _if; - int ifdef; - int ifndef; - int line; - int pragma; - int undef; - - int version; - - int _0; - int _1; + boolean frontfacing; /* remove eventually */ }; +void lp_setup_tri_coef( struct lp_setup_context *setup, + struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info); -int -sl_pp_dict_init(struct sl_pp_context *context); - -#endif /* SL_PP_DICT_H */ +#endif diff --git a/src/gallium/drivers/llvmpipe/lp_setup_coef_intrin.c b/src/gallium/drivers/llvmpipe/lp_setup_coef_intrin.c new file mode 100644 index 0000000000..73fb70599c --- /dev/null +++ b/src/gallium/drivers/llvmpipe/lp_setup_coef_intrin.c @@ -0,0 +1,207 @@ +/************************************************************************** + * + * Copyright 2010 VMware. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Binning code for triangles + */ + +#include "util/u_math.h" +#include "util/u_memory.h" +#include "lp_perf.h" +#include "lp_setup_context.h" +#include "lp_setup_coef.h" +#include "lp_rast.h" + +#if defined(PIPE_ARCH_SSE) +#include <emmintrin.h> + + +static void constant_coef4( struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info, + unsigned slot, + const float *attr) +{ + *(__m128 *)inputs->a0[slot] = *(__m128 *)attr; + *(__m128 *)inputs->dadx[slot] = _mm_set1_ps(0.0); + *(__m128 *)inputs->dady[slot] = _mm_set1_ps(0.0); +} + + + +/** + * Setup the fragment input attribute with the front-facing value. + * \param frontface is the triangle front facing? + */ +static void setup_facing_coef( struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info, + unsigned slot ) +{ + /* XXX: just pass frontface directly to the shader, don't bother + * treating it as an input. + */ + __m128 a0 = _mm_setr_ps(info->frontfacing ? 1.0 : -1.0, + 0, 0, 0); + + *(__m128 *)inputs->a0[slot] = a0; + *(__m128 *)inputs->dadx[slot] = _mm_set1_ps(0.0); + *(__m128 *)inputs->dady[slot] = _mm_set1_ps(0.0); +} + + + +static void calc_coef4( struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info, + unsigned slot, + __m128 a0, + __m128 a1, + __m128 a2) +{ + __m128 da01 = _mm_sub_ps(a0, a1); + __m128 da20 = _mm_sub_ps(a2, a0); + + __m128 da01_dy20_ooa = _mm_mul_ps(da01, _mm_set1_ps(info->dy20_ooa)); + __m128 da20_dy01_ooa = _mm_mul_ps(da20, _mm_set1_ps(info->dy01_ooa)); + __m128 dadx = _mm_sub_ps(da01_dy20_ooa, da20_dy01_ooa); + + __m128 da01_dx20_ooa = _mm_mul_ps(da01, _mm_set1_ps(info->dx20_ooa)); + __m128 da20_dx01_ooa = _mm_mul_ps(da20, _mm_set1_ps(info->dx01_ooa)); + __m128 dady = _mm_sub_ps(da20_dx01_ooa, da01_dx20_ooa); + + __m128 dadx_x0 = _mm_mul_ps(dadx, _mm_set1_ps(info->x0_center)); + __m128 dady_y0 = _mm_mul_ps(dady, _mm_set1_ps(info->y0_center)); + __m128 attr_v0 = _mm_add_ps(dadx_x0, dady_y0); + __m128 attr_0 = _mm_sub_ps(a0, attr_v0); + + *(__m128 *)inputs->a0[slot] = attr_0; + *(__m128 *)inputs->dadx[slot] = dadx; + *(__m128 *)inputs->dady[slot] = dady; +} + + +static void linear_coef( struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info, + unsigned slot, + unsigned vert_attr) +{ + __m128 a0 = *(const __m128 *)info->v0[vert_attr]; + __m128 a1 = *(const __m128 *)info->v1[vert_attr]; + __m128 a2 = *(const __m128 *)info->v2[vert_attr]; + + calc_coef4(inputs, info, slot, a0, a1, a2); +} + + + +/** + * Compute a0, dadx and dady for a perspective-corrected interpolant, + * for a triangle. + * We basically multiply the vertex value by 1/w before computing + * the plane coefficients (a0, dadx, dady). + * Later, when we compute the value at a particular fragment position we'll + * divide the interpolated value by the interpolated W at that fragment. + */ +static void perspective_coef( struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info, + unsigned slot, + unsigned vert_attr) +{ + /* premultiply by 1/w (v[0][3] is always 1/w): + */ + __m128 a0 = *(const __m128 *)info->v0[vert_attr]; + __m128 a1 = *(const __m128 *)info->v1[vert_attr]; + __m128 a2 = *(const __m128 *)info->v2[vert_attr]; + + __m128 a0_oow = _mm_mul_ps(a0, _mm_set1_ps(info->v0[0][3])); + __m128 a1_oow = _mm_mul_ps(a1, _mm_set1_ps(info->v1[0][3])); + __m128 a2_oow = _mm_mul_ps(a2, _mm_set1_ps(info->v2[0][3])); + + calc_coef4(inputs, info, slot, a0_oow, a1_oow, a2_oow); +} + + + + + +/** + * Compute the inputs-> dadx, dady, a0 values. + */ +void lp_setup_tri_coef( struct lp_setup_context *setup, + struct lp_rast_shader_inputs *inputs, + const struct lp_tri_info *info) +{ + unsigned slot; + + /* The internal position input is in slot zero: + */ + linear_coef(inputs, info, 0, 0); + + /* setup interpolation for all the remaining attributes: + */ + for (slot = 0; slot < setup->fs.nr_inputs; slot++) { + unsigned vert_attr = setup->fs.input[slot].src_index; + + switch (setup->fs.input[slot].interp) { + case LP_INTERP_CONSTANT: + if (setup->flatshade_first) { + constant_coef4(inputs, info, slot+1, info->v0[vert_attr]); + } + else { + constant_coef4(inputs, info, slot+1, info->v2[vert_attr]); + } + break; + + case LP_INTERP_LINEAR: + linear_coef(inputs, info, slot+1, vert_attr); + break; + + case LP_INTERP_PERSPECTIVE: + perspective_coef(inputs, info, slot+1, vert_attr); + break; + + case LP_INTERP_POSITION: + /* + * The generated pixel interpolators will pick up the coeffs from + * slot 0. + */ + break; + + case LP_INTERP_FACING: + setup_facing_coef(inputs, info, slot+1); + break; + + default: + assert(0); + } + } +} + +#else +extern void lp_setup_coef_dummy(void); +void lp_setup_coef_dummy(void) +{ +} +#endif diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h index a0606f5034..877a492c6d 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_context.h +++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h @@ -41,6 +41,7 @@ #include "lp_scene.h" #include "draw/draw_vbuf.h" +#include "util/u_rect.h" #define LP_SETUP_NEW_FS 0x01 #define LP_SETUP_NEW_CONSTANTS 0x02 @@ -73,6 +74,7 @@ struct lp_setup_context uint prim; uint vertex_size; uint nr_vertices; + uint sprite; uint vertex_buffer_size; void *vertex_buffer; @@ -88,10 +90,17 @@ struct lp_setup_context boolean flatshade_first; boolean ccw_is_frontface; boolean scissor_test; + boolean point_size_per_vertex; unsigned cullmode; float pixel_offset; + float line_width; + float point_size; + float psize; struct pipe_framebuffer_state fb; + struct u_rect framebuffer; + struct u_rect scissor; + struct u_rect draw_region; /* intersection of fb & scissor */ struct { unsigned flags; @@ -127,9 +136,6 @@ struct lp_setup_context uint8_t *stored; } blend_color; - struct { - struct pipe_scissor_state current; - } scissor; unsigned dirty; /**< bitmask of LP_SETUP_NEW_x bits */ @@ -158,4 +164,29 @@ void lp_setup_update_state( struct lp_setup_context *setup ); void lp_setup_destroy( struct lp_setup_context *setup ); +void +lp_setup_print_triangle(struct lp_setup_context *setup, + const float (*v0)[4], + const float (*v1)[4], + const float (*v2)[4]); + +void +lp_setup_print_vertex(struct lp_setup_context *setup, + const char *name, + const float (*v)[4]); + + +struct lp_rast_triangle * +lp_setup_alloc_triangle(struct lp_scene *scene, + unsigned nr_inputs, + unsigned nr_planes, + unsigned *tri_size); + +void +lp_setup_bin_triangle( struct lp_setup_context *setup, + struct lp_rast_triangle *tri, + const struct u_rect *bbox, + int nr_planes ); + #endif + diff --git a/src/gallium/drivers/llvmpipe/lp_setup_line.c b/src/gallium/drivers/llvmpipe/lp_setup_line.c index be41c44e6f..ce2da55cf4 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_line.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_line.c @@ -29,19 +29,671 @@ * Binning code for lines */ +#include "util/u_math.h" +#include "util/u_memory.h" +#include "lp_perf.h" #include "lp_setup_context.h" +#include "lp_rast.h" +#include "lp_state_fs.h" -static void line_nop( struct lp_setup_context *setup, - const float (*v0)[4], - const float (*v1)[4] ) +#define NUM_CHANNELS 4 + +struct lp_line_info { + + float dx; + float dy; + float oneoverarea; + + const float (*v1)[4]; + const float (*v2)[4]; +}; + + +/** + * Compute a0 for a constant-valued coefficient (GL_FLAT shading). + */ +static void constant_coef( struct lp_setup_context *setup, + struct lp_rast_triangle *tri, + unsigned slot, + const float value, + unsigned i ) +{ + tri->inputs.a0[slot][i] = value; + tri->inputs.dadx[slot][i] = 0.0f; + tri->inputs.dady[slot][i] = 0.0f; +} + + +/** + * Compute a0, dadx and dady for a linearly interpolated coefficient, + * for a triangle. + */ +static void linear_coef( struct lp_setup_context *setup, + struct lp_rast_triangle *tri, + struct lp_line_info *info, + unsigned slot, + unsigned vert_attr, + unsigned i) +{ + float a1 = info->v1[vert_attr][i]; + float a2 = info->v2[vert_attr][i]; + + float da21 = a1 - a2; + float dadx = da21 * info->dx * info->oneoverarea; + float dady = da21 * info->dy * info->oneoverarea; + + tri->inputs.dadx[slot][i] = dadx; + tri->inputs.dady[slot][i] = dady; + + tri->inputs.a0[slot][i] = (a1 - + (dadx * (info->v1[0][0] - setup->pixel_offset) + + dady * (info->v1[0][1] - setup->pixel_offset))); +} + + +/** + * Compute a0, dadx and dady for a perspective-corrected interpolant, + * for a triangle. + * We basically multiply the vertex value by 1/w before computing + * the plane coefficients (a0, dadx, dady). + * Later, when we compute the value at a particular fragment position we'll + * divide the interpolated value by the interpolated W at that fragment. + */ +static void perspective_coef( struct lp_setup_context *setup, + struct lp_rast_triangle *tri, + struct lp_line_info *info, + unsigned slot, + unsigned vert_attr, + unsigned i) +{ + /* premultiply by 1/w (v[0][3] is always 1/w): + */ + float a1 = info->v1[vert_attr][i] * info->v1[0][3]; + float a2 = info->v2[vert_attr][i] * info->v2[0][3]; + + float da21 = a1 - a2; + float dadx = da21 * info->dx * info->oneoverarea; + float dady = da21 * info->dy * info->oneoverarea; + + tri->inputs.dadx[slot][i] = dadx; + tri->inputs.dady[slot][i] = dady; + + tri->inputs.a0[slot][i] = (a1 - + (dadx * (info->v1[0][0] - setup->pixel_offset) + + dady * (info->v1[0][1] - setup->pixel_offset))); +} + +static void +setup_fragcoord_coef( struct lp_setup_context *setup, + struct lp_rast_triangle *tri, + struct lp_line_info *info, + unsigned slot, + unsigned usage_mask) +{ + /*X*/ + if (usage_mask & TGSI_WRITEMASK_X) { + tri->inputs.a0[slot][0] = 0.0; + tri->inputs.dadx[slot][0] = 1.0; + tri->inputs.dady[slot][0] = 0.0; + } + + /*Y*/ + if (usage_mask & TGSI_WRITEMASK_Y) { + tri->inputs.a0[slot][1] = 0.0; + tri->inputs.dadx[slot][1] = 0.0; + tri->inputs.dady[slot][1] = 1.0; + } + + /*Z*/ + if (usage_mask & TGSI_WRITEMASK_Z) { + linear_coef(setup, tri, info, slot, 0, 2); + } + + /*W*/ + if (usage_mask & TGSI_WRITEMASK_W) { + linear_coef(setup, tri, info, slot, 0, 3); + } +} + +/** + * Compute the tri->coef[] array dadx, dady, a0 values. + */ +static void setup_line_coefficients( struct lp_setup_context *setup, + struct lp_rast_triangle *tri, + struct lp_line_info *info) +{ + unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ; + unsigned slot; + + /* setup interpolation for all the remaining attributes: + */ + for (slot = 0; slot < setup->fs.nr_inputs; slot++) { + unsigned vert_attr = setup->fs.input[slot].src_index; + unsigned usage_mask = setup->fs.input[slot].usage_mask; + unsigned i; + + switch (setup->fs.input[slot].interp) { + case LP_INTERP_CONSTANT: + if (setup->flatshade_first) { + for (i = 0; i < NUM_CHANNELS; i++) + if (usage_mask & (1 << i)) + constant_coef(setup, tri, slot+1, info->v1[vert_attr][i], i); + } + else { + for (i = 0; i < NUM_CHANNELS; i++) + if (usage_mask & (1 << i)) + constant_coef(setup, tri, slot+1, info->v2[vert_attr][i], i); + } + break; + + case LP_INTERP_LINEAR: + for (i = 0; i < NUM_CHANNELS; i++) + if (usage_mask & (1 << i)) + linear_coef(setup, tri, info, slot+1, vert_attr, i); + break; + + case LP_INTERP_PERSPECTIVE: + for (i = 0; i < NUM_CHANNELS; i++) + if (usage_mask & (1 << i)) + perspective_coef(setup, tri, info, slot+1, vert_attr, i); + fragcoord_usage_mask |= TGSI_WRITEMASK_W; + break; + + case LP_INTERP_POSITION: + /* + * The generated pixel interpolators will pick up the coeffs from + * slot 0, so all need to ensure that the usage mask is covers all + * usages. + */ + fragcoord_usage_mask |= usage_mask; + break; + + default: + assert(0); + } + } + + /* The internal position input is in slot zero: + */ + setup_fragcoord_coef(setup, tri, info, 0, + fragcoord_usage_mask); +} + + + +static INLINE int subpixel_snap( float a ) +{ + return util_iround(FIXED_ONE * a); +} + + +/** + * Print line vertex attribs (for debug). + */ +static void +print_line(struct lp_setup_context *setup, + const float (*v1)[4], + const float (*v2)[4]) +{ + uint i; + + debug_printf("llvmpipe line\n"); + for (i = 0; i < 1 + setup->fs.nr_inputs; i++) { + debug_printf(" v1[%d]: %f %f %f %f\n", i, + v1[i][0], v1[i][1], v1[i][2], v1[i][3]); + } + for (i = 0; i < 1 + setup->fs.nr_inputs; i++) { + debug_printf(" v2[%d]: %f %f %f %f\n", i, + v2[i][0], v2[i][1], v2[i][2], v2[i][3]); + } +} + + +static INLINE boolean sign(float x){ + return x >= 0; +} + + +/* Used on positive floats only: + */ +static INLINE float fracf(float f) { + return f - floorf(f); } -void -lp_setup_choose_line( struct lp_setup_context *setup ) + +static void +lp_setup_line( struct lp_setup_context *setup, + const float (*v1)[4], + const float (*v2)[4]) { - setup->line = line_nop; + struct lp_scene *scene = lp_setup_get_current_scene(setup); + struct lp_rast_triangle *line; + struct lp_line_info info; + float width = MAX2(1.0, setup->line_width); + struct u_rect bbox; + unsigned tri_bytes; + int x[4]; + int y[4]; + int i; + int nr_planes = 4; + + /* linewidth should be interpreted as integer */ + int fixed_width = util_iround(width) * FIXED_ONE; + + float x_offset=0; + float y_offset=0; + float x_offset_end=0; + float y_offset_end=0; + + float x1diff; + float y1diff; + float x2diff; + float y2diff; + float dx, dy; + + boolean draw_start; + boolean draw_end; + boolean will_draw_start; + boolean will_draw_end; + + if (0) + print_line(setup, v1, v2); + + if (setup->scissor_test) { + nr_planes = 8; + } + else { + nr_planes = 4; + } + + + dx = v1[0][0] - v2[0][0]; + dy = v1[0][1] - v2[0][1]; + + /* X-MAJOR LINE */ + if (fabsf(dx) >= fabsf(dy)) { + float dydx = dy / dx; + + x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5; + y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5; + x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5; + y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5; + + if (y2diff==-0.5 && dy<0){ + y2diff = 0.5; + } + + /* + * Diamond exit rule test for starting point + */ + if (fabsf(x1diff) + fabsf(y1diff) < 0.5) { + draw_start = TRUE; + } + else if (sign(x1diff) == sign(-dx)) { + draw_start = FALSE; + } + else if (sign(-y1diff) != sign(dy)) { + draw_start = TRUE; + } + else { + /* do intersection test */ + float yintersect = fracf(v1[0][1]) + x1diff * dydx; + draw_start = (yintersect < 1.0 && yintersect > 0.0); + } + + + /* + * Diamond exit rule test for ending point + */ + if (fabsf(x2diff) + fabsf(y2diff) < 0.5) { + draw_end = FALSE; + } + else if (sign(x2diff) != sign(-dx)) { + draw_end = FALSE; + } + else if (sign(-y2diff) == sign(dy)) { + draw_end = TRUE; + } + else { + /* do intersection test */ + float yintersect = fracf(v2[0][1]) + x2diff * dydx; + draw_end = (yintersect < 1.0 && yintersect > 0.0); + } + + /* Are we already drawing start/end? + */ + will_draw_start = sign(-x1diff) != sign(dx); + will_draw_end = (sign(x2diff) == sign(-dx)) || x2diff==0; + + if (dx < 0) { + /* if v2 is to the right of v1, swap pointers */ + const float (*temp)[4] = v1; + v1 = v2; + v2 = temp; + dx = -dx; + dy = -dy; + /* Otherwise shift planes appropriately */ + if (will_draw_start != draw_start) { + x_offset_end = - x1diff - 0.5; + y_offset_end = x_offset_end * dydx; + + } + if (will_draw_end != draw_end) { + x_offset = - x2diff - 0.5; + y_offset = x_offset * dydx; + } + + } + else{ + /* Otherwise shift planes appropriately */ + if (will_draw_start != draw_start) { + x_offset = - x1diff + 0.5; + y_offset = x_offset * dydx; + } + if (will_draw_end != draw_end) { + x_offset_end = - x2diff + 0.5; + y_offset_end = x_offset_end * dydx; + } + } + + /* x/y positions in fixed point */ + x[0] = subpixel_snap(v1[0][0] + x_offset - setup->pixel_offset); + x[1] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset); + x[2] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset); + x[3] = subpixel_snap(v1[0][0] + x_offset - setup->pixel_offset); + + y[0] = subpixel_snap(v1[0][1] + y_offset - setup->pixel_offset) - fixed_width/2; + y[1] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset) - fixed_width/2; + y[2] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset) + fixed_width/2; + y[3] = subpixel_snap(v1[0][1] + y_offset - setup->pixel_offset) + fixed_width/2; + + } + else { + const float dxdy = dx / dy; + + /* Y-MAJOR LINE */ + x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5; + y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5; + x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5; + y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5; + + if (x2diff==-0.5 && dx<0) { + x2diff = 0.5; + } + + /* + * Diamond exit rule test for starting point + */ + if (fabsf(x1diff) + fabsf(y1diff) < 0.5) { + draw_start = TRUE; + } + else if (sign(-y1diff) == sign(dy)) { + draw_start = FALSE; + } + else if (sign(x1diff) != sign(-dx)) { + draw_start = TRUE; + } + else { + /* do intersection test */ + float xintersect = fracf(v1[0][0]) + y1diff * dxdy; + draw_start = (xintersect < 1.0 && xintersect > 0.0); + } + + /* + * Diamond exit rule test for ending point + */ + if (fabsf(x2diff) + fabsf(y2diff) < 0.5) { + draw_end = FALSE; + } + else if (sign(-y2diff) != sign(dy) ) { + draw_end = FALSE; + } + else if (sign(x2diff) == sign(-dx) ) { + draw_end = TRUE; + } + else { + /* do intersection test */ + float xintersect = fracf(v2[0][0]) + y2diff * dxdy; + draw_end = (xintersect < 1.0 && xintersect > 0.0); + } + + /* Are we already drawing start/end? + */ + will_draw_start = sign(y1diff) == sign(dy); + will_draw_end = (sign(-y2diff) == sign(dy)) || y2diff==0; + + if (dy > 0) { + /* if v2 is on top of v1, swap pointers */ + const float (*temp)[4] = v1; + v1 = v2; + v2 = temp; + dx = -dx; + dy = -dy; + + /* Otherwise shift planes appropriately */ + if (will_draw_start != draw_start) { + y_offset_end = - y1diff + 0.5; + x_offset_end = y_offset_end * dxdy; + } + if (will_draw_end != draw_end) { + y_offset = - y2diff + 0.5; + x_offset = y_offset * dxdy; + } + } + else { + /* Otherwise shift planes appropriately */ + if (will_draw_start != draw_start) { + y_offset = - y1diff - 0.5; + x_offset = y_offset * dxdy; + + } + if (will_draw_end != draw_end) { + y_offset_end = - y2diff - 0.5; + x_offset_end = y_offset_end * dxdy; + } + } + + /* x/y positions in fixed point */ + x[0] = subpixel_snap(v1[0][0] + x_offset - setup->pixel_offset) - fixed_width/2; + x[1] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset) - fixed_width/2; + x[2] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset) + fixed_width/2; + x[3] = subpixel_snap(v1[0][0] + x_offset - setup->pixel_offset) + fixed_width/2; + + y[0] = subpixel_snap(v1[0][1] + y_offset - setup->pixel_offset); + y[1] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset); + y[2] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset); + y[3] = subpixel_snap(v1[0][1] + y_offset - setup->pixel_offset); + } + + + + LP_COUNT(nr_tris); + + + /* Bounding rectangle (in pixels) */ + { + /* Yes this is necessary to accurately calculate bounding boxes + * with the two fill-conventions we support. GL (normally) ends + * up needing a bottom-left fill convention, which requires + * slightly different rounding. + */ + int adj = (setup->pixel_offset != 0) ? 1 : 0; + + bbox.x0 = (MIN4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER; + bbox.x1 = (MAX4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER; + bbox.y0 = (MIN4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; + bbox.y1 = (MAX4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; + + /* Inclusive coordinates: + */ + bbox.x1--; + bbox.y1--; + } + + if (bbox.x1 < bbox.x0 || + bbox.y1 < bbox.y0) { + if (0) debug_printf("empty bounding box\n"); + LP_COUNT(nr_culled_tris); + return; + } + + if (!u_rect_test_intersection(&setup->draw_region, &bbox)) { + if (0) debug_printf("offscreen\n"); + LP_COUNT(nr_culled_tris); + return; + } + + u_rect_find_intersection(&setup->draw_region, &bbox); + + line = lp_setup_alloc_triangle(scene, + setup->fs.nr_inputs, + nr_planes, + &tri_bytes); + if (!line) + return; + +#ifdef DEBUG + line->v[0][0] = v1[0][0]; + line->v[1][0] = v2[0][0]; + line->v[0][1] = v1[0][1]; + line->v[1][1] = v2[0][1]; +#endif + + /* calculate the deltas */ + line->plane[0].dcdy = x[0] - x[1]; + line->plane[1].dcdy = x[1] - x[2]; + line->plane[2].dcdy = x[2] - x[3]; + line->plane[3].dcdy = x[3] - x[0]; + + line->plane[0].dcdx = y[0] - y[1]; + line->plane[1].dcdx = y[1] - y[2]; + line->plane[2].dcdx = y[2] - y[3]; + line->plane[3].dcdx = y[3] - y[0]; + + + info.oneoverarea = 1.0f / (dx * dx + dy * dy); + info.dx = dx; + info.dy = dy; + info.v1 = v1; + info.v2 = v2; + + /* Setup parameter interpolants: + */ + setup_line_coefficients( setup, line, &info); + + line->inputs.facing = 1.0F; + line->inputs.state = setup->fs.stored; + + for (i = 0; i < 4; i++) { + struct lp_rast_plane *plane = &line->plane[i]; + + /* half-edge constants, will be interated over the whole render + * target. + */ + plane->c = plane->dcdx * x[i] - plane->dcdy * y[i]; + + + /* correct for top-left vs. bottom-left fill convention. + * + * note that we're overloading gl_rasterization_rules to mean + * both (0.5,0.5) pixel centers *and* bottom-left filling + * convention. + * + * GL actually has a top-left filling convention, but GL's + * notion of "top" differs from gallium's... + * + * Also, sometimes (in FBO cases) GL will render upside down + * to its usual method, in which case it will probably want + * to use the opposite, top-left convention. + */ + if (plane->dcdx < 0) { + /* both fill conventions want this - adjust for left edges */ + plane->c++; + } + else if (plane->dcdx == 0) { + if (setup->pixel_offset == 0) { + /* correct for top-left fill convention: + */ + if (plane->dcdy > 0) plane->c++; + } + else { + /* correct for bottom-left fill convention: + */ + if (plane->dcdy < 0) plane->c++; + } + } + + plane->dcdx *= FIXED_ONE; + plane->dcdy *= FIXED_ONE; + + /* find trivial reject offsets for each edge for a single-pixel + * sized block. These will be scaled up at each recursive level to + * match the active blocksize. Scaling in this way works best if + * the blocks are square. + */ + plane->eo = 0; + if (plane->dcdx < 0) plane->eo -= plane->dcdx; + if (plane->dcdy > 0) plane->eo += plane->dcdy; + + /* Calculate trivial accept offsets from the above. + */ + plane->ei = plane->dcdy - plane->dcdx - plane->eo; + } + + + /* + * When rasterizing scissored tris, use the intersection of the + * triangle bounding box and the scissor rect to generate the + * scissor planes. + * + * This permits us to cut off the triangle "tails" that are present + * in the intermediate recursive levels caused when two of the + * triangles edges don't diverge quickly enough to trivially reject + * exterior blocks from the triangle. + * + * It's not really clear if it's worth worrying about these tails, + * but since we generate the planes for each scissored tri, it's + * free to trim them in this case. + * + * Note that otherwise, the scissor planes only vary in 'C' value, + * and even then only on state-changes. Could alternatively store + * these planes elsewhere. + */ + if (nr_planes == 8) { + line->plane[4].dcdx = -1; + line->plane[4].dcdy = 0; + line->plane[4].c = 1-bbox.x0; + line->plane[4].ei = 0; + line->plane[4].eo = 1; + + line->plane[5].dcdx = 1; + line->plane[5].dcdy = 0; + line->plane[5].c = bbox.x1+1; + line->plane[5].ei = -1; + line->plane[5].eo = 0; + + line->plane[6].dcdx = 0; + line->plane[6].dcdy = 1; + line->plane[6].c = 1-bbox.y0; + line->plane[6].ei = 0; + line->plane[6].eo = 1; + + line->plane[7].dcdx = 0; + line->plane[7].dcdy = -1; + line->plane[7].c = bbox.y1+1; + line->plane[7].ei = -1; + line->plane[7].eo = 0; + } + + lp_setup_bin_triangle(setup, line, &bbox, nr_planes); +} + + +void lp_setup_choose_line( struct lp_setup_context *setup ) +{ + setup->line = lp_setup_line; } diff --git a/src/gallium/drivers/llvmpipe/lp_setup_point.c b/src/gallium/drivers/llvmpipe/lp_setup_point.c index 9f69e6c5ce..6ae318d328 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_point.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_point.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2010, VMware Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -18,7 +18,7 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,17 +30,299 @@ */ #include "lp_setup_context.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "lp_perf.h" +#include "lp_setup_context.h" +#include "lp_rast.h" +#include "lp_state_fs.h" +#include "tgsi/tgsi_scan.h" + +#define NUM_CHANNELS 4 + +struct point_info { + /* x,y deltas */ + int dy01, dy12; + int dx01, dx12; + + const float (*v0)[4]; +}; + + +/** + * Compute a0 for a constant-valued coefficient (GL_FLAT shading). + */ +static void constant_coef( struct lp_setup_context *setup, + struct lp_rast_triangle *point, + unsigned slot, + const float value, + unsigned i ) +{ + point->inputs.a0[slot][i] = value; + point->inputs.dadx[slot][i] = 0.0f; + point->inputs.dady[slot][i] = 0.0f; +} + +static void perspective_coef( struct lp_setup_context *setup, + struct lp_rast_triangle *point, + const struct point_info *info, + unsigned slot, + unsigned vert_attr, + unsigned i) +{ + if (i == 0) { + float dadx = FIXED_ONE / (float)info->dx12; + float dady = 0.0f; + point->inputs.dadx[slot][i] = dadx; + point->inputs.dady[slot][i] = dady; + point->inputs.a0[slot][i] = (0.5 - + (dadx * ((float)info->v0[0][0] - setup->pixel_offset) + + dady * ((float)info->v0[0][1] - setup->pixel_offset))); + } + + else if (i == 1) { + float dadx = 0.0f; + float dady = FIXED_ONE / (float)info->dx12; + + point->inputs.dadx[slot][i] = dadx; + point->inputs.dady[slot][i] = dady; + point->inputs.a0[slot][i] = (0.5 - + (dadx * ((float)info->v0[0][0] - setup->pixel_offset) + + dady * ((float)info->v0[0][1] - setup->pixel_offset))); + } + + else if (i == 2) { + point->inputs.a0[slot][i] = 0.0f; + point->inputs.dadx[slot][i] = 0.0f; + point->inputs.dady[slot][i] = 0.0f; + } + + else if (i == 3) { + point->inputs.a0[slot][i] = 1.0f; + point->inputs.dadx[slot][i] = 0.0f; + point->inputs.dady[slot][i] = 0.0f; + } + +} + + +/** + * Special coefficient setup for gl_FragCoord. + * X and Y are trivial + * Z and W are copied from position_coef which should have already been computed. + * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask. + */ +static void +setup_point_fragcoord_coef(struct lp_setup_context *setup, + struct lp_rast_triangle *point, + const struct point_info *info, + unsigned slot, + unsigned usage_mask) +{ + /*X*/ + if (usage_mask & TGSI_WRITEMASK_X) { + point->inputs.a0[slot][0] = 0.0; + point->inputs.dadx[slot][0] = 1.0; + point->inputs.dady[slot][0] = 0.0; + } + + /*Y*/ + if (usage_mask & TGSI_WRITEMASK_Y) { + point->inputs.a0[slot][1] = 0.0; + point->inputs.dadx[slot][1] = 0.0; + point->inputs.dady[slot][1] = 1.0; + } + + /*Z*/ + if (usage_mask & TGSI_WRITEMASK_Z) { + constant_coef(setup, point, slot, info->v0[0][2], 2); + } + + /*W*/ + if (usage_mask & TGSI_WRITEMASK_W) { + constant_coef(setup, point, slot, info->v0[0][3], 3); + } +} + +/** + * Compute the point->coef[] array dadx, dady, a0 values. + */ +static void +setup_point_coefficients( struct lp_setup_context *setup, + struct lp_rast_triangle *point, + const struct point_info *info) +{ + unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ; + unsigned slot; + + /* setup interpolation for all the remaining attributes: + */ + for (slot = 0; slot < setup->fs.nr_inputs; slot++) { + unsigned vert_attr = setup->fs.input[slot].src_index; + unsigned usage_mask = setup->fs.input[slot].usage_mask; + unsigned i; + + switch (setup->fs.input[slot].interp) { + case LP_INTERP_POSITION: + /* + * The generated pixel interpolators will pick up the coeffs from + * slot 0, so all need to ensure that the usage mask is covers all + * usages. + */ + fragcoord_usage_mask |= usage_mask; + break; + + case LP_INTERP_PERSPECTIVE: + /* For point sprite textures */ + if (setup->fs.current.variant->shader->info.input_semantic_name[slot] + == TGSI_SEMANTIC_GENERIC) + { + int index = setup->fs.current.variant->shader->info.input_semantic_index[slot]; + + if (setup->sprite & (1 << index)) { + for (i = 0; i < NUM_CHANNELS; i++) + if (usage_mask & (1 << i)) + perspective_coef(setup, point, info, slot+1, vert_attr, i); + fragcoord_usage_mask |= TGSI_WRITEMASK_W; + break; + } + } + + /* Otherwise fallthrough */ + default: + for (i = 0; i < NUM_CHANNELS; i++) { + if (usage_mask & (1 << i)) + constant_coef(setup, point, slot+1, info->v0[vert_attr][i], i); + } + } + } -static void point_nop( struct lp_setup_context *setup, - const float (*v0)[4] ) + /* The internal position input is in slot zero: + */ + setup_point_fragcoord_coef(setup, point, info, 0, + fragcoord_usage_mask); +} + +static INLINE int +subpixel_snap(float a) { + return util_iround(FIXED_ONE * a); +} + + +static void lp_setup_point( struct lp_setup_context *setup, + const float (*v0)[4] ) +{ + /* x/y positions in fixed point */ + const int sizeAttr = setup->psize; + const float size + = (setup->point_size_per_vertex && sizeAttr > 0) ? v0[sizeAttr][0] + : setup->point_size; + + /* Point size as fixed point integer, remove rounding errors + * and gives minimum width for very small points + */ + int fixed_width = MAX2(FIXED_ONE, + (subpixel_snap(size) + FIXED_ONE/2 - 1) & ~(FIXED_ONE-1)); + + const int x0 = subpixel_snap(v0[0][0] - setup->pixel_offset) - fixed_width/2; + const int y0 = subpixel_snap(v0[0][1] - setup->pixel_offset) - fixed_width/2; + + struct lp_scene *scene = lp_setup_get_current_scene(setup); + struct lp_rast_triangle *point; + unsigned bytes; + struct u_rect bbox; + unsigned nr_planes = 4; + struct point_info info; + + + /* Bounding rectangle (in pixels) */ + { + /* Yes this is necessary to accurately calculate bounding boxes + * with the two fill-conventions we support. GL (normally) ends + * up needing a bottom-left fill convention, which requires + * slightly different rounding. + */ + int adj = (setup->pixel_offset != 0) ? 1 : 0; + + bbox.x0 = (x0 + (FIXED_ONE-1) + adj) >> FIXED_ORDER; + bbox.x1 = (x0 + fixed_width + (FIXED_ONE-1) + adj) >> FIXED_ORDER; + bbox.y0 = (y0 + (FIXED_ONE-1)) >> FIXED_ORDER; + bbox.y1 = (y0 + fixed_width + (FIXED_ONE-1)) >> FIXED_ORDER; + + /* Inclusive coordinates: + */ + bbox.x1--; + bbox.y1--; + } + + if (!u_rect_test_intersection(&setup->draw_region, &bbox)) { + if (0) debug_printf("offscreen\n"); + LP_COUNT(nr_culled_tris); + return; + } + + u_rect_find_intersection(&setup->draw_region, &bbox); + + point = lp_setup_alloc_triangle(scene, + setup->fs.nr_inputs, + nr_planes, + &bytes); + if (!point) + return; + +#ifdef DEBUG + point->v[0][0] = v0[0][0]; + point->v[0][1] = v0[0][1]; +#endif + + info.v0 = v0; + info.dx01 = 0; + info.dx12 = fixed_width; + info.dy01 = fixed_width; + info.dy12 = 0; + + /* Setup parameter interpolants: + */ + setup_point_coefficients(setup, point, &info); + + point->inputs.facing = 1.0F; + point->inputs.state = setup->fs.stored; + + { + point->plane[0].dcdx = -1; + point->plane[0].dcdy = 0; + point->plane[0].c = 1-bbox.x0; + point->plane[0].ei = 0; + point->plane[0].eo = 1; + + point->plane[1].dcdx = 1; + point->plane[1].dcdy = 0; + point->plane[1].c = bbox.x1+1; + point->plane[1].ei = -1; + point->plane[1].eo = 0; + + point->plane[2].dcdx = 0; + point->plane[2].dcdy = 1; + point->plane[2].c = 1-bbox.y0; + point->plane[2].ei = 0; + point->plane[2].eo = 1; + + point->plane[3].dcdx = 0; + point->plane[3].dcdy = -1; + point->plane[3].c = bbox.y1+1; + point->plane[3].ei = -1; + point->plane[3].eo = 0; + } + + lp_setup_bin_triangle(setup, point, &bbox, nr_planes); } void lp_setup_choose_point( struct lp_setup_context *setup ) { - setup->point = point_nop; + setup->point = lp_setup_point; } diff --git a/src/gallium/drivers/llvmpipe/lp_setup_tri.c b/src/gallium/drivers/llvmpipe/lp_setup_tri.c index 393533ebee..0180d95090 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_tri.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_tri.c @@ -31,35 +31,15 @@ #include "util/u_math.h" #include "util/u_memory.h" +#include "util/u_rect.h" #include "lp_perf.h" #include "lp_setup_context.h" +#include "lp_setup_coef.h" #include "lp_rast.h" #include "lp_state_fs.h" #define NUM_CHANNELS 4 -struct tri_info { - - float pixel_offset; - - /* fixed point vertex coordinates */ - int x[3]; - int y[3]; - - /* float x,y deltas - all from the original coordinates - */ - float dy01, dy20; - float dx01, dx20; - float oneoverarea; - - const float (*v0)[4]; - const float (*v1)[4]; - const float (*v2)[4]; - - boolean frontfacing; -}; - - static INLINE int @@ -76,247 +56,6 @@ fixed_to_float(int a) -/** - * Compute a0 for a constant-valued coefficient (GL_FLAT shading). - */ -static void constant_coef( struct lp_rast_triangle *tri, - unsigned slot, - const float value, - unsigned i ) -{ - tri->inputs.a0[slot][i] = value; - tri->inputs.dadx[slot][i] = 0.0f; - tri->inputs.dady[slot][i] = 0.0f; -} - - - -static void linear_coef( struct lp_rast_triangle *tri, - const struct tri_info *info, - unsigned slot, - unsigned vert_attr, - unsigned i) -{ - float a0 = info->v0[vert_attr][i]; - float a1 = info->v1[vert_attr][i]; - float a2 = info->v2[vert_attr][i]; - - float da01 = a0 - a1; - float da20 = a2 - a0; - float dadx = (da01 * info->dy20 - info->dy01 * da20) * info->oneoverarea; - float dady = (da20 * info->dx01 - info->dx20 * da01) * info->oneoverarea; - - tri->inputs.dadx[slot][i] = dadx; - tri->inputs.dady[slot][i] = dady; - - /* calculate a0 as the value which would be sampled for the - * fragment at (0,0), taking into account that we want to sample at - * pixel centers, in other words (0.5, 0.5). - * - * this is neat but unfortunately not a good way to do things for - * triangles with very large values of dadx or dady as it will - * result in the subtraction and re-addition from a0 of a very - * large number, which means we'll end up loosing a lot of the - * fractional bits and precision from a0. the way to fix this is - * to define a0 as the sample at a pixel center somewhere near vmin - * instead - i'll switch to this later. - */ - tri->inputs.a0[slot][i] = (a0 - - (dadx * (info->v0[0][0] - info->pixel_offset) + - dady * (info->v0[0][1] - info->pixel_offset))); -} - - -/** - * Compute a0, dadx and dady for a perspective-corrected interpolant, - * for a triangle. - * We basically multiply the vertex value by 1/w before computing - * the plane coefficients (a0, dadx, dady). - * Later, when we compute the value at a particular fragment position we'll - * divide the interpolated value by the interpolated W at that fragment. - */ -static void perspective_coef( struct lp_rast_triangle *tri, - const struct tri_info *info, - unsigned slot, - unsigned vert_attr, - unsigned i) -{ - /* premultiply by 1/w (v[0][3] is always 1/w): - */ - float a0 = info->v0[vert_attr][i] * info->v0[0][3]; - float a1 = info->v1[vert_attr][i] * info->v1[0][3]; - float a2 = info->v2[vert_attr][i] * info->v2[0][3]; - float da01 = a0 - a1; - float da20 = a2 - a0; - float dadx = (da01 * info->dy20 - info->dy01 * da20) * info->oneoverarea; - float dady = (da20 * info->dx01 - info->dx20 * da01) * info->oneoverarea; - - tri->inputs.dadx[slot][i] = dadx; - tri->inputs.dady[slot][i] = dady; - tri->inputs.a0[slot][i] = (a0 - - (dadx * (info->v0[0][0] - info->pixel_offset) + - dady * (info->v0[0][1] - info->pixel_offset))); -} - - -/** - * Special coefficient setup for gl_FragCoord. - * X and Y are trivial - * Z and W are copied from position_coef which should have already been computed. - * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask. - */ -static void -setup_fragcoord_coef(struct lp_rast_triangle *tri, - const struct tri_info *info, - unsigned slot, - unsigned usage_mask) -{ - /*X*/ - if (usage_mask & TGSI_WRITEMASK_X) { - tri->inputs.a0[slot][0] = 0.0; - tri->inputs.dadx[slot][0] = 1.0; - tri->inputs.dady[slot][0] = 0.0; - } - - /*Y*/ - if (usage_mask & TGSI_WRITEMASK_Y) { - tri->inputs.a0[slot][1] = 0.0; - tri->inputs.dadx[slot][1] = 0.0; - tri->inputs.dady[slot][1] = 1.0; - } - - /*Z*/ - if (usage_mask & TGSI_WRITEMASK_Z) { - linear_coef(tri, info, slot, 0, 2); - } - - /*W*/ - if (usage_mask & TGSI_WRITEMASK_W) { - linear_coef(tri, info, slot, 0, 3); - } -} - - -/** - * Setup the fragment input attribute with the front-facing value. - * \param frontface is the triangle front facing? - */ -static void setup_facing_coef( struct lp_rast_triangle *tri, - unsigned slot, - boolean frontface, - unsigned usage_mask) -{ - /* convert TRUE to 1.0 and FALSE to -1.0 */ - if (usage_mask & TGSI_WRITEMASK_X) - constant_coef( tri, slot, 2.0f * frontface - 1.0f, 0 ); - - if (usage_mask & TGSI_WRITEMASK_Y) - constant_coef( tri, slot, 0.0f, 1 ); /* wasted */ - - if (usage_mask & TGSI_WRITEMASK_Z) - constant_coef( tri, slot, 0.0f, 2 ); /* wasted */ - - if (usage_mask & TGSI_WRITEMASK_W) - constant_coef( tri, slot, 0.0f, 3 ); /* wasted */ -} - - -/** - * Compute the tri->coef[] array dadx, dady, a0 values. - */ -static void setup_tri_coefficients( struct lp_setup_context *setup, - struct lp_rast_triangle *tri, - const struct tri_info *info) -{ - unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ; - unsigned slot; - unsigned i; - - /* setup interpolation for all the remaining attributes: - */ - for (slot = 0; slot < setup->fs.nr_inputs; slot++) { - unsigned vert_attr = setup->fs.input[slot].src_index; - unsigned usage_mask = setup->fs.input[slot].usage_mask; - - switch (setup->fs.input[slot].interp) { - case LP_INTERP_CONSTANT: - if (setup->flatshade_first) { - for (i = 0; i < NUM_CHANNELS; i++) - if (usage_mask & (1 << i)) - constant_coef(tri, slot+1, info->v0[vert_attr][i], i); - } - else { - for (i = 0; i < NUM_CHANNELS; i++) - if (usage_mask & (1 << i)) - constant_coef(tri, slot+1, info->v2[vert_attr][i], i); - } - break; - - case LP_INTERP_LINEAR: - for (i = 0; i < NUM_CHANNELS; i++) - if (usage_mask & (1 << i)) - linear_coef(tri, info, slot+1, vert_attr, i); - break; - - case LP_INTERP_PERSPECTIVE: - for (i = 0; i < NUM_CHANNELS; i++) - if (usage_mask & (1 << i)) - perspective_coef(tri, info, slot+1, vert_attr, i); - fragcoord_usage_mask |= TGSI_WRITEMASK_W; - break; - - case LP_INTERP_POSITION: - /* - * The generated pixel interpolators will pick up the coeffs from - * slot 0, so all need to ensure that the usage mask is covers all - * usages. - */ - fragcoord_usage_mask |= usage_mask; - break; - - case LP_INTERP_FACING: - setup_facing_coef(tri, slot+1, info->frontfacing, usage_mask); - break; - - default: - assert(0); - } - } - - /* The internal position input is in slot zero: - */ - setup_fragcoord_coef(tri, info, 0, fragcoord_usage_mask); - - if (0) { - for (i = 0; i < NUM_CHANNELS; i++) { - float a0 = tri->inputs.a0 [0][i]; - float dadx = tri->inputs.dadx[0][i]; - float dady = tri->inputs.dady[0][i]; - - debug_printf("POS.%c: a0 = %f, dadx = %f, dady = %f\n", - "xyzw"[i], - a0, dadx, dady); - } - - for (slot = 0; slot < setup->fs.nr_inputs; slot++) { - unsigned usage_mask = setup->fs.input[slot].usage_mask; - for (i = 0; i < NUM_CHANNELS; i++) { - if (usage_mask & (1 << i)) { - float a0 = tri->inputs.a0 [1 + slot][i]; - float dadx = tri->inputs.dadx[1 + slot][i]; - float dady = tri->inputs.dady[1 + slot][i]; - - debug_printf("IN[%u].%c: a0 = %f, dadx = %f, dady = %f\n", - slot, - "xyzw"[i], - a0, dadx, dady); - } - } - } - } -} - - @@ -329,11 +68,11 @@ static void setup_tri_coefficients( struct lp_setup_context *setup, * \param nr_inputs number of fragment shader inputs * \return pointer to triangle space */ -static INLINE struct lp_rast_triangle * -alloc_triangle(struct lp_scene *scene, - unsigned nr_inputs, - unsigned nr_planes, - unsigned *tri_size) +struct lp_rast_triangle * +lp_setup_alloc_triangle(struct lp_scene *scene, + unsigned nr_inputs, + unsigned nr_planes, + unsigned *tri_size) { unsigned input_array_sz = NUM_CHANNELS * (nr_inputs + 1) * sizeof(float); struct lp_rast_triangle *tri; @@ -357,35 +96,71 @@ alloc_triangle(struct lp_scene *scene, return tri; } +void +lp_setup_print_vertex(struct lp_setup_context *setup, + const char *name, + const float (*v)[4]) +{ + int i, j; + + debug_printf(" wpos (%s[0]) xyzw %f %f %f %f\n", + name, + v[0][0], v[0][1], v[0][2], v[0][3]); + + for (i = 0; i < setup->fs.nr_inputs; i++) { + const float *in = v[setup->fs.input[i].src_index]; + + debug_printf(" in[%d] (%s[%d]) %s%s%s%s ", + i, + name, setup->fs.input[i].src_index, + (setup->fs.input[i].usage_mask & 0x1) ? "x" : " ", + (setup->fs.input[i].usage_mask & 0x2) ? "y" : " ", + (setup->fs.input[i].usage_mask & 0x4) ? "z" : " ", + (setup->fs.input[i].usage_mask & 0x8) ? "w" : " "); + + for (j = 0; j < 4; j++) + if (setup->fs.input[i].usage_mask & (1<<j)) + debug_printf("%.5f ", in[j]); + + debug_printf("\n"); + } +} + /** * Print triangle vertex attribs (for debug). */ -static void -print_triangle(struct lp_setup_context *setup, - const float (*v1)[4], - const float (*v2)[4], - const float (*v3)[4]) +void +lp_setup_print_triangle(struct lp_setup_context *setup, + const float (*v0)[4], + const float (*v1)[4], + const float (*v2)[4]) { - uint i; + debug_printf("triangle\n"); - debug_printf("llvmpipe triangle\n"); - for (i = 0; i < 1 + setup->fs.nr_inputs; i++) { - debug_printf(" v1[%d]: %f %f %f %f\n", i, - v1[i][0], v1[i][1], v1[i][2], v1[i][3]); - } - for (i = 0; i < 1 + setup->fs.nr_inputs; i++) { - debug_printf(" v2[%d]: %f %f %f %f\n", i, - v2[i][0], v2[i][1], v2[i][2], v2[i][3]); - } - for (i = 0; i < 1 + setup->fs.nr_inputs; i++) { - debug_printf(" v3[%d]: %f %f %f %f\n", i, - v3[i][0], v3[i][1], v3[i][2], v3[i][3]); + { + const float ex = v0[0][0] - v2[0][0]; + const float ey = v0[0][1] - v2[0][1]; + const float fx = v1[0][0] - v2[0][0]; + const float fy = v1[0][1] - v2[0][1]; + + /* det = cross(e,f).z */ + const float det = ex * fy - ey * fx; + if (det < 0.0f) + debug_printf(" - ccw\n"); + else if (det > 0.0f) + debug_printf(" - cw\n"); + else + debug_printf(" - zero area\n"); } + + lp_setup_print_vertex(setup, "v0", v0); + lp_setup_print_vertex(setup, "v1", v1); + lp_setup_print_vertex(setup, "v2", v2); } -lp_rast_cmd lp_rast_tri_tab[8] = { +lp_rast_cmd lp_rast_tri_tab[9] = { NULL, /* should be impossible */ lp_rast_triangle_1, lp_rast_triangle_2, @@ -393,7 +168,8 @@ lp_rast_cmd lp_rast_tri_tab[8] = { lp_rast_triangle_4, lp_rast_triangle_5, lp_rast_triangle_6, - lp_rast_triangle_7 + lp_rast_triangle_7, + lp_rast_triangle_8 }; /** @@ -403,25 +179,27 @@ lp_rast_cmd lp_rast_tri_tab[8] = { */ static void do_triangle_ccw(struct lp_setup_context *setup, + const float (*v0)[4], const float (*v1)[4], const float (*v2)[4], - const float (*v3)[4], boolean frontfacing ) { - struct lp_scene *scene = lp_setup_get_current_scene(setup); - struct lp_fragment_shader_variant *variant = setup->fs.current.variant; struct lp_rast_triangle *tri; - struct tri_info info; + int x[3]; + int y[3]; + float dy01, dy20; + float dx01, dx20; + float oneoverarea; + struct lp_tri_info info; int area; - int minx, maxx, miny, maxy; - int ix0, ix1, iy0, iy1; + struct u_rect bbox; unsigned tri_bytes; int i; int nr_planes = 3; if (0) - print_triangle(setup, v1, v2, v3); + lp_setup_print_triangle(setup, v0, v1, v2); if (setup->scissor_test) { nr_planes = 7; @@ -430,38 +208,73 @@ do_triangle_ccw(struct lp_setup_context *setup, nr_planes = 3; } + /* x/y positions in fixed point */ + x[0] = subpixel_snap(v0[0][0] - setup->pixel_offset); + x[1] = subpixel_snap(v1[0][0] - setup->pixel_offset); + x[2] = subpixel_snap(v2[0][0] - setup->pixel_offset); + y[0] = subpixel_snap(v0[0][1] - setup->pixel_offset); + y[1] = subpixel_snap(v1[0][1] - setup->pixel_offset); + y[2] = subpixel_snap(v2[0][1] - setup->pixel_offset); + + + /* Bounding rectangle (in pixels) */ + { + /* Yes this is necessary to accurately calculate bounding boxes + * with the two fill-conventions we support. GL (normally) ends + * up needing a bottom-left fill convention, which requires + * slightly different rounding. + */ + int adj = (setup->pixel_offset != 0) ? 1 : 0; + + bbox.x0 = (MIN3(x[0], x[1], x[2]) + (FIXED_ONE-1)) >> FIXED_ORDER; + bbox.x1 = (MAX3(x[0], x[1], x[2]) + (FIXED_ONE-1)) >> FIXED_ORDER; + bbox.y0 = (MIN3(y[0], y[1], y[2]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; + bbox.y1 = (MAX3(y[0], y[1], y[2]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; + + /* Inclusive coordinates: + */ + bbox.x1--; + bbox.y1--; + } + + if (bbox.x1 < bbox.x0 || + bbox.y1 < bbox.y0) { + if (0) debug_printf("empty bounding box\n"); + LP_COUNT(nr_culled_tris); + return; + } + + if (!u_rect_test_intersection(&setup->draw_region, &bbox)) { + if (0) debug_printf("offscreen\n"); + LP_COUNT(nr_culled_tris); + return; + } + + u_rect_find_intersection(&setup->draw_region, &bbox); - tri = alloc_triangle(scene, - setup->fs.nr_inputs, - nr_planes, - &tri_bytes); + tri = lp_setup_alloc_triangle(scene, + setup->fs.nr_inputs, + nr_planes, + &tri_bytes); if (!tri) return; #ifdef DEBUG - tri->v[0][0] = v1[0][0]; - tri->v[1][0] = v2[0][0]; - tri->v[2][0] = v3[0][0]; - tri->v[0][1] = v1[0][1]; - tri->v[1][1] = v2[0][1]; - tri->v[2][1] = v3[0][1]; + tri->v[0][0] = v0[0][0]; + tri->v[1][0] = v1[0][0]; + tri->v[2][0] = v2[0][0]; + tri->v[0][1] = v0[0][1]; + tri->v[1][1] = v1[0][1]; + tri->v[2][1] = v2[0][1]; #endif - /* x/y positions in fixed point */ - info.x[0] = subpixel_snap(v1[0][0] - setup->pixel_offset); - info.x[1] = subpixel_snap(v2[0][0] - setup->pixel_offset); - info.x[2] = subpixel_snap(v3[0][0] - setup->pixel_offset); - info.y[0] = subpixel_snap(v1[0][1] - setup->pixel_offset); - info.y[1] = subpixel_snap(v2[0][1] - setup->pixel_offset); - info.y[2] = subpixel_snap(v3[0][1] - setup->pixel_offset); - - tri->plane[0].dcdy = info.x[0] - info.x[1]; - tri->plane[1].dcdy = info.x[1] - info.x[2]; - tri->plane[2].dcdy = info.x[2] - info.x[0]; + tri->plane[0].dcdy = x[0] - x[1]; + tri->plane[1].dcdy = x[1] - x[2]; + tri->plane[2].dcdy = x[2] - x[0]; - tri->plane[0].dcdx = info.y[0] - info.y[1]; - tri->plane[1].dcdx = info.y[1] - info.y[2]; - tri->plane[2].dcdx = info.y[2] - info.y[0]; + tri->plane[0].dcdx = y[0] - y[1]; + tri->plane[1].dcdx = y[1] - y[2]; + tri->plane[2].dcdx = y[2] - y[0]; area = (tri->plane[0].dcdy * tri->plane[2].dcdx - tri->plane[2].dcdy * tri->plane[0].dcdx); @@ -478,57 +291,29 @@ do_triangle_ccw(struct lp_setup_context *setup, return; } - /* Bounding rectangle (in pixels) */ - { - /* Yes this is necessary to accurately calculate bounding boxes - * with the two fill-conventions we support. GL (normally) ends - * up needing a bottom-left fill convention, which requires - * slightly different rounding. - */ - int adj = (setup->pixel_offset != 0) ? 1 : 0; - - minx = (MIN3(info.x[0], info.x[1], info.x[2]) + (FIXED_ONE-1)) >> FIXED_ORDER; - maxx = (MAX3(info.x[0], info.x[1], info.x[2]) + (FIXED_ONE-1)) >> FIXED_ORDER; - miny = (MIN3(info.y[0], info.y[1], info.y[2]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; - maxy = (MAX3(info.y[0], info.y[1], info.y[2]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; - } - - if (setup->scissor_test) { - minx = MAX2(minx, setup->scissor.current.minx); - maxx = MIN2(maxx, setup->scissor.current.maxx); - miny = MAX2(miny, setup->scissor.current.miny); - maxy = MIN2(maxy, setup->scissor.current.maxy); - } - else { - minx = MAX2(minx, 0); - miny = MAX2(miny, 0); - maxx = MIN2(maxx, scene->fb.width); - maxy = MIN2(maxy, scene->fb.height); - } - - - if (miny >= maxy || minx >= maxx) { - lp_scene_putback_data( scene, tri_bytes ); - LP_COUNT(nr_culled_tris); - return; - } /* */ - info.pixel_offset = setup->pixel_offset; - info.v0 = v1; - info.v1 = v2; - info.v2 = v3; - info.dx01 = info.v0[0][0] - info.v1[0][0]; - info.dx20 = info.v2[0][0] - info.v0[0][0]; - info.dy01 = info.v0[0][1] - info.v1[0][1]; - info.dy20 = info.v2[0][1] - info.v0[0][1]; - info.oneoverarea = 1.0f / (info.dx01 * info.dy20 - info.dx20 * info.dy01); + dx01 = v0[0][0] - v1[0][0]; + dy01 = v0[0][1] - v1[0][1]; + dx20 = v2[0][0] - v0[0][0]; + dy20 = v2[0][1] - v0[0][1]; + oneoverarea = 1.0f / (dx01 * dy20 - dx20 * dy01); + + info.v0 = v0; + info.v1 = v1; + info.v2 = v2; info.frontfacing = frontfacing; + info.x0_center = v0[0][0] - setup->pixel_offset; + info.y0_center = v0[0][1] - setup->pixel_offset; + info.dx01_ooa = dx01 * oneoverarea; + info.dx20_ooa = dx20 * oneoverarea; + info.dy01_ooa = dy01 * oneoverarea; + info.dy20_ooa = dy20 * oneoverarea; /* Setup parameter interpolants: */ - setup_tri_coefficients( setup, tri, &info ); + lp_setup_tri_coef( setup, &tri->inputs, &info ); tri->inputs.facing = frontfacing ? 1.0F : -1.0F; tri->inputs.state = setup->fs.stored; @@ -541,7 +326,7 @@ do_triangle_ccw(struct lp_setup_context *setup, /* half-edge constants, will be interated over the whole render * target. */ - plane->c = plane->dcdx * info.x[i] - plane->dcdy * info.y[i]; + plane->c = plane->dcdx * x[i] - plane->dcdy * y[i]; /* correct for top-left vs. bottom-left fill convention. * @@ -612,29 +397,43 @@ do_triangle_ccw(struct lp_setup_context *setup, if (nr_planes == 7) { tri->plane[3].dcdx = -1; tri->plane[3].dcdy = 0; - tri->plane[3].c = 1-minx; + tri->plane[3].c = 1-bbox.x0; tri->plane[3].ei = 0; tri->plane[3].eo = 1; tri->plane[4].dcdx = 1; tri->plane[4].dcdy = 0; - tri->plane[4].c = maxx; + tri->plane[4].c = bbox.x1+1; tri->plane[4].ei = -1; tri->plane[4].eo = 0; tri->plane[5].dcdx = 0; tri->plane[5].dcdy = 1; - tri->plane[5].c = 1-miny; + tri->plane[5].c = 1-bbox.y0; tri->plane[5].ei = 0; tri->plane[5].eo = 1; tri->plane[6].dcdx = 0; tri->plane[6].dcdy = -1; - tri->plane[6].c = maxy; + tri->plane[6].c = bbox.y1+1; tri->plane[6].ei = -1; tri->plane[6].eo = 0; } + lp_setup_bin_triangle( setup, tri, &bbox, nr_planes ); +} + + +void +lp_setup_bin_triangle( struct lp_setup_context *setup, + struct lp_rast_triangle *tri, + const struct u_rect *bbox, + int nr_planes ) +{ + struct lp_scene *scene = setup->scene; + struct lp_fragment_shader_variant *variant = setup->fs.current.variant; + int ix0, ix1, iy0, iy1; + int i; /* * All fields of 'tri' are now set. The remaining code here is @@ -643,10 +442,30 @@ do_triangle_ccw(struct lp_setup_context *setup, /* Convert to tile coordinates, and inclusive ranges: */ - ix0 = minx / TILE_SIZE; - iy0 = miny / TILE_SIZE; - ix1 = (maxx-1) / TILE_SIZE; - iy1 = (maxy-1) / TILE_SIZE; + if (nr_planes == 3) { + int ix0 = bbox->x0 / 16; + int iy0 = bbox->y0 / 16; + int ix1 = bbox->x1 / 16; + int iy1 = bbox->y1 / 16; + + if (iy0 == iy1 && ix0 == ix1) + { + + /* Triangle is contained in a single 16x16 block: + */ + int mask = (ix0 & 3) | ((iy0 & 3) << 4); + + lp_scene_bin_command( scene, ix0/4, iy0/4, + lp_rast_triangle_3_16, + lp_rast_arg_triangle(tri, mask) ); + return; + } + } + + ix0 = bbox->x0 / TILE_SIZE; + iy0 = bbox->y0 / TILE_SIZE; + ix1 = bbox->x1 / TILE_SIZE; + iy1 = bbox->y1 / TILE_SIZE; /* * Clamp to framebuffer size @@ -799,9 +618,10 @@ static void triangle_both( struct lp_setup_context *setup, const float fy = v1[0][1] - v2[0][1]; /* det = cross(e,f).z */ - if (ex * fy - ey * fx < 0.0f) + const float det = ex * fy - ey * fx; + if (det < 0.0f) triangle_ccw( setup, v0, v1, v2 ); - else + else if (det > 0.0f) triangle_cw( setup, v0, v1, v2 ); } diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c index 77bec4640b..edd723f65f 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_derived.c +++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c @@ -74,6 +74,15 @@ compute_vertex_info(struct llvmpipe_context *llvmpipe) vs_index = draw_find_shader_output(llvmpipe->draw, lpfs->info.input_semantic_name[i], lpfs->info.input_semantic_index[i]); + if (vs_index < 0) { + /* + * This can happen with sprite coordinates - the vertex + * shader doesn't need to provide an output as we generate + * them internally. However, lets keep pretending that there + * is something there to not confuse other code. + */ + vs_index = 0; + } /* This can be pre-computed, except for flatshade: */ @@ -125,6 +134,17 @@ compute_vertex_info(struct llvmpipe_context *llvmpipe) inputs[i].src_index = vinfo->num_attribs; draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_PERSPECTIVE, vs_index); } + + /* Figure out if we need pointsize as well. + */ + vs_index = draw_find_shader_output(llvmpipe->draw, + TGSI_SEMANTIC_PSIZE, 0); + + if (vs_index > 0) { + llvmpipe->psize_slot = vinfo->num_attribs; + draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, vs_index); + } + llvmpipe->num_inputs = lpfs->info.num_inputs; draw_compute_vertex_size(vinfo); diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c index dbca49a2ef..33c1a49efe 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_fs.c +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c @@ -808,7 +808,7 @@ generate_variant(struct llvmpipe_context *lp, variant->list_item_local.base = variant; variant->no = shader->variants_created++; - memcpy(&variant->key, key, sizeof *key); + memcpy(&variant->key, key, shader->variant_key_size); if (gallivm_debug & GALLIVM_DEBUG_IR) { debug_printf("llvmpipe: Creating fragment shader #%u variant #%u:\n", @@ -840,6 +840,7 @@ llvmpipe_create_fs_state(struct pipe_context *pipe, const struct pipe_shader_state *templ) { struct lp_fragment_shader *shader; + int nr_samplers; shader = CALLOC_STRUCT(lp_fragment_shader); if (!shader) @@ -854,6 +855,11 @@ llvmpipe_create_fs_state(struct pipe_context *pipe, /* we need to keep a local copy of the tokens */ shader->base.tokens = tgsi_dup_tokens(templ->tokens); + nr_samplers = shader->info.file_max[TGSI_FILE_SAMPLER] + 1; + + shader->variant_key_size = Offset(struct lp_fragment_shader_variant_key, + sampler[nr_samplers]); + if (LP_DEBUG & DEBUG_TGSI) { unsigned attrib; debug_printf("llvmpipe: Create fragment shader #%u %p:\n", shader->no, (void *) shader); @@ -921,7 +927,6 @@ static void llvmpipe_delete_fs_state(struct pipe_context *pipe, void *fs) { struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe); - struct pipe_fence_handle *fence = NULL; struct lp_fragment_shader *shader = fs; struct lp_fs_variant_list_item *li; @@ -934,12 +939,7 @@ llvmpipe_delete_fs_state(struct pipe_context *pipe, void *fs) * Flushing alone might not sufficient we need to wait on it too. */ - llvmpipe_flush(pipe, 0, &fence); - - if (fence) { - pipe->screen->fence_finish(pipe->screen, fence, 0); - pipe->screen->fence_reference(pipe->screen, &fence, NULL); - } + llvmpipe_finish(pipe, __FUNCTION__); li = first_elem(&shader->variants); while(!at_end(&shader->variants, li)) { @@ -1027,7 +1027,7 @@ make_variant_key(struct llvmpipe_context *lp, { unsigned i; - memset(key, 0, sizeof *key); + memset(key, 0, shader->variant_key_size); if (lp->framebuffer.zsbuf) { if (lp->depth_stencil->depth.enabled) { @@ -1097,9 +1097,17 @@ make_variant_key(struct llvmpipe_context *lp, } } - for(i = 0; i < PIPE_MAX_SAMPLERS; ++i) - if(shader->info.file_mask[TGSI_FILE_SAMPLER] & (1 << i)) - lp_sampler_static_state(&key->sampler[i], lp->fragment_sampler_views[i], lp->sampler[i]); + /* This value will be the same for all the variants of a given shader: + */ + key->nr_samplers = shader->info.file_max[TGSI_FILE_SAMPLER] + 1; + + for(i = 0; i < key->nr_samplers; ++i) { + if(shader->info.file_mask[TGSI_FILE_SAMPLER] & (1 << i)) { + lp_sampler_static_state(&key->sampler[i], + lp->fragment_sampler_views[i], + lp->sampler[i]); + } + } } /** @@ -1118,7 +1126,7 @@ llvmpipe_update_fs(struct llvmpipe_context *lp) li = first_elem(&shader->variants); while(!at_end(&shader->variants, li)) { - if(memcmp(&li->base->key, &key, sizeof key) == 0) { + if(memcmp(&li->base->key, &key, shader->variant_key_size) == 0) { variant = li->base; break; } @@ -1134,19 +1142,14 @@ llvmpipe_update_fs(struct llvmpipe_context *lp) unsigned i; if (lp->nr_fs_variants >= LP_MAX_SHADER_VARIANTS) { struct pipe_context *pipe = &lp->pipe; - struct pipe_fence_handle *fence = NULL; /* * XXX: we need to flush the context until we have some sort of reference * counting in fragment shaders as they may still be binned * Flushing alone might not be sufficient we need to wait on it too. */ - llvmpipe_flush(pipe, 0, &fence); + llvmpipe_finish(pipe, __FUNCTION__); - if (fence) { - pipe->screen->fence_finish(pipe->screen, fence, 0); - pipe->screen->fence_reference(pipe->screen, &fence, NULL); - } for (i = 0; i < LP_MAX_SHADER_VARIANTS / 4; i++) { struct lp_fs_variant_list_item *item = last_elem(&lp->fs_variants_list); remove_shader_variant(lp, item->base); diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.h b/src/gallium/drivers/llvmpipe/lp_state_fs.h index 37900fc544..33c480010d 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_fs.h +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.h @@ -53,13 +53,10 @@ struct lp_fragment_shader_variant_key struct pipe_blend_state blend; enum pipe_format zsbuf_format; unsigned nr_cbufs:8; + unsigned nr_samplers:8; /* actually derivable from just the shader */ unsigned flatshade:1; unsigned occlusion_count:1; - struct { - ubyte colormask; - } cbuf_blend[PIPE_MAX_COLOR_BUFS]; - struct lp_sampler_static_state sampler[PIPE_MAX_SAMPLERS]; }; @@ -97,6 +94,7 @@ struct lp_fragment_shader struct lp_fs_variant_list_item variants; /* For debugging/profiling purposes */ + unsigned variant_key_size; unsigned no; unsigned variants_created; unsigned variants_cached; diff --git a/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c b/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c index afd3e0b21c..0bad7320f3 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c +++ b/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c @@ -73,7 +73,13 @@ llvmpipe_bind_rasterizer_state(struct pipe_context *pipe, void *handle) llvmpipe->rasterizer->gl_rasterization_rules); lp_setup_set_flatshade_first( llvmpipe->setup, llvmpipe->rasterizer->flatshade_first); - } + lp_setup_set_line_state( llvmpipe->setup, + llvmpipe->rasterizer->line_width); + lp_setup_set_point_state( llvmpipe->setup, + llvmpipe->rasterizer->point_size, + llvmpipe->rasterizer->point_size_per_vertex, + llvmpipe->rasterizer->sprite_coord_enable); + } llvmpipe->dirty |= LP_NEW_RASTERIZER; } diff --git a/src/gallium/drivers/llvmpipe/lp_state_vertex.c b/src/gallium/drivers/llvmpipe/lp_state_vertex.c index d86e66b4fb..fb29423dd3 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_vertex.c +++ b/src/gallium/drivers/llvmpipe/lp_state_vertex.c @@ -100,7 +100,7 @@ llvmpipe_set_index_buffer(struct pipe_context *pipe, else memset(&llvmpipe->index_buffer, 0, sizeof(llvmpipe->index_buffer)); - /* TODO make this more like a state */ + draw_set_index_buffer(llvmpipe->draw, ib); } void diff --git a/src/gallium/drivers/llvmpipe/lp_surface.c b/src/gallium/drivers/llvmpipe/lp_surface.c index f761e82850..63ddc669c2 100644 --- a/src/gallium/drivers/llvmpipe/lp_surface.c +++ b/src/gallium/drivers/llvmpipe/lp_surface.c @@ -68,14 +68,16 @@ lp_resource_copy(struct pipe_context *pipe, 0, /* flush_flags */ FALSE, /* read_only */ TRUE, /* cpu_access */ - FALSE); /* do_not_block */ + FALSE, + "blit dst"); /* do_not_block */ llvmpipe_flush_resource(pipe, src, subsrc.face, subsrc.level, 0, /* flush_flags */ TRUE, /* read_only */ TRUE, /* cpu_access */ - FALSE); /* do_not_block */ + FALSE, + "blit src"); /* do_not_block */ /* printf("surface copy from %u to %u: %u,%u to %u,%u %u x %u\n", diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c index 25112c10a6..5832ea2744 100644 --- a/src/gallium/drivers/llvmpipe/lp_texture.c +++ b/src/gallium/drivers/llvmpipe/lp_texture.c @@ -67,6 +67,7 @@ resource_is_texture(const struct pipe_resource *resource) return FALSE; case PIPE_TEXTURE_1D: case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_3D: case PIPE_TEXTURE_CUBE: return TRUE; @@ -583,7 +584,8 @@ llvmpipe_get_transfer(struct pipe_context *pipe, 0, /* flush_flags */ read_only, TRUE, /* cpu_access */ - do_not_block)) { + do_not_block, + "transfer dest")) { /* * It would have blocked, but state tracker requested no to. */ diff --git a/src/gallium/drivers/nouveau/nouveau_class.h b/src/gallium/drivers/nouveau/nouveau_class.h index f44979e562..d9f35b4c4b 100644 --- a/src/gallium/drivers/nouveau/nouveau_class.h +++ b/src/gallium/drivers/nouveau/nouveau_class.h @@ -6189,6 +6189,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV34TCL_FP_REG_CONTROL_UNK1_MASK 0xffff0000 #define NV34TCL_FP_REG_CONTROL_UNK0_SHIFT 0 #define NV34TCL_FP_REG_CONTROL_UNK0_MASK 0x0000ffff +#define NV34TCL_FLATSHADE_FIRST 0x00001454 +#define NV34TCL_EDGEFLAG_ENABLE 0x0000145c #define NV34TCL_VP_CLIP_PLANES_ENABLE 0x00001478 #define NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 (1 << 1) #define NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1 (1 << 5) @@ -6222,10 +6224,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV34TCL_VTXFMT__SIZE 0x00000010 #define NV34TCL_VTXFMT_TYPE_SHIFT 0 #define NV34TCL_VTXFMT_TYPE_MASK 0x0000000f -#define NV34TCL_VTXFMT_TYPE_FLOAT 0x00000002 -#define NV34TCL_VTXFMT_TYPE_HALF 0x00000003 -#define NV34TCL_VTXFMT_TYPE_UBYTE 0x00000004 -#define NV34TCL_VTXFMT_TYPE_USHORT 0x00000005 +#define NV34TCL_VTXFMT_TYPE_16_SNORM 0x00000001 +#define NV34TCL_VTXFMT_TYPE_32_FLOAT 0x00000002 +#define NV34TCL_VTXFMT_TYPE_16_FLOAT 0x00000003 +#define NV34TCL_VTXFMT_TYPE_8_UNORM 0x00000004 +#define NV34TCL_VTXFMT_TYPE_16_SSCALED 0x00000005 +#define NV34TCL_VTXFMT_TYPE_11_11_10_SNORM 0x00000006 +#define NV34TCL_VTXFMT_TYPE_8_USCALED 0x00000007 #define NV34TCL_VTXFMT_SIZE_SHIFT 4 #define NV34TCL_VTXFMT_SIZE_MASK 0x000000f0 #define NV34TCL_VTXFMT_STRIDE_SHIFT 8 @@ -6368,6 +6373,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV34TCL_TX_FORMAT_FORMAT_R8G8B8_RECT 0x00001e00 #define NV34TCL_TX_FORMAT_FORMAT_A8L8_RECT 0x00002000 #define NV34TCL_TX_FORMAT_FORMAT_DSDT8 0x00002800 +#define NV34TCL_TX_FORMAT_FORMAT_Z24 0x2a00 +#define NV34TCL_TX_FORMAT_FORMAT_Z24_RECT 0x2b00 /* XXX: guess! */ +#define NV34TCL_TX_FORMAT_FORMAT_Z16 0x2c00 +#define NV34TCL_TX_FORMAT_FORMAT_Z16_RECT 0x2d00 /* XXX: guess! */ #define NV34TCL_TX_FORMAT_FORMAT_HILO16 0x00003300 #define NV34TCL_TX_FORMAT_FORMAT_HILO16_RECT 0x00003600 #define NV34TCL_TX_FORMAT_FORMAT_HILO8 0x00004400 diff --git a/src/gallium/drivers/nouveau/nouveau_screen.c b/src/gallium/drivers/nouveau/nouveau_screen.c index 513e5e02bc..ebb21a6e5a 100644 --- a/src/gallium/drivers/nouveau/nouveau_screen.c +++ b/src/gallium/drivers/nouveau/nouveau_screen.c @@ -258,6 +258,7 @@ nouveau_screen_fini(struct nouveau_screen *screen) { struct pipe_winsys *ws = screen->base.winsys; nouveau_channel_free(&screen->channel); - ws->destroy(ws); + if (ws) + ws->destroy(ws); } diff --git a/src/gallium/drivers/nouveau/nouveau_util.h b/src/gallium/drivers/nouveau/nouveau_util.h deleted file mode 100644 index b165f7a611..0000000000 --- a/src/gallium/drivers/nouveau/nouveau_util.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef __NOUVEAU_UTIL_H__ -#define __NOUVEAU_UTIL_H__ - -/* Determine how many vertices can be pushed into the command stream. - * Where the remaining space isn't large enough to represent all verices, - * split the buffer at primitive boundaries. - * - * Returns a count of vertices that can be rendered, and an index to - * restart drawing at after a flush. - */ -static INLINE unsigned -nouveau_vbuf_split(unsigned remaining, unsigned overhead, unsigned vpp, - unsigned mode, unsigned start, unsigned count, - unsigned *restart) -{ - int max, adj = 0; - - max = remaining - overhead; - if (max < 0) - return 0; - - max *= vpp; - if (max >= count) - return count; - - switch (mode) { - case PIPE_PRIM_POINTS: - break; - case PIPE_PRIM_LINES: - max = max & 1; - break; - case PIPE_PRIM_TRIANGLES: - max = max - (max % 3); - break; - case PIPE_PRIM_QUADS: - max = max & ~3; - break; - case PIPE_PRIM_LINE_LOOP: - case PIPE_PRIM_LINE_STRIP: - if (max < 2) - max = 0; - adj = 1; - break; - case PIPE_PRIM_POLYGON: - case PIPE_PRIM_TRIANGLE_STRIP: - case PIPE_PRIM_TRIANGLE_FAN: - if (max < 3) - max = 0; - adj = 2; - break; - case PIPE_PRIM_QUAD_STRIP: - if (max < 4) - max = 0; - adj = 3; - break; - default: - assert(0); - } - - *restart = start + max - adj; - return max; -} - -/* Integer base-2 logarithm, rounded towards zero. */ -static INLINE unsigned log2i(unsigned i) -{ - unsigned r = 0; - - if (i & 0xffff0000) { - i >>= 16; - r += 16; - } - if (i & 0x0000ff00) { - i >>= 8; - r += 8; - } - if (i & 0x000000f0) { - i >>= 4; - r += 4; - } - if (i & 0x0000000c) { - i >>= 2; - r += 2; - } - if (i & 0x00000002) { - r += 1; - } - return r; -} - -#endif diff --git a/src/gallium/drivers/nv50/nv50_miptree.c b/src/gallium/drivers/nv50/nv50_miptree.c index 12b5ad106c..dd0e8fd41b 100644 --- a/src/gallium/drivers/nv50/nv50_miptree.c +++ b/src/gallium/drivers/nv50/nv50_miptree.c @@ -238,7 +238,8 @@ nv50_miptree_from_handle(struct pipe_screen *pscreen, unsigned stride; /* Only supports 2D, non-mipmapped textures for the moment */ - if (template->target != PIPE_TEXTURE_2D || + if ((template->target != PIPE_TEXTURE_2D && + template->target != PIPE_TEXTURE_RECT) || template->last_level != 0 || template->depth0 != 1) return NULL; diff --git a/src/gallium/drivers/nv50/nv50_push.c b/src/gallium/drivers/nv50/nv50_push.c index 0091927a98..380f69406a 100644 --- a/src/gallium/drivers/nv50/nv50_push.c +++ b/src/gallium/drivers/nv50/nv50_push.c @@ -108,8 +108,9 @@ emit_vertex(struct push_context *ctx, unsigned n) int i; if (ctx->edgeflag_attr < 16) { - float *edgeflag = (uint8_t *)ctx->attr[ctx->edgeflag_attr].map + - ctx->attr[ctx->edgeflag_attr].stride * n; + float *edgeflag = (float *) + ((uint8_t *)ctx->attr[ctx->edgeflag_attr].map + + ctx->attr[ctx->edgeflag_attr].stride * n); if (*edgeflag != ctx->edgeflag) { BEGIN_RING(chan, tesla, NV50TCL_EDGEFLAG_ENABLE, 1); diff --git a/src/gallium/drivers/nv50/nv50_tex.c b/src/gallium/drivers/nv50/nv50_tex.c index 5535818370..658324ec5b 100644 --- a/src/gallium/drivers/nv50/nv50_tex.c +++ b/src/gallium/drivers/nv50/nv50_tex.c @@ -83,6 +83,9 @@ nv50_tex_construct(struct nv50_sampler_view *view) case PIPE_TEXTURE_2D: tic[2] |= NV50TIC_0_2_TARGET_2D; break; + case PIPE_TEXTURE_RECT: + tic[2] |= NV50TIC_0_2_TARGET_RECT; + break; case PIPE_TEXTURE_3D: tic[2] |= NV50TIC_0_2_TARGET_3D; break; diff --git a/src/gallium/drivers/nvfx/Makefile b/src/gallium/drivers/nvfx/Makefile index c1d57ca396..6cbbad699e 100644 --- a/src/gallium/drivers/nvfx/Makefile +++ b/src/gallium/drivers/nvfx/Makefile @@ -4,7 +4,7 @@ include $(TOP)/configs/current LIBNAME = nvfx C_SOURCES = \ - nv04_surface_2d.c \ + nv04_2d.c \ nvfx_buffer.c \ nvfx_context.c \ nvfx_clear.c \ @@ -14,6 +14,7 @@ C_SOURCES = \ nv30_fragtex.c \ nv40_fragtex.c \ nvfx_miptree.c \ + nvfx_push.c \ nvfx_query.c \ nvfx_resource.c \ nvfx_screen.c \ diff --git a/src/gallium/drivers/nvfx/SConscript b/src/gallium/drivers/nvfx/SConscript index 02d931b10e..80e3ef2257 100644 --- a/src/gallium/drivers/nvfx/SConscript +++ b/src/gallium/drivers/nvfx/SConscript @@ -9,7 +9,7 @@ env.PrependUnique(delete_existing=1, CPPPATH = [ nvfx = env.ConvenienceLibrary( target = 'nvfx', source = [ - 'nv04_surface_2d.c', + 'nv04_2d.c', 'nvfx_buffer.c', 'nvfx_context.c', 'nvfx_clear.c', @@ -19,6 +19,7 @@ nvfx = env.ConvenienceLibrary( 'nv30_fragtex.c', 'nv40_fragtex.c', 'nvfx_miptree.c', + 'nvfx_push.c', 'nvfx_query.c', 'nvfx_resource.c', 'nvfx_screen.c', diff --git a/src/gallium/drivers/nvfx/nv04_2d.c b/src/gallium/drivers/nvfx/nv04_2d.c new file mode 100644 index 0000000000..c05312219b --- /dev/null +++ b/src/gallium/drivers/nvfx/nv04_2d.c @@ -0,0 +1,1341 @@ +/************************************************************************** + * + * Copyright 2009 Ben Skeggs + * Copyright 2009 Younes Manton + * Copyright 2010 Luca Barbieri + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + **************************************************************************/ + +/* this code has no Mesa or Gallium dependency and can be reused in the classic Mesa driver or DDX */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <nouveau/nouveau_class.h> +#include <nouveau/nouveau_device.h> +#include <nouveau/nouveau_pushbuf.h> +#include <nouveau/nouveau_channel.h> +#include <nouveau/nouveau_bo.h> +#include <nouveau/nouveau_notifier.h> +#include <nouveau/nouveau_grobj.h> +#include "nv04_2d.h" + +/* avoid depending on Mesa/Gallium */ +#ifdef __GNUC__ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) !!(x) +#define unlikely(x) !!(x) +#endif + +#define MIN2( A, B ) ( (A)<(B) ? (A) : (B) ) +#define MAX2( A, B ) ( (A)>(B) ? (A) : (B) ) + +struct nv04_2d_context +{ + struct nouveau_notifier *ntfy; + struct nouveau_grobj *surf2d; + struct nouveau_grobj *swzsurf; + struct nouveau_grobj *m2mf; + struct nouveau_grobj *rect; + struct nouveau_grobj *sifm; + struct nouveau_grobj *blit; +}; + +static inline int +align(int value, int alignment) +{ + return (value + alignment - 1) & ~(alignment - 1); +} + +static inline int +util_is_pot(unsigned x) +{ + return (x & (x - 1)) == 0; +} + +/* Integer base-2 logarithm, rounded towards zero. */ +static inline unsigned log2i(unsigned i) +{ + unsigned r = 0; + + if (i & 0xffff0000) { + i >>= 16; + r += 16; + } + if (i & 0x0000ff00) { + i >>= 8; + r += 8; + } + if (i & 0x000000f0) { + i >>= 4; + r += 4; + } + if (i & 0x0000000c) { + i >>= 2; + r += 2; + } + if (i & 0x00000002) { + r += 1; + } + return r; +} + +//#define NV04_REGION_DEBUG + +// Yes, we really want to inline everything, since all the functions are used only once +#if defined(__GNUC__) && defined(DEBUG) +#define inline __attribute__((always_inline)) inline +#endif + +static inline unsigned +nv04_swizzle_bits_square(unsigned x, unsigned y) +{ + unsigned u = (x & 0x001) << 0 | + (x & 0x002) << 1 | + (x & 0x004) << 2 | + (x & 0x008) << 3 | + (x & 0x010) << 4 | + (x & 0x020) << 5 | + (x & 0x040) << 6 | + (x & 0x080) << 7 | + (x & 0x100) << 8 | + (x & 0x200) << 9 | + (x & 0x400) << 10 | + (x & 0x800) << 11; + + unsigned v = (y & 0x001) << 1 | + (y & 0x002) << 2 | + (y & 0x004) << 3 | + (y & 0x008) << 4 | + (y & 0x010) << 5 | + (y & 0x020) << 6 | + (y & 0x040) << 7 | + (y & 0x080) << 8 | + (y & 0x100) << 9 | + (y & 0x200) << 10 | + (y & 0x400) << 11 | + (y & 0x800) << 12; + return v | u; +} + +/* rectangular swizzled textures are linear concatenations of swizzled square tiles */ +static inline unsigned +nv04_swizzle_bits_2d(unsigned x, unsigned y, unsigned w, unsigned h) +{ + if(h <= 1) + return x; + else + { + unsigned s = MIN2(w, h); + unsigned m = s - 1; + return (((x | y) & ~m) * s) | nv04_swizzle_bits_square(x & m, y & m); + } +} + +// general 3D texture case +static inline unsigned +nv04_swizzle_bits(unsigned x, unsigned y, unsigned z, unsigned w, unsigned h, unsigned d) +{ + if(d <= 1) + return nv04_swizzle_bits_2d(x, y, w, h); + else + { + // TODO: autogenerate code for all possible texture sizes (13 * 13 * 13 with dims <= 4096) and do a single indirect call + unsigned v = 0; + w >>= 1; + h >>= 1; + d >>= 1; + for(int i = 0;;) + { + int oldi = i; + if(likely(w)) + { + v |= (x & 1) << i; + x >>= 1; + w >>= 1; + ++i; + } + + if(likely(h)) + { + v |= (y & 1) << i; + y >>= 1; + h >>= 1; + ++i; + } + + if(likely(d)) + { + v |= (z & 1) << i; + z >>= 1; + d >>= 1; + ++i; + } + + if(i == oldi) + break; + } + return v; + } +} + +unsigned +nv04_region_begin(struct nv04_region* rgn, unsigned w, unsigned h) +{ + if(rgn->pitch) + return rgn->pitch * rgn->y + (rgn->x << rgn->bpps); + else + return nv04_swizzle_bits(rgn->x, rgn->y, rgn->z, rgn->w, rgn->h, rgn->d) << rgn->bpps; +} + +unsigned +nv04_region_end(struct nv04_region* rgn, unsigned w, unsigned h) +{ + if(rgn->pitch) + return rgn->pitch * (rgn->y + h - 1) + ((rgn->x + w) << rgn->bpps); + else + return (nv04_swizzle_bits(rgn->x + w - 1, rgn->y + h - 1, rgn->z, rgn->w, rgn->h, rgn->d) + 1) << rgn->bpps; +} + +// *pitch = -1 -> use 3D swizzling for (x, y), *pitch = 0 -> use 2D swizzling, other *pitch -> use linear calculations +// returns 2 if pixel order is 3D-swizzled and 1 if subrect is 2D-swizzled +/* *pitch == -1 ret = 0 -> 3D swizzled subrect + * *pitch == 0 ret = 0 -> 2D swizzled subrect + * *pitch > 0 ret = 0 -> linear subrect + * *pitch > 0 ret = 1 -> linear subrect, but with swizzled 3D data inside + */ + +static inline void +nv04_region_print(struct nv04_region* rgn) +{ + fprintf(stderr, "<%i[%i]> ", rgn->bo->handle, rgn->offset); + if(rgn->pitch) + fprintf(stderr, "lin %i", rgn->pitch); + else + fprintf(stderr, "swz %ix%ix%i", rgn->w, rgn->h, rgn->d); + fprintf(stderr, " (%i, %i, %i)", rgn->x, rgn->y, rgn->z); +} + +static inline void +nv04_region_assert(struct nv04_region* rgn, unsigned w, unsigned h) +{ + unsigned end = rgn->offset + nv04_region_end(rgn, w, h); + + assert(rgn->offset <= (int)rgn->bo->size); + assert(end <= rgn->bo->size); + (void) end; + if(!rgn->pitch) { + assert(util_is_pot(rgn->w)); + assert(util_is_pot(rgn->h)); + } +} + +/* determine if region can be linearized or fake-linearized */ +static inline int +nv04_region_is_contiguous(struct nv04_region* rgn, int w, int h) +{ + int surf_min; + int rect_min; + + if(rgn->pitch) + return rgn->pitch == w << rgn->bpps; + + // redundant, but this is the fast path for the common case + if(w == rgn->w && h == rgn->h && rgn->d <= 1) + return 1; + + // must be POT + if((w & (w - 1)) || (h & (h - 1))) + return 0; + + // must be aligned + if((rgn->x & (w - 1)) || (rgn->y & (h - 1))) + return 0; + + if(rgn->d > 1) + return 0; + + surf_min = MIN2(rgn->w, rgn->h); + rect_min = MIN2(w, h); + + if((rect_min == surf_min) || (w == h) || (w == 2 * h)) + return 1; + + return 0; +} + +// double the pitch until it is larger than the alignment, or the height becomes odd or 1 +static inline void +nv04_region_contiguous_shape(struct nv04_region* rgn, int* w, int* h, int align) +{ + while(!(*h & 1) && (*w << rgn->bpps) < (1 << align)) + { + *w <<= 1; + *h >>= 1; + } + + while((*w << rgn->bpps) > 16384 && !(*w & 1)) + { + *w >>= 1; + *h <<= 1; + } + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tCONTIGUOUS %ix%i\n", *w, *h); +#endif +} + +static inline void +nv04_region_linearize_contiguous(struct nv04_region* rgn, unsigned w, unsigned h) +{ + int pos; + if(rgn->pitch) + { + rgn->offset += rgn->y * rgn->pitch + (rgn->x << rgn->bpps); + rgn->x = 0; + rgn->y = 0; + } + else + { + rgn->offset += (rgn->w * rgn->h * rgn->z) << rgn->bpps; + pos = nv04_swizzle_bits(rgn->x, rgn->y, rgn->z, rgn->w, rgn->h, rgn->d); + rgn->x = pos & (w - 1); + rgn->y = pos / w; + } + rgn->pitch = w << rgn->bpps; + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tLINEARIZE "); + nv04_region_print(rgn); + fprintf(stderr, "\n"); +#endif +} + + /* preserve the offset! */ + /* + rgn->pitch = util_format_get_stride(rgn->format, w); + int pos = nv04_swizzle_bits(rgn->x, rgn->y, rgn->z, rgn->w, rgn->h, rgn->d); + rgn->x = pos & (w - 1); + rgn->y = pos & ~(w - 1); + */ + + /* + rgn->offset += + rgn->pitch = util_format_get_stride(rgn->format, w); + rgn->x = 0; + rgn->y = 0; + */ + +/* This code will get used for, and always succeed on: + * - 4x2 1bpp swizzled texture mipmap levels + * - linear regions created by linearization + * + * This code will get used for, and MAY work for: + * - misaligned texture blanket + * - linear surfaces created without wide_pitch (in this case, it will only work if we are lucky) + * + * The general case requires splitting the region in 2. + */ +static inline int +nv04_region_do_align_offset(struct nv04_region* rgn, unsigned w, unsigned h, int shift) +{ + if(rgn->pitch > 0) + { + int delta; + + assert(!(rgn->offset & ((1 << rgn->bpps) - 1))); // fatal! + delta = rgn->offset & ((1 << shift) - 1); + + if(h <= 1) + { + rgn->x += delta >> rgn->bpps; + rgn->offset -= delta; + rgn->pitch = align((rgn->x + w) << rgn->bpps, 1 << shift); + } + else + { + int newxo = (rgn->x << rgn->bpps) + delta; + int dy = newxo / rgn->pitch; + newxo -= dy * rgn->pitch; + if((newxo + (w << rgn->bpps)) > rgn->pitch) + { + // TODO: split the region into two rectangles (!) if *really* necessary, unless the hardware actually supports "wrapping" rectangles + // this does not happen if the surface is pitch-aligned, which it should always be + assert(0); + return -1; + } + rgn->x = newxo >> rgn->bpps; + rgn->y += dy; + } + } + else + { + int size; + int min; + int v; + + // we don't care about the alignment of 3D surfaces since the 2D engine can't use them + if(rgn->d < 0) + return -1; + + min = MIN2(rgn->w, rgn->h); + size = min * min << rgn->bpps; + + // this is unfixable, and should not be happening + if(rgn->offset & (size - 1)) + return -1; + + v = (rgn->offset & ((1 << shift) - 1)) / size; + rgn->offset -= v * size; + + if(rgn->h == min) + { + unsigned w; + rgn->x += rgn->h * v; + w = rgn->w + rgn->h * v; + + while(rgn->w < w) + rgn->w += rgn->w; + } + else + { + unsigned h; + rgn->y += rgn->w * v; + h = rgn->h + rgn->w * v; + + while(rgn->h < h) + rgn->h += rgn->h; + } + } + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tALIGNED "); + nv04_region_print(rgn); + fprintf(stderr, "\n"); +#endif + return 0; +} + +// both pitch and shift +// will leave the region unchanged if it fails +static inline int +nv04_region_align(struct nv04_region* rgn, unsigned w, unsigned h, int shift) +{ + if(rgn->pitch & ((1 << shift) - 1)) + { + if(h == 1) + goto do_align; /* this will fix pitch too in this case */ + else + return -1; + } + + if(rgn->offset & ((1 << shift) - 1)) + { + do_align: + if(nv04_region_do_align_offset(rgn, w, h, shift)) + return -1; + } + return 0; +} + +/* this contains 22 different copy loops after preprocessing. unfortunately, it's necessary */ +void +nv04_region_copy_cpu(struct nv04_region* dst, struct nv04_region* src, int w, int h) +{ + uint8_t* mdst; + uint8_t* msrc; + int size; + + if(dst->bo != src->bo) + { + nouveau_bo_map(dst->bo, NOUVEAU_BO_WR); + nouveau_bo_map(src->bo, NOUVEAU_BO_RD); + } + else + nouveau_bo_map(dst->bo, NOUVEAU_BO_WR | NOUVEAU_BO_RD); + + mdst = (uint8_t*)dst->bo->map + dst->offset; + msrc = (uint8_t*)src->bo->map + src->offset; + + size = w << dst->bpps; + + nv04_region_assert(dst, w, h); + nv04_region_assert(src, w, h); + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tRGN_COPY_CPU [%i, %i: %i] ", w, h, dst->bpps); + for(int i = 0; i < 2; ++i) + { + nv04_region_print(i ? src : dst); + fprintf(stderr, i ? "\n" : " <- "); + } + +// for(int i = 0; i < 16; ++i) +// fprintf(stderr, "%02x ", msrc[i]); +// fprintf(stderr, "\n"); +#endif + + // TODO: support overlapping copies! + if(src->pitch && dst->pitch) + { + mdst += dst->y * dst->pitch + (dst->x << dst->bpps); + msrc += src->y * src->pitch + (src->x << src->bpps); + if(dst->bo != src->bo) + goto simple; + else if(mdst < msrc) + { + if(mdst + size <= msrc) + { +simple: + for(int iy = 0; iy < h; ++iy) + { + assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size); + assert(msrc + size <= (uint8_t*)src->bo->map + src->bo->size); + memcpy(mdst, msrc, size); + msrc += src->pitch; mdst += dst->pitch; + } + } + else + { + for(int iy = 0; iy < h; ++iy) + { + assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size); + assert(msrc + size <= (uint8_t*)src->bo->map + src->bo->size); + memmove(mdst, msrc, size); + msrc += src->pitch; mdst += dst->pitch; + } + } + } + else + { + /* copy backwards so we don't destroy data we have to read yet */ + if(msrc + size <= mdst) + { + for(int iy = h - 1; iy >= 0; --iy) + { + assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size); + assert(msrc + size <= (uint8_t*)src->bo->map + src->bo->size); + memcpy(mdst, msrc, size); + msrc += src->pitch; mdst += dst->pitch; + } + } + else + { + for(int iy = h - 1; iy >= 0; --iy) + { + assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size); + assert(msrc + size <= (uint8_t*)src->bo->map + src->bo->size); + memmove(mdst, msrc, size); + msrc += src->pitch; mdst += dst->pitch; + } + } + } + } + else + { + int* dswx = NULL; + int* dswy = NULL; + int* sswx = NULL; + int* sswy = NULL; + int dir; + + if(!dst->pitch) + { + dswx = alloca(w * sizeof(int)); + for(int ix = 0; ix < w; ++ix) // we are adding, so z cannot be contributed by both + dswx[ix] = nv04_swizzle_bits(dst->x + ix, 0, 0, dst->w, dst->h, dst->d); + dswy = alloca(h * sizeof(int)); + for(int iy = 0; iy < h; ++iy) + dswy[iy] = nv04_swizzle_bits(0, dst->y + iy, dst->z, dst->w, dst->h, dst->d); + } + + if(!src->pitch) + { + sswx = alloca(w * sizeof(int)); + for(int ix = 0; ix < w; ++ix) + sswx[ix] = nv04_swizzle_bits(src->x + ix, 0, 0, src->w, src->h, src->d); + sswy = alloca(h * sizeof(int)); + for(int iy = 0; iy < h; ++iy) + sswy[iy] = nv04_swizzle_bits(0, src->y + iy, src->z, src->w, src->h, src->d); + } + + dir = 1; + /* do backwards copies for overlapping swizzled surfaces */ + if(dst->pitch == src->pitch && dst->offset == src->offset) + { + if(dst->y > src->y || (dst->y == src->y && dst->x > src->x)) + dir = -1; + } + +#define SWIZZLED_COPY_LOOPS + if(dir == 1) + { + int dir = 1; +#define LOOP_Y for(int iy = 0; iy < h; ++iy) +#define LOOP_X for(int ix = 0; ix < w; ++ix) +#include "nv04_2d_loops.h" +#undef LOOP_X +#undef LOOP_Y + } + else + { + int dir = -1; +#define LOOP_Y for(int iy = h - 1; iy >= 0; --iy) +#define LOOP_X for(int ix = w - 1; ix >= 0; --ix) +#include "nv04_2d_loops.h" +#undef LOOP_X +#undef LOOP_Y + } +#undef SWIZZLED_COPY_LOOP + } + + if(src->bo != dst->bo) + nouveau_bo_unmap(src->bo); + nouveau_bo_unmap(dst->bo); +} + +/* TODO: if the destination is swizzled, we are doing random writes, which causes write combining to fail + * the alternative is to read, modify and copy back, which may or may not be faster + * loading 3D textures is a common case that hits this and could probably benefit from the temporary + */ +void +nv04_region_fill_cpu(struct nv04_region* dst, int w, int h, unsigned value) +{ + uint8_t* mdst = (nouveau_bo_map(dst->bo, NOUVEAU_BO_WR), (uint8_t*)dst->bo->map + dst->offset); + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tRGN_FILL_CPU "); + nv04_region_print(dst); + fprintf(stderr, "\n"); +#endif + + nv04_region_assert(dst, w, h); + + if(dst->pitch) + { + unsigned size = w << dst->bpps; + +#define FILL(T) do { \ + for(int iy = 0; iy < h; ++iy) \ + { \ + assert((char*)((T*)mdst + w) <= (char*)dst->bo->map + dst->bo->size); \ + for(int ix = 0; ix < w; ++ix) \ + ((T*)mdst)[ix] = (T)value; \ + mdst += dst->pitch; \ + } \ + } while(0) + + mdst += dst->y * dst->pitch + (dst->x << dst->bpps); + + if(dst->bpps == 0) + { +ms: + assert(mdst + size * h <= (uint8_t*)dst->bo->map + dst->bo->size); + if(size == dst->pitch) + memset(mdst, (uint8_t)value, size * h); + else + { + for(int iy = 0; iy < h; ++iy) + { + assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size); + memset(mdst, (uint8_t)value, size); + mdst += dst->pitch; + } + } + } + else if(dst->bpps == 1) + { + if(!((uint8_t)value ^ (uint8_t)(value >> 8))) + goto ms; + + FILL(uint16_t); + } + else if(dst->bpps == 2) + { + if(value == (uint8_t)value * 0x1010101) + goto ms; + FILL(uint32_t); + } + else + assert(0); +#undef FILL + } + else + { + int* dswx; + int* dswy; + + dswx = alloca(w * sizeof(int)); + for(int ix = 0; ix < w; ++ix) + dswx[ix] = nv04_swizzle_bits(dst->x + ix, 0, dst->z, dst->w, dst->h, dst->d); + dswy = alloca(h * sizeof(int)); + for(int iy = 0; iy < h; ++iy) + dswy[iy] = nv04_swizzle_bits(0, dst->y + iy, dst->z, dst->w, dst->h, dst->d); + +#define FILL(T) do { \ + T tvalue = (T)value; \ + for(int iy = 0; iy < h; ++iy) \ + { \ + T* pdst = (T*)mdst + dswy[iy]; \ + for(int ix = 0; ix < w; ++ix) \ + { \ + assert((uint8_t*)&pdst[dswx[ix] + 1] <= (uint8_t*)dst->bo->map + dst->bo->size); \ + pdst[dswx[ix]] = tvalue; \ + } \ + } \ + } while(0) + + if(dst->bpps == 0) + FILL(uint8_t); + else if(dst->bpps == 1) + FILL(uint16_t); + else if(dst->bpps == 2) + FILL(uint32_t); + else + assert(0 && "unhandled bpp"); +#undef FILL + } + + nouveau_bo_unmap(dst->bo); +} + +static void +nv04_region_copy_swizzle(struct nv04_2d_context *ctx, + struct nv04_region* dst, + struct nv04_region* src, + int w, int h, int cs2d_format, int sifm_format) +{ + struct nouveau_channel *chan = ctx->swzsurf->channel; + struct nouveau_grobj *swzsurf = ctx->swzsurf; + struct nouveau_grobj *sifm = ctx->sifm; + /* Max width & height may not be the same on all HW, but must be POT */ + unsigned max_shift = 10; + unsigned cw = 1 << max_shift; + unsigned ch = 1 << max_shift; + unsigned sx = dst->x >> max_shift; + unsigned sy = dst->y >> max_shift; + unsigned ex = (dst->x + w - 1) >> max_shift; + unsigned ey = (dst->y + h - 1) >> max_shift; + unsigned chunks = (ex - sx + 1) * (ey - sy + 1); + unsigned chunk_size; + if(dst->w < cw) + cw = dst->w; + if(dst->h < ch) + ch = dst->h; + chunk_size = cw * ch << dst->bpps; + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tRGN_COPY_SWIZZLE [%i, %i: %i] ", w, h, dst->bpps); + for(int i = 0; i < 2; ++i) + { + nv04_region_print(i ? src : dst); + fprintf(stderr, i ? "\n" : " <- "); + } +#endif + + nv04_region_assert(dst, w, h); + nv04_region_assert(src, w, h); + + MARK_RING (chan, 8 + chunks * 17, 2 + chunks * 2); + + BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_DMA_IMAGE, 1); + OUT_RELOCo(chan, dst->bo, + NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); + + BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_FORMAT, 1); + OUT_RING (chan, cs2d_format | + log2i(cw) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_U_SHIFT | + log2i(ch) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_V_SHIFT); + + BEGIN_RING(chan, sifm, NV03_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE, 1); + OUT_RELOCo(chan, src->bo, + NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); + BEGIN_RING(chan, sifm, NV04_SCALED_IMAGE_FROM_MEMORY_SURFACE, 1); + OUT_RING (chan, swzsurf->handle); + + assert(!(dst->offset & 63)); + + for (int cy = sy; cy <= ey; ++cy) { + int ry = MAX2(0, (int)(dst->y - ch * cy)); + int rh = MIN2((int)ch, (int)(dst->y - ch * cy + h)) - ry; + for (int cx = sx; cx <= ex; ++cx) { + int rx = MAX2(0, (int)(dst->x - cw * cx)); + int rw = MIN2((int)cw, (int)(dst->x - cw * cx + w)) - rx; + unsigned dst_offset; + unsigned src_offset; + + BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_OFFSET, 1); + + dst_offset = dst->offset + (nv04_swizzle_bits_2d(cx * cw, cy * ch, dst->w, dst->h) << dst->bpps); + assert(dst_offset <= dst->bo->size); + assert(dst_offset + chunk_size <= dst->bo->size); + OUT_RELOCl(chan, dst->bo, dst_offset, + NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); + + BEGIN_RING(chan, sifm, NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION, 9); + OUT_RING (chan, NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE); + OUT_RING (chan, sifm_format); + OUT_RING (chan, NV03_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY); + OUT_RING (chan, rx | (ry << NV03_SCALED_IMAGE_FROM_MEMORY_CLIP_POINT_Y_SHIFT)); + OUT_RING (chan, rh << NV03_SCALED_IMAGE_FROM_MEMORY_CLIP_SIZE_H_SHIFT | rw); + OUT_RING (chan, rx | (ry << NV03_SCALED_IMAGE_FROM_MEMORY_OUT_POINT_Y_SHIFT)); + OUT_RING (chan, rh << NV03_SCALED_IMAGE_FROM_MEMORY_OUT_SIZE_H_SHIFT | rw); + OUT_RING (chan, 1 << 20); + OUT_RING (chan, 1 << 20); + + BEGIN_RING(chan, sifm, NV03_SCALED_IMAGE_FROM_MEMORY_SIZE, 4); + OUT_RING (chan, rh << NV03_SCALED_IMAGE_FROM_MEMORY_SIZE_H_SHIFT | align(rw, 8)); + OUT_RING (chan, src->pitch | + NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER | + NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE); + src_offset = src->offset + (cy * ch + ry + src->y - dst->y) * src->pitch + ((cx * cw + rx + src->x - dst->x) << src->bpps); + assert(src_offset <= src->bo->size); + assert(src_offset + (src->pitch * (rh - 1)) + (rw << src->bpps) <= src->bo->size); + OUT_RELOCl(chan, src->bo, src_offset, + NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); + OUT_RING (chan, 0); + } + } +} + +static inline void +nv04_copy_m2mf_begin(struct nv04_2d_context *ctx, struct nouveau_bo* dstbo, struct nouveau_bo* srcbo, unsigned commands) +{ + struct nouveau_channel *chan = ctx->m2mf->channel; + struct nouveau_grobj *m2mf = ctx->m2mf; + MARK_RING (chan, 3 + commands * 9, 2 + commands * 2); + BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2); + OUT_RELOCo(chan, srcbo, + NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); + OUT_RELOCo(chan, dstbo, + NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); +} + +static inline void +nv04_copy_m2mf_body(struct nv04_2d_context *ctx, struct nouveau_bo* dstbo, int* pdstoff, unsigned dstpitch, struct nouveau_bo* srcbo, int* psrcoff, unsigned srcpitch, unsigned size, unsigned lines) +{ + struct nouveau_channel *chan = ctx->m2mf->channel; + struct nouveau_grobj *m2mf = ctx->m2mf; + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\t\t\tCOPY_M2MF_BODY [%i, %i] <%i[%u]> lin %u <- <%i[%u]> lin %u\n", size, lines, dstbo->handle, *pdstoff, dstpitch, srcbo->handle, *psrcoff, srcpitch); +#endif + + BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); + OUT_RELOCl(chan, srcbo, *psrcoff, + NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD); + OUT_RELOCl(chan, dstbo, *pdstoff, + NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_WR); + OUT_RING (chan, srcpitch); + OUT_RING (chan, dstpitch); + OUT_RING (chan, size); + OUT_RING (chan, lines); + OUT_RING (chan, 0x0101); + OUT_RING (chan, 0); + + *psrcoff += srcpitch * lines; + *pdstoff += dstpitch * lines; +} + +static void +nv04_copy_m2mf(struct nv04_2d_context *ctx, + struct nouveau_bo* dstbo, int dstoff, unsigned dstpitch, + struct nouveau_bo* srcbo, int srcoff, unsigned srcpitch, + unsigned size, unsigned h) +{ + unsigned max_pitch = 32767; + unsigned max_lines = 2047; + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\t\tCOPY_M2MF [%i, %i] <%i[%i]> lin %u <- <%i[%i]> lin %u\n", size, h, dstbo->handle, dstoff, dstpitch, srcbo->handle, srcoff, srcpitch); +#endif + + if(srcpitch <= max_pitch && dstpitch <= max_pitch) + { + unsigned full_pages = h / max_lines; + unsigned leftover_lines = h - full_pages * max_lines; + + nv04_copy_m2mf_begin(ctx, dstbo, srcbo, full_pages + !!leftover_lines); + + for(unsigned i = 0; i < full_pages; ++i) + nv04_copy_m2mf_body(ctx, dstbo, &dstoff, dstpitch, srcbo, &srcoff, srcpitch, size, max_lines); + + if(leftover_lines) + nv04_copy_m2mf_body(ctx, dstbo, &dstoff, dstpitch, srcbo, &srcoff, srcpitch, size, leftover_lines); + } + else + { + unsigned lines = size / max_pitch; + unsigned leftover = size - lines * max_pitch; + unsigned full_pages = lines / max_lines; + unsigned leftover_lines = lines - full_pages * max_lines; + unsigned srcgap = srcpitch - size; + unsigned dstgap = dstpitch - size; + + nv04_copy_m2mf_begin(ctx, dstbo, srcbo, h * (full_pages + !!leftover_lines + !!leftover)); + + for(unsigned i = 0; i < h; ++i) + { + for(unsigned j = 0; j < full_pages; ++j) + nv04_copy_m2mf_body(ctx, dstbo, &dstoff, max_pitch, srcbo, &srcoff, max_pitch, max_pitch, max_lines); + + if(leftover_lines) + nv04_copy_m2mf_body(ctx, dstbo, &dstoff, max_pitch, srcbo, &srcoff, max_pitch, max_pitch, leftover_lines); + + if(leftover) + nv04_copy_m2mf_body(ctx, dstbo, &dstoff, leftover, srcbo, &srcoff, leftover, leftover, 1); + + srcoff += srcgap; + dstoff += dstgap; + } + } +} + +void +nv04_memcpy(struct nv04_2d_context *ctx, struct nouveau_bo* dstbo, int dstoff, struct nouveau_bo* srcbo, int srcoff, unsigned size) +{ +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tMEMCPY [%i] <%i[%i]> <- <%i[%i]>\n", size, dstbo->handle, dstoff, srcbo->handle, srcoff); +#endif + + nv04_copy_m2mf(ctx, dstbo, dstoff, size, srcbo, srcoff, size, size, 1); +} + +static void +nv04_region_copy_m2mf(struct nv04_2d_context *ctx, struct nv04_region *dst, struct nv04_region *src, int w, int h) +{ +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tRGN_COPY_M2MF [%i, %i: %i] ", w, h, dst->bpps); + for(int i = 0; i < 2; ++i) + { + nv04_region_print(i ? src : dst); + fprintf(stderr, i ? "\n" : " <- "); + } +#endif + + nv04_region_assert(dst, w, h); + nv04_region_assert(src, w, h); + assert(src->pitch); + assert(dst->pitch); + + nv04_copy_m2mf(ctx, + dst->bo, dst->offset + dst->y * dst->pitch + (dst->x << dst->bpps), dst->pitch, + src->bo, src->offset + src->y * src->pitch + (src->x << src->bpps), src->pitch, + w << src->bpps, h); +} + +static inline void +nv04_region_copy_blit(struct nv04_2d_context *ctx, struct nv04_region* dst, struct nv04_region* src, int w, int h, int format) +{ + struct nouveau_channel *chan = ctx->surf2d->channel; + struct nouveau_grobj *surf2d = ctx->surf2d; + struct nouveau_grobj *blit = ctx->blit; + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tRGN_COPY_BLIT [%i, %i: %i] ", w, h, dst->bpps); + for(int i = 0; i < 2; ++i) + { + nv04_region_print(i ? src : dst); + fprintf(stderr, i ? "\n" : " <- "); + } +#endif + + assert(!(src->pitch & 63) && src->pitch); + assert(!(dst->pitch & 63) && dst->pitch); + nv04_region_assert(dst, w, h); + nv04_region_assert(src, w, h); + + MARK_RING (chan, 12, 4); + BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2); + OUT_RELOCo(chan, src->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); + OUT_RELOCo(chan, dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); + BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4); + OUT_RING (chan, format); + OUT_RING (chan, (dst->pitch << 16) | src->pitch); + OUT_RELOCl(chan, src->bo, src->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); + OUT_RELOCl(chan, dst->bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); + + BEGIN_RING(chan, blit, 0x0300, 3); + OUT_RING (chan, (src->y << 16) | src->x); + OUT_RING (chan, (dst->y << 16) | dst->x); + OUT_RING (chan, ( h << 16) | w); +} + +/* THEOREM: a non-linearizable swizzled destination is always 64 byte aligned, except for 4x2 mipmap levels of swizzled 1bpp surfaces + * HYPOTESIS: + * 1. The first mipmap level is 64-byte-aligned + * PROOF: + * 1. Thus, all mipmaps level with a parent which is 64-byte or more in size are. + * 2. At 1bpp, the smallest levels with a <= 32-byte parent are either Nx1 or 1xN or size <=8, thus 4x2, 2x2 or 2x4 + * 3. Nx1, 1xN, 2x4, 2x2 have all subrects linearizable. 4x2 does not. + * 4. At 2/4bpp or more, the smallest levels with a 32-byte parent are 1xN, Nx1 or 2x2 + * + * However, nv04_region_align handles that. + */ + +// 0 -> done, 1 -> do with 3D engine or CPU, -1 -> do with CPU +// dst and src may be modified, and the possibly modified version should be passed to nv04_region_cpu if necessary +int +nv04_region_copy_2d(struct nv04_2d_context *ctx, struct nv04_region* dst, struct nv04_region* src, + int w, int h, int cs2d_format, int sifm_format, int dst_to_gpu, int src_on_gpu) +{ + assert(src->bpps == dst->bpps); + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "RGN_COPY%s [%i, %i: %i] ", (cs2d_format >= 0) ? "_2D" : "_NO2D", w, h, dst->bpps); + for(int i = 0; i < 2; ++i) + { + int gpu = i ? src_on_gpu : dst_to_gpu; + nv04_region_print(i ? src : dst); + fprintf(stderr, " %s", gpu ? "gpu" : "cpu"); + fprintf(stderr, i ? "\n" : " <- "); + } +#endif + + // if they are contiguous and either both swizzled or both linear, reshape + if(!dst->pitch == !src->pitch + && nv04_region_is_contiguous(dst, w, h) + && nv04_region_is_contiguous(src, w, h)) + { + nv04_region_contiguous_shape(dst, &w, &h, 6); + nv04_region_linearize_contiguous(dst, w, h); + nv04_region_linearize_contiguous(src, w, h); + } + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tOPT "); + for(int i = 0; i < 2; ++i) + { + nv04_region_print(i ? src : dst); + fprintf(stderr, i ? "\n" : " <- "); + } +#endif + + /* if the destination is not for GPU _and_ source is on CPU, use CPU */ + /* if the destination is not for GPU _or_ source is on CPU, use CPU only if we think it's faster than the GPU */ + /* TODO: benchmark to find out in which cases exactly we should prefer the CPU */ + if((!dst_to_gpu && !src_on_gpu) + || (!dst->pitch && dst->d > 1) + /* 3D swizzled destination are unwritable by the GPU, and 2D swizzled ones are readable only by the 3D engine */ + ) + return -1; + /* there is no known way to read 2D/3D-swizzled surfaces with the 2D engine + * ask the caller to use the 3D engine + * If a format cannot be sampled from the 3D engine there is no point in making it swizzled, so we must not do so + */ + else if(!src->pitch) + { +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tCOPY_ENG3D\n"); +#endif + return 1; + } + /* Setup transfer to swizzle the texture to vram if needed */ + else + { + if (!dst->pitch) + { + if(cs2d_format < 0 || sifm_format < 0 || !dst_to_gpu) + { +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tCOPY_ENG3D\n"); +#endif + return 1; + } + else + { + assert(!nv04_region_align(dst, w, h, 6)); + + nv04_region_copy_swizzle(ctx, dst, src, w, h, cs2d_format, sifm_format); + return 0; + } + } + else + { + /* NV_CONTEXT_SURFACES_2D has buffer alignment restrictions, fallback + * to NV_MEMORY_TO_MEMORY_FORMAT in this case. + * TODO: is this also true for the source? possibly not + */ + + if ((cs2d_format < 0) + || !dst_to_gpu + || nv04_region_align(src, w, h, 6) + || nv04_region_align(dst, w, h, 6) + ) + nv04_region_copy_m2mf(ctx, dst, src, w, h); + else + nv04_region_copy_blit(ctx, dst, src, w, h, cs2d_format); + + return 0; + } + } +} + +static inline void +nv04_region_fill_gdirect(struct nv04_2d_context *ctx, struct nv04_region* dst, int w, int h, unsigned value) +{ + struct nouveau_channel *chan = ctx->surf2d->channel; + struct nouveau_grobj *surf2d = ctx->surf2d; + struct nouveau_grobj *rect = ctx->rect; + int cs2d_format, gdirect_format; + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tFILL_GDIRECT\n"); +#endif + + assert(!(dst->pitch & 63) && dst->pitch); + nv04_region_assert(dst, w, h); + + if(dst->bpps == 0) + { + gdirect_format = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8; + cs2d_format = NV04_CONTEXT_SURFACES_2D_FORMAT_Y8; + } + else if(dst->bpps == 1) + { + gdirect_format = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5; + cs2d_format = NV04_CONTEXT_SURFACES_2D_FORMAT_Y16; + } + else if(dst->bpps == 2) + { + gdirect_format = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8; + cs2d_format = NV04_CONTEXT_SURFACES_2D_FORMAT_Y32; + } + else + { + assert(0); + gdirect_format = 0; + cs2d_format = 0; + } + + MARK_RING (chan, 15, 4); + BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2); + OUT_RELOCo(chan, dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); + OUT_RELOCo(chan, dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); + BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4); + OUT_RING (chan, cs2d_format); + OUT_RING (chan, (dst->pitch << 16) | dst->pitch); + OUT_RELOCl(chan, dst->bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); + OUT_RELOCl(chan, dst->bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); + + BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1); + OUT_RING (chan, gdirect_format); + BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1); + OUT_RING (chan, value); + BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2); + OUT_RING (chan, (dst->x << 16) | dst->y); + OUT_RING (chan, ( w << 16) | h); +} + +int +nv04_region_fill_2d(struct nv04_2d_context *ctx, struct nv04_region *dst, + int w, int h, unsigned value) +{ + if(!w || !h) + return 0; + +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "FILL [%i, %i: %i] ", w, h, dst->bpps); + nv04_region_print(dst); + fprintf(stderr, " <- 0x%x\n", value); +#endif + + if(nv04_region_is_contiguous(dst, w, h)) + { + nv04_region_contiguous_shape(dst, &w, &h, 6); + nv04_region_linearize_contiguous(dst, w, h); + } + + // TODO: maybe do intermediate copies for some cases instead of using the 3D engine/CPU + /* GdiRect doesn't work together with swzsurf, so the 3D engine, or an intermediate copy, is the only option here */ + if(!dst->pitch) + { +#ifdef NV04_REGION_DEBUG + fprintf(stderr, "\tFILL_ENG3D\n"); +#endif + return 1; + } + else if(!nv04_region_align(dst, w, h, 6)) + { + nv04_region_fill_gdirect(ctx, dst, w, h, value); + return 0; + } + else + return -1; +} + + +void +nv04_2d_context_takedown(struct nv04_2d_context *ctx) +{ + nouveau_notifier_free(&ctx->ntfy); + nouveau_grobj_free(&ctx->m2mf); + nouveau_grobj_free(&ctx->surf2d); + nouveau_grobj_free(&ctx->swzsurf); + nouveau_grobj_free(&ctx->rect); + nouveau_grobj_free(&ctx->blit); + nouveau_grobj_free(&ctx->sifm); + + free(ctx); +} + +struct nv04_2d_context * +nv04_2d_context_init(struct nouveau_channel* chan) +{ + struct nv04_2d_context *ctx = calloc(1, sizeof(struct nv04_2d_context)); + unsigned handle = 0x88000000, class; + int ret; + + if (!ctx) + return NULL; + + ret = nouveau_notifier_alloc(chan, handle++, 1, &ctx->ntfy); + if (ret) { + nv04_2d_context_takedown(ctx); + return NULL; + } + + ret = nouveau_grobj_alloc(chan, handle++, 0x0039, &ctx->m2mf); + if (ret) { + nv04_2d_context_takedown(ctx); + return NULL; + } + + BEGIN_RING(chan, ctx->m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1); + OUT_RING (chan, ctx->ntfy->handle); + + if (chan->device->chipset < 0x10) + class = NV04_CONTEXT_SURFACES_2D; + else + class = NV10_CONTEXT_SURFACES_2D; + + ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->surf2d); + if (ret) { + nv04_2d_context_takedown(ctx); + return NULL; + } + + BEGIN_RING(chan, ctx->surf2d, + NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2); + OUT_RING (chan, chan->vram->handle); + OUT_RING (chan, chan->vram->handle); + + if (chan->device->chipset < 0x10) + class = NV04_IMAGE_BLIT; + else + class = NV12_IMAGE_BLIT; + + ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->blit); + if (ret) { + nv04_2d_context_takedown(ctx); + return NULL; + } + + BEGIN_RING(chan, ctx->blit, NV01_IMAGE_BLIT_DMA_NOTIFY, 1); + OUT_RING (chan, ctx->ntfy->handle); + BEGIN_RING(chan, ctx->blit, NV04_IMAGE_BLIT_SURFACE, 1); + OUT_RING (chan, ctx->surf2d->handle); + BEGIN_RING(chan, ctx->blit, NV01_IMAGE_BLIT_OPERATION, 1); + OUT_RING (chan, NV01_IMAGE_BLIT_OPERATION_SRCCOPY); + + ret = nouveau_grobj_alloc(chan, handle++, NV04_GDI_RECTANGLE_TEXT, + &ctx->rect); + if (ret) { + nv04_2d_context_takedown(ctx); + return NULL; + } + + BEGIN_RING(chan, ctx->rect, NV04_GDI_RECTANGLE_TEXT_DMA_NOTIFY, 1); + OUT_RING (chan, ctx->ntfy->handle); + BEGIN_RING(chan, ctx->rect, NV04_GDI_RECTANGLE_TEXT_SURFACE, 1); + OUT_RING (chan, ctx->surf2d->handle); + BEGIN_RING(chan, ctx->rect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1); + OUT_RING (chan, NV04_GDI_RECTANGLE_TEXT_OPERATION_SRCCOPY); + BEGIN_RING(chan, ctx->rect, + NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT, 1); + OUT_RING (chan, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE); + + switch (chan->device->chipset & 0xf0) { + case 0x00: + case 0x10: + class = NV04_SWIZZLED_SURFACE; + break; + case 0x20: + class = NV20_SWIZZLED_SURFACE; + break; + case 0x30: + class = NV30_SWIZZLED_SURFACE; + break; + case 0x40: + case 0x60: + class = NV40_SWIZZLED_SURFACE; + break; + default: + /* Famous last words: this really can't happen.. */ + assert(0); + break; + } + + ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->swzsurf); + if (ret) { + nv04_2d_context_takedown(ctx); + return NULL; + } + + /* all the Gallium MARK_RING calculations assume no autobinding, so do that now */ + if(ctx->swzsurf->bound == NOUVEAU_GROBJ_UNBOUND) + nouveau_grobj_autobind(ctx->swzsurf); + + switch (chan->device->chipset & 0xf0) { + case 0x10: + case 0x20: + class = NV10_SCALED_IMAGE_FROM_MEMORY; + break; + case 0x30: + class = NV30_SCALED_IMAGE_FROM_MEMORY; + break; + case 0x40: + case 0x60: + class = NV40_SCALED_IMAGE_FROM_MEMORY; + break; + default: + class = NV04_SCALED_IMAGE_FROM_MEMORY; + break; + } + + ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->sifm); + if (ret) { + nv04_2d_context_takedown(ctx); + return NULL; + } + + /* all the Gallium MARK_RING calculations assume no autobinding, so do that now */ + if(ctx->sifm->bound == NOUVEAU_GROBJ_UNBOUND) + nouveau_grobj_autobind(ctx->sifm); + + return ctx; +} diff --git a/src/gallium/drivers/nvfx/nv04_2d.h b/src/gallium/drivers/nvfx/nv04_2d.h new file mode 100644 index 0000000000..e638b8c874 --- /dev/null +++ b/src/gallium/drivers/nvfx/nv04_2d.h @@ -0,0 +1,87 @@ +/************************************************************************** + * + * Copyright 2009 Ben Skeggs + * Copyright 2009 Younes Manton + * Copyright 2010 Luca Barbieri + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + **************************************************************************/ + +/* this code has no Mesa or Gallium dependency and can be reused in the classic Mesa driver or DDX */ + +#ifndef __NV04_2D_H__ +#define __NV04_2D_H__ + +struct nv04_2d_context; +struct nouveau_channel; +struct nouveau_bo; + +// NOTE: all functions taking this as a parameter will CLOBBER it (except for ->bo) +struct nv04_region { + struct nouveau_bo* bo; + int offset; + unsigned pitch; // 0 -> swizzled + unsigned bpps; // bpp shift (0, 1, 2; 3, 4 for fp/compressed) + unsigned x, y, z; + unsigned w, h, d; +}; + +void +nv04_memcpy(struct nv04_2d_context *ctx, + struct nouveau_bo* dstbo, int dstoff, + struct nouveau_bo* srcbo, int srcoff, + unsigned size); + +unsigned +nv04_region_begin(struct nv04_region* rgn, unsigned w, unsigned h); + +unsigned +nv04_region_end(struct nv04_region* rgn, unsigned w, unsigned h); + +void +nv04_2d_context_takedown(struct nv04_2d_context *pctx); + +struct nv04_2d_context * +nv04_2d_context_init(struct nouveau_channel* chan); + +void +nv04_region_copy_cpu(struct nv04_region* dst, struct nv04_region* src, int w, int h); + +void +nv04_region_fill_cpu(struct nv04_region* dst, int w, int h, unsigned value); + +int +nv04_region_copy_2d(struct nv04_2d_context *ctx, + struct nv04_region* dst, struct nv04_region* src, + int w, int h, + int cs2d_format, int sifm_format, + int dst_to_gpu, int src_on_gpu); + +int +nv04_region_fill_2d(struct nv04_2d_context *ctx, + struct nv04_region *dst, + int w, int h, + unsigned value); + +#endif diff --git a/src/gallium/drivers/nvfx/nv04_2d_loops.h b/src/gallium/drivers/nvfx/nv04_2d_loops.h new file mode 100644 index 0000000000..3a6787c071 --- /dev/null +++ b/src/gallium/drivers/nvfx/nv04_2d_loops.h @@ -0,0 +1,70 @@ +#ifndef T +{ + if(dst->bpps == 0) +#define T uint8_t +#include "nv04_2d_loops.h" +#undef T + else if(dst->bpps == 1) +#define T uint16_t +#include "nv04_2d_loops.h" +#undef T + else if(dst->bpps == 2) +#define T uint32_t +#include "nv04_2d_loops.h" +#undef T + else + assert(0); +} +#else +#ifdef SWIZZLED_COPY_LOOPS +{ + if(!dst->pitch) + { + if(!src->pitch) + { + LOOP_Y + { + T* pdst = (T*)mdst + dswy[iy]; + T* psrc = (T*)msrc + sswy[iy]; + LOOP_X + { + assert((char*)&psrc[sswx[ix] + 1] <= ((char*)src->bo->map + src->bo->size)); + assert((char*)&pdst[dswx[ix] + 1] <= ((char*)dst->bo->map + dst->bo->size)); + pdst[dswx[ix]] = psrc[sswx[ix]]; + } + } + } + else + { + T* psrc = (T*)(msrc + ((dir > 0) ? src->y : (src->y + h - 1)) * src->pitch) + src->x; + LOOP_Y + { + T* pdst = (T*)mdst + dswy[iy]; + LOOP_X + { + assert((char*)&psrc[ix + 1] <= ((char*)src->bo->map + src->bo->size)); + assert((char*)&pdst[dswx[ix] + 1] <= ((char*)dst->bo->map + dst->bo->size)); + pdst[dswx[ix]] = psrc[ix]; + } + psrc = (T*)((char*)psrc + dir * src->pitch); + } + } + } + else + { + T* pdst = (T*)(mdst + ((dir > 0) ? dst->y : (dst->y + h - 1)) * dst->pitch) + dst->x; + LOOP_Y + { + T* psrc = (T*)msrc + sswy[iy]; + LOOP_X + { + assert((char*)&psrc[sswx[ix] + 1] <= ((char*)src->bo->map + src->bo->size)); + assert((char*)&pdst[ix + 1] <= ((char*)dst->bo->map + dst->bo->size)); + pdst[ix] = psrc[sswx[ix]]; + } + pdst = (T*)((char*)pdst + dir * dst->pitch); + } + } +} +#endif +#endif diff --git a/src/gallium/drivers/nvfx/nv04_surface_2d.c b/src/gallium/drivers/nvfx/nv04_surface_2d.c deleted file mode 100644 index 7acbb505df..0000000000 --- a/src/gallium/drivers/nvfx/nv04_surface_2d.c +++ /dev/null @@ -1,532 +0,0 @@ -#include "pipe/p_context.h" -#include "pipe/p_format.h" -#include "util/u_format.h" -#include "util/u_math.h" -#include "util/u_memory.h" - -#include "nouveau/nouveau_winsys.h" -#include "nouveau/nouveau_util.h" -#include "nouveau/nouveau_screen.h" -#include "nv04_surface_2d.h" - -static INLINE int -nv04_surface_format(enum pipe_format format) -{ - switch (format) { - case PIPE_FORMAT_A8_UNORM: - case PIPE_FORMAT_L8_UNORM: - case PIPE_FORMAT_I8_UNORM: - return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8; - case PIPE_FORMAT_R16_SNORM: - case PIPE_FORMAT_B5G6R5_UNORM: - case PIPE_FORMAT_Z16_UNORM: - case PIPE_FORMAT_L8A8_UNORM: - return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5; - case PIPE_FORMAT_B8G8R8X8_UNORM: - case PIPE_FORMAT_B8G8R8A8_UNORM: - return NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8; - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - case PIPE_FORMAT_X8Z24_UNORM: - return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32; - default: - return -1; - } -} - -static INLINE int -nv04_rect_format(enum pipe_format format) -{ - switch (format) { - case PIPE_FORMAT_A8_UNORM: - return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8; - case PIPE_FORMAT_B5G6R5_UNORM: - case PIPE_FORMAT_L8A8_UNORM: - case PIPE_FORMAT_Z16_UNORM: - return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5; - case PIPE_FORMAT_B8G8R8X8_UNORM: - case PIPE_FORMAT_B8G8R8A8_UNORM: - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - case PIPE_FORMAT_X8Z24_UNORM: - return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8; - default: - return -1; - } -} - -static INLINE int -nv04_scaled_image_format(enum pipe_format format) -{ - switch (format) { - case PIPE_FORMAT_A8_UNORM: - case PIPE_FORMAT_L8_UNORM: - case PIPE_FORMAT_I8_UNORM: - return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_Y8; - case PIPE_FORMAT_B5G5R5A1_UNORM: - return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A1R5G5B5; - case PIPE_FORMAT_B8G8R8A8_UNORM: - return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A8R8G8B8; - case PIPE_FORMAT_B8G8R8X8_UNORM: - return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_X8R8G8B8; - case PIPE_FORMAT_B5G6R5_UNORM: - case PIPE_FORMAT_R16_SNORM: - case PIPE_FORMAT_L8A8_UNORM: - return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_R5G6B5; - default: - return -1; - } -} - -static INLINE unsigned -nv04_swizzle_bits_square(unsigned x, unsigned y) -{ - unsigned u = (x & 0x001) << 0 | - (x & 0x002) << 1 | - (x & 0x004) << 2 | - (x & 0x008) << 3 | - (x & 0x010) << 4 | - (x & 0x020) << 5 | - (x & 0x040) << 6 | - (x & 0x080) << 7 | - (x & 0x100) << 8 | - (x & 0x200) << 9 | - (x & 0x400) << 10 | - (x & 0x800) << 11; - - unsigned v = (y & 0x001) << 1 | - (y & 0x002) << 2 | - (y & 0x004) << 3 | - (y & 0x008) << 4 | - (y & 0x010) << 5 | - (y & 0x020) << 6 | - (y & 0x040) << 7 | - (y & 0x080) << 8 | - (y & 0x100) << 9 | - (y & 0x200) << 10 | - (y & 0x400) << 11 | - (y & 0x800) << 12; - return v | u; -} - -/* rectangular swizzled textures are linear concatenations of swizzled square tiles */ -static INLINE unsigned -nv04_swizzle_bits(unsigned x, unsigned y, unsigned w, unsigned h) -{ - unsigned s = MIN2(w, h); - unsigned m = s - 1; - return (((x | y) & ~m) * s) | nv04_swizzle_bits_square(x & m, y & m); -} - -static int -nv04_surface_copy_swizzle(struct nv04_surface_2d *ctx, - struct pipe_surface *dst, int dx, int dy, - struct pipe_surface *src, int sx, int sy, - int w, int h) -{ - struct nouveau_channel *chan = ctx->swzsurf->channel; - struct nouveau_grobj *swzsurf = ctx->swzsurf; - struct nouveau_grobj *sifm = ctx->sifm; - struct nouveau_bo *src_bo = ctx->buf(src); - struct nouveau_bo *dst_bo = ctx->buf(dst); - const unsigned src_pitch = ((struct nv04_surface *)src)->pitch; - /* Max width & height may not be the same on all HW, but must be POT */ - const unsigned max_w = 1024; - const unsigned max_h = 1024; - unsigned sub_w = w > max_w ? max_w : w; - unsigned sub_h = h > max_h ? max_h : h; - unsigned x; - unsigned y; - - /* Swizzled surfaces must be POT */ - assert(util_is_pot(dst->width) && util_is_pot(dst->height)); - - /* If area is too large to copy in one shot we must copy it in POT chunks to meet alignment requirements */ - assert(sub_w == w || util_is_pot(sub_w)); - assert(sub_h == h || util_is_pot(sub_h)); - - MARK_RING (chan, 8 + ((w+sub_w)/sub_w)*((h+sub_h)/sub_h)*17, 2 + - ((w+sub_w)/sub_w)*((h+sub_h)/sub_h)*2); - - BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_DMA_IMAGE, 1); - OUT_RELOCo(chan, dst_bo, - NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - - BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_FORMAT, 1); - OUT_RING (chan, nv04_surface_format(dst->format) | - log2i(dst->width) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_U_SHIFT | - log2i(dst->height) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_V_SHIFT); - - BEGIN_RING(chan, sifm, NV03_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE, 1); - OUT_RELOCo(chan, src_bo, - NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); - BEGIN_RING(chan, sifm, NV04_SCALED_IMAGE_FROM_MEMORY_SURFACE, 1); - OUT_RING (chan, swzsurf->handle); - - for (y = 0; y < h; y += sub_h) { - sub_h = MIN2(sub_h, h - y); - - for (x = 0; x < w; x += sub_w) { - sub_w = MIN2(sub_w, w - x); - - assert(!(dst->offset & 63)); - - BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_OFFSET, 1); - OUT_RELOCl(chan, dst_bo, dst->offset, - NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - - BEGIN_RING(chan, sifm, NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION, 9); - OUT_RING (chan, NV05_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE); - OUT_RING (chan, nv04_scaled_image_format(src->format)); - OUT_RING (chan, NV03_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY); - OUT_RING (chan, (x + dx) | ((y + dy) << NV03_SCALED_IMAGE_FROM_MEMORY_CLIP_POINT_Y_SHIFT)); - OUT_RING (chan, sub_h << NV03_SCALED_IMAGE_FROM_MEMORY_CLIP_SIZE_H_SHIFT | sub_w); - OUT_RING (chan, (x + dx) | ((y + dy) << NV03_SCALED_IMAGE_FROM_MEMORY_OUT_POINT_Y_SHIFT)); - OUT_RING (chan, sub_h << NV03_SCALED_IMAGE_FROM_MEMORY_OUT_SIZE_H_SHIFT | sub_w); - OUT_RING (chan, 1 << 20); - OUT_RING (chan, 1 << 20); - - BEGIN_RING(chan, sifm, NV03_SCALED_IMAGE_FROM_MEMORY_SIZE, 4); - OUT_RING (chan, sub_h << NV03_SCALED_IMAGE_FROM_MEMORY_SIZE_H_SHIFT | sub_w); - OUT_RING (chan, src_pitch | - NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER | - NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE); - OUT_RELOCl(chan, src_bo, src->offset + (sy+y) * src_pitch + (sx+x) * util_format_get_blocksize(src->texture->format), - NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); - OUT_RING (chan, 0); - } - } - - return 0; -} - -static int -nv04_surface_copy_m2mf(struct nv04_surface_2d *ctx, - struct pipe_surface *dst, int dx, int dy, - struct pipe_surface *src, int sx, int sy, int w, int h) -{ - struct nouveau_channel *chan = ctx->m2mf->channel; - struct nouveau_grobj *m2mf = ctx->m2mf; - struct nouveau_bo *src_bo = ctx->buf(src); - struct nouveau_bo *dst_bo = ctx->buf(dst); - unsigned src_pitch = ((struct nv04_surface *)src)->pitch; - unsigned dst_pitch = ((struct nv04_surface *)dst)->pitch; - unsigned dst_offset = dst->offset + dy * dst_pitch + - dx * util_format_get_blocksize(dst->texture->format); - unsigned src_offset = src->offset + sy * src_pitch + - sx * util_format_get_blocksize(src->texture->format); - - MARK_RING (chan, 3 + ((h / 2047) + 1) * 9, 2 + ((h / 2047) + 1) * 2); - BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2); - OUT_RELOCo(chan, src_bo, - NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); - OUT_RELOCo(chan, dst_bo, - NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - - while (h) { - int count = (h > 2047) ? 2047 : h; - - BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); - OUT_RELOCl(chan, src_bo, src_offset, - NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD); - OUT_RELOCl(chan, dst_bo, dst_offset, - NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_WR); - OUT_RING (chan, src_pitch); - OUT_RING (chan, dst_pitch); - OUT_RING (chan, w * util_format_get_blocksize(src->texture->format)); - OUT_RING (chan, count); - OUT_RING (chan, 0x0101); - OUT_RING (chan, 0); - - h -= count; - src_offset += src_pitch * count; - dst_offset += dst_pitch * count; - } - - return 0; -} - -static int -nv04_surface_copy_blit(struct nv04_surface_2d *ctx, struct pipe_surface *dst, - int dx, int dy, struct pipe_surface *src, int sx, int sy, - int w, int h) -{ - struct nouveau_channel *chan = ctx->surf2d->channel; - struct nouveau_grobj *surf2d = ctx->surf2d; - struct nouveau_grobj *blit = ctx->blit; - struct nouveau_bo *src_bo = ctx->buf(src); - struct nouveau_bo *dst_bo = ctx->buf(dst); - unsigned src_pitch = ((struct nv04_surface *)src)->pitch; - unsigned dst_pitch = ((struct nv04_surface *)dst)->pitch; - int format; - - format = nv04_surface_format(dst->format); - if (format < 0) - return 1; - - MARK_RING (chan, 12, 4); - BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2); - OUT_RELOCo(chan, src_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); - OUT_RELOCo(chan, dst_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4); - OUT_RING (chan, format); - OUT_RING (chan, (dst_pitch << 16) | src_pitch); - OUT_RELOCl(chan, src_bo, src->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); - OUT_RELOCl(chan, dst_bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - - BEGIN_RING(chan, blit, 0x0300, 3); - OUT_RING (chan, (sy << 16) | sx); - OUT_RING (chan, (dy << 16) | dx); - OUT_RING (chan, ( h << 16) | w); - - return 0; -} - -static void -nv04_surface_copy(struct nv04_surface_2d *ctx, struct pipe_surface *dst, - int dx, int dy, struct pipe_surface *src, int sx, int sy, - int w, int h) -{ - int src_linear = src->texture->flags & NVFX_RESOURCE_FLAG_LINEAR; - int dst_linear = dst->texture->flags & NVFX_RESOURCE_FLAG_LINEAR; - - assert(src->format == dst->format); - - /* Setup transfer to swizzle the texture to vram if needed */ - if (src_linear && !dst_linear && w > 1 && h > 1) { - nv04_surface_copy_swizzle(ctx, dst, dx, dy, src, sx, sy, w, h); - return; - } - - /* Use M2MF instead of the blitter since it always works - * Any possible performance drop is likely to be not very significant - * and dwarfed anyway by the current buffer management problems - */ - nv04_surface_copy_m2mf(ctx, dst, dx, dy, src, sx, sy, w, h); -} - -static void -nv04_surface_fill(struct nv04_surface_2d *ctx, struct pipe_surface *dst, - int dx, int dy, int w, int h, unsigned value) -{ - struct nouveau_channel *chan = ctx->surf2d->channel; - struct nouveau_grobj *surf2d = ctx->surf2d; - struct nouveau_grobj *rect = ctx->rect; - struct nouveau_bo *dst_bo = ctx->buf(dst); - unsigned dst_pitch = ((struct nv04_surface *)dst)->pitch; - int cs2d_format, gdirect_format; - - cs2d_format = nv04_surface_format(dst->format); - assert(cs2d_format >= 0); - - gdirect_format = nv04_rect_format(dst->format); - assert(gdirect_format >= 0); - - MARK_RING (chan, 16, 4); - BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2); - OUT_RELOCo(chan, dst_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - OUT_RELOCo(chan, dst_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4); - OUT_RING (chan, cs2d_format); - OUT_RING (chan, (dst_pitch << 16) | dst_pitch); - OUT_RELOCl(chan, dst_bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - OUT_RELOCl(chan, dst_bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - - BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1); - OUT_RING (chan, gdirect_format); - BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1); - OUT_RING (chan, value); - BEGIN_RING(chan, rect, - NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2); - OUT_RING (chan, (dx << 16) | dy); - OUT_RING (chan, ( w << 16) | h); -} - -void -nv04_surface_2d_takedown(struct nv04_surface_2d **pctx) -{ - struct nv04_surface_2d *ctx; - - if (!pctx || !*pctx) - return; - ctx = *pctx; - *pctx = NULL; - - nouveau_notifier_free(&ctx->ntfy); - nouveau_grobj_free(&ctx->m2mf); - nouveau_grobj_free(&ctx->surf2d); - nouveau_grobj_free(&ctx->swzsurf); - nouveau_grobj_free(&ctx->rect); - nouveau_grobj_free(&ctx->blit); - nouveau_grobj_free(&ctx->sifm); - - FREE(ctx); -} - -struct nv04_surface_2d * -nv04_surface_2d_init(struct nouveau_screen *screen) -{ - struct nv04_surface_2d *ctx = CALLOC_STRUCT(nv04_surface_2d); - struct nouveau_channel *chan = screen->channel; - unsigned handle = 0x88000000, class; - int ret; - - if (!ctx) - return NULL; - - ret = nouveau_notifier_alloc(chan, handle++, 1, &ctx->ntfy); - if (ret) { - nv04_surface_2d_takedown(&ctx); - return NULL; - } - - ret = nouveau_grobj_alloc(chan, handle++, 0x0039, &ctx->m2mf); - if (ret) { - nv04_surface_2d_takedown(&ctx); - return NULL; - } - - BEGIN_RING(chan, ctx->m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1); - OUT_RING (chan, ctx->ntfy->handle); - - if (chan->device->chipset < 0x10) - class = NV04_CONTEXT_SURFACES_2D; - else - class = NV10_CONTEXT_SURFACES_2D; - - ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->surf2d); - if (ret) { - nv04_surface_2d_takedown(&ctx); - return NULL; - } - - BEGIN_RING(chan, ctx->surf2d, - NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2); - OUT_RING (chan, chan->vram->handle); - OUT_RING (chan, chan->vram->handle); - - if (chan->device->chipset < 0x10) - class = NV04_IMAGE_BLIT; - else - class = NV12_IMAGE_BLIT; - - ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->blit); - if (ret) { - nv04_surface_2d_takedown(&ctx); - return NULL; - } - - BEGIN_RING(chan, ctx->blit, NV01_IMAGE_BLIT_DMA_NOTIFY, 1); - OUT_RING (chan, ctx->ntfy->handle); - BEGIN_RING(chan, ctx->blit, NV04_IMAGE_BLIT_SURFACE, 1); - OUT_RING (chan, ctx->surf2d->handle); - BEGIN_RING(chan, ctx->blit, NV01_IMAGE_BLIT_OPERATION, 1); - OUT_RING (chan, NV01_IMAGE_BLIT_OPERATION_SRCCOPY); - - ret = nouveau_grobj_alloc(chan, handle++, NV04_GDI_RECTANGLE_TEXT, - &ctx->rect); - if (ret) { - nv04_surface_2d_takedown(&ctx); - return NULL; - } - - BEGIN_RING(chan, ctx->rect, NV04_GDI_RECTANGLE_TEXT_DMA_NOTIFY, 1); - OUT_RING (chan, ctx->ntfy->handle); - BEGIN_RING(chan, ctx->rect, NV04_GDI_RECTANGLE_TEXT_SURFACE, 1); - OUT_RING (chan, ctx->surf2d->handle); - BEGIN_RING(chan, ctx->rect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1); - OUT_RING (chan, NV04_GDI_RECTANGLE_TEXT_OPERATION_SRCCOPY); - BEGIN_RING(chan, ctx->rect, - NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT, 1); - OUT_RING (chan, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE); - - switch (chan->device->chipset & 0xf0) { - case 0x00: - case 0x10: - class = NV04_SWIZZLED_SURFACE; - break; - case 0x20: - class = NV20_SWIZZLED_SURFACE; - break; - case 0x30: - class = NV30_SWIZZLED_SURFACE; - break; - case 0x40: - case 0x60: - class = NV40_SWIZZLED_SURFACE; - break; - default: - /* Famous last words: this really can't happen.. */ - assert(0); - break; - } - - ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->swzsurf); - if (ret) { - nv04_surface_2d_takedown(&ctx); - return NULL; - } - - switch (chan->device->chipset & 0xf0) { - case 0x10: - case 0x20: - class = NV10_SCALED_IMAGE_FROM_MEMORY; - break; - case 0x30: - class = NV30_SCALED_IMAGE_FROM_MEMORY; - break; - case 0x40: - case 0x60: - class = NV40_SCALED_IMAGE_FROM_MEMORY; - break; - default: - class = NV04_SCALED_IMAGE_FROM_MEMORY; - break; - } - - ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->sifm); - if (ret) { - nv04_surface_2d_takedown(&ctx); - return NULL; - } - - ctx->copy = nv04_surface_copy; - ctx->fill = nv04_surface_fill; - return ctx; -} - -struct nv04_surface* -nv04_surface_wrap_for_render(struct pipe_screen *pscreen, - struct nv04_surface_2d* eng2d, struct nv04_surface* ns) -{ - struct pipe_resource templ; - struct pipe_resource* temp_tex; - struct nv04_surface* temp_ns; - int temp_flags; - - temp_flags = ns->base.usage; - - ns->base.usage = 0; - - memset(&templ, 0, sizeof(templ)); - templ.format = ns->base.texture->format; - templ.target = PIPE_TEXTURE_2D; - templ.width0 = ns->base.width; - templ.height0 = ns->base.height; - templ.depth0 = 1; - templ.last_level = 0; - - // TODO: this is probably wrong and we should specifically handle multisampling somehow once it is implemented - templ.nr_samples = ns->base.texture->nr_samples; - - templ.bind = ns->base.texture->bind | PIPE_BIND_RENDER_TARGET; - - temp_tex = pscreen->resource_create(pscreen, &templ); - temp_ns = (struct nv04_surface*)pscreen->get_tex_surface(pscreen, temp_tex, 0, 0, 0, temp_flags); - temp_ns->backing = ns; - - if(1) /* hmm */ - eng2d->copy(eng2d, &temp_ns->backing->base, - 0, 0, &ns->base, - 0, 0, ns->base.width, ns->base.height); - - return temp_ns; -} diff --git a/src/gallium/drivers/nvfx/nv04_surface_2d.h b/src/gallium/drivers/nvfx/nv04_surface_2d.h deleted file mode 100644 index 2123c3ed08..0000000000 --- a/src/gallium/drivers/nvfx/nv04_surface_2d.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef __NV04_SURFACE_2D_H__ -#define __NV04_SURFACE_2D_H__ - -#include "pipe/p_state.h" - -struct nouveau_screen; - -struct nv04_surface { - struct pipe_surface base; - unsigned pitch; - struct nv04_surface* backing; -}; - -struct nv04_surface_2d { - struct nouveau_notifier *ntfy; - struct nouveau_grobj *surf2d; - struct nouveau_grobj *swzsurf; - struct nouveau_grobj *m2mf; - struct nouveau_grobj *rect; - struct nouveau_grobj *blit; - struct nouveau_grobj *sifm; - - struct nouveau_bo *(*buf)(struct pipe_surface *); - - void (*copy)(struct nv04_surface_2d *, struct pipe_surface *dst, - int dx, int dy, struct pipe_surface *src, int sx, int sy, - int w, int h); - void (*fill)(struct nv04_surface_2d *, struct pipe_surface *dst, - int dx, int dy, int w, int h, unsigned value); -}; - -struct nv04_surface_2d * -nv04_surface_2d_init(struct nouveau_screen *screen); - -void -nv04_surface_2d_takedown(struct nv04_surface_2d **); - -struct nv04_surface* -nv04_surface_wrap_for_render(struct pipe_screen *pscreen, struct nv04_surface_2d* eng2d, struct nv04_surface* ns); - -#define NVFX_RESOURCE_FLAG_LINEAR (PIPE_RESOURCE_FLAG_DRV_PRIV << 0) - -#endif diff --git a/src/gallium/drivers/nvfx/nv30_fragtex.c b/src/gallium/drivers/nvfx/nv30_fragtex.c index dec073ac90..0c3d43fd57 100644 --- a/src/gallium/drivers/nvfx/nv30_fragtex.c +++ b/src/gallium/drivers/nvfx/nv30_fragtex.c @@ -1,7 +1,6 @@ #include "util/u_format.h" #include "nvfx_context.h" -#include "nouveau/nouveau_util.h" #include "nvfx_tex.h" #include "nvfx_resource.h" @@ -10,138 +9,109 @@ nv30_sampler_state_init(struct pipe_context *pipe, struct nvfx_sampler_state *ps, const struct pipe_sampler_state *cso) { - if (cso->max_anisotropy >= 8) { - ps->en |= NV34TCL_TX_ENABLE_ANISO_8X; - } else - if (cso->max_anisotropy >= 4) { - ps->en |= NV34TCL_TX_ENABLE_ANISO_4X; - } else - if (cso->max_anisotropy >= 2) { - ps->en |= NV34TCL_TX_ENABLE_ANISO_2X; - } + float limit; + if (cso->max_anisotropy >= 2) { - float limit; + if (cso->max_anisotropy >= 8) + ps->en |= NV34TCL_TX_ENABLE_ANISO_8X; + else if (cso->max_anisotropy >= 4) + ps->en |= NV34TCL_TX_ENABLE_ANISO_4X; + else if (cso->max_anisotropy >= 2) + ps->en |= NV34TCL_TX_ENABLE_ANISO_2X; + } - limit = CLAMP(cso->lod_bias, -16.0, 15.0); - ps->filt |= (int)(cso->lod_bias * 256.0) & 0x1fff; + limit = CLAMP(cso->lod_bias, -16.0, 15.0 + (255.0 / 256.0)); + ps->filt |= (int)(cso->lod_bias * 256.0) & 0x1fff; - limit = CLAMP(cso->max_lod, 0.0, 15.0); - ps->en |= (int)(limit) << 14 /*NV34TCL_TX_ENABLE_MIPMAP_MAX_LOD_SHIFT*/; + ps->max_lod = (int)CLAMP(cso->max_lod, 0.0, 15.0); + ps->min_lod = (int)CLAMP(cso->min_lod, 0.0, 15.0); - limit = CLAMP(cso->min_lod, 0.0, 15.0); - ps->en |= (int)(limit) << 26 /*NV34TCL_TX_ENABLE_MIPMAP_MIN_LOD_SHIFT*/; - } + ps->en |= NV34TCL_TX_ENABLE_ENABLE; } -#define _(m,tf,ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w) \ -{ \ - TRUE, \ - PIPE_FORMAT_##m, \ - NV34TCL_TX_FORMAT_FORMAT_##tf, \ - (NV34TCL_TX_SWIZZLE_S0_X_##ts0x | NV34TCL_TX_SWIZZLE_S0_Y_##ts0y | \ - NV34TCL_TX_SWIZZLE_S0_Z_##ts0z | NV34TCL_TX_SWIZZLE_S0_W_##ts0w | \ - NV34TCL_TX_SWIZZLE_S1_X_##ts1x | NV34TCL_TX_SWIZZLE_S1_Y_##ts1y | \ - NV34TCL_TX_SWIZZLE_S1_Z_##ts1z | NV34TCL_TX_SWIZZLE_S1_W_##ts1w) \ -} - -struct nv30_texture_format { - boolean defined; - uint pipe; - int format; - int swizzle; -}; - -static struct nv30_texture_format -nv30_texture_formats[] = { - _(B8G8R8X8_UNORM, A8R8G8B8, S1, S1, S1, ONE, X, Y, Z, W), - _(B8G8R8A8_UNORM, A8R8G8B8, S1, S1, S1, S1, X, Y, Z, W), - _(B5G5R5A1_UNORM, A1R5G5B5, S1, S1, S1, S1, X, Y, Z, W), - _(B4G4R4A4_UNORM, A4R4G4B4, S1, S1, S1, S1, X, Y, Z, W), - _(B5G6R5_UNORM , R5G6B5 , S1, S1, S1, ONE, X, Y, Z, W), - _(L8_UNORM , L8 , S1, S1, S1, ONE, X, X, X, X), - _(A8_UNORM , L8 , ZERO, ZERO, ZERO, S1, X, X, X, X), - _(I8_UNORM , L8 , S1, S1, S1, S1, X, X, X, X), - _(L8A8_UNORM , A8L8 , S1, S1, S1, S1, X, X, X, Y), - _(Z16_UNORM , R5G6B5 , S1, S1, S1, ONE, X, X, X, X), - _(S8_USCALED_Z24_UNORM , A8R8G8B8, S1, S1, S1, ONE, X, X, X, X), - _(DXT1_RGB , DXT1 , S1, S1, S1, ONE, X, Y, Z, W), - _(DXT1_RGBA , DXT1 , S1, S1, S1, S1, X, Y, Z, W), - _(DXT3_RGBA , DXT3 , S1, S1, S1, S1, X, Y, Z, W), - _(DXT5_RGBA , DXT5 , S1, S1, S1, S1, X, Y, Z, W), - {}, -}; - -static struct nv30_texture_format * -nv30_fragtex_format(uint pipe_format) +void +nv30_sampler_view_init(struct pipe_context *pipe, + struct nvfx_sampler_view *sv) { - struct nv30_texture_format *tf = nv30_texture_formats; - - while (tf->defined) { - if (tf->pipe == pipe_format) - return tf; - tf++; - } - - NOUVEAU_ERR("unknown texture format %s\n", util_format_name(pipe_format)); - return NULL; + struct pipe_resource* pt = sv->base.texture; + struct nvfx_texture_format *tf = &nvfx_texture_formats[sv->base.format]; + unsigned txf; + unsigned level = pt->target == PIPE_TEXTURE_CUBE ? 0 : sv->base.first_level; + + assert(tf->fmt[0] >= 0); + + txf = sv->u.init_fmt; + txf |= (level != sv->base.last_level ? NV34TCL_TX_FORMAT_MIPMAP : 0); + txf |= util_logbase2(u_minify(pt->width0, level)) << NV34TCL_TX_FORMAT_BASE_SIZE_U_SHIFT; + txf |= util_logbase2(u_minify(pt->height0, level)) << NV34TCL_TX_FORMAT_BASE_SIZE_V_SHIFT; + txf |= util_logbase2(u_minify(pt->depth0, level)) << NV34TCL_TX_FORMAT_BASE_SIZE_W_SHIFT; + txf |= 0x10000; + + sv->u.nv30.fmt[0] = tf->fmt[0] | txf; + sv->u.nv30.fmt[1] = tf->fmt[1] | txf; + sv->u.nv30.fmt[2] = tf->fmt[2] | txf; + sv->u.nv30.fmt[3] = tf->fmt[3] | txf; + + sv->swizzle |= (nvfx_subresource_pitch(pt, 0) << NV34TCL_TX_SWIZZLE_RECT_PITCH_SHIFT); + + if(pt->height0 <= 1 || util_format_is_compressed(sv->base.format)) + sv->u.nv30.rect = -1; + else + sv->u.nv30.rect = !!(pt->flags & NVFX_RESOURCE_FLAG_LINEAR); + + sv->lod_offset = sv->base.first_level - level; + sv->max_lod_limit = sv->base.last_level - level; } - void nv30_fragtex_set(struct nvfx_context *nvfx, int unit) { struct nvfx_sampler_state *ps = nvfx->tex_sampler[unit]; - struct nvfx_miptree *nv30mt = (struct nvfx_miptree *)nvfx->fragment_sampler_views[unit]->texture; - struct pipe_resource *pt = &nv30mt->base.base; - struct nouveau_bo *bo = nv30mt->base.bo; - struct nv30_texture_format *tf; + struct nvfx_sampler_view* sv = (struct nvfx_sampler_view*)nvfx->fragment_sampler_views[unit]; + struct nouveau_bo *bo = ((struct nvfx_miptree *)sv->base.texture)->base.bo; struct nouveau_channel* chan = nvfx->screen->base.channel; - uint32_t txf, txs; + unsigned txf; unsigned tex_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD; + unsigned use_rect; + unsigned max_lod = MIN2(ps->max_lod + sv->lod_offset, sv->max_lod_limit); + unsigned min_lod = MIN2(ps->min_lod + sv->lod_offset, max_lod) ; - tf = nv30_fragtex_format(pt->format); - if (!tf) - return; - - txf = tf->format; - txf |= ((pt->last_level>0) ? NV34TCL_TX_FORMAT_MIPMAP : 0); - txf |= log2i(pt->width0) << NV34TCL_TX_FORMAT_BASE_SIZE_U_SHIFT; - txf |= log2i(pt->height0) << NV34TCL_TX_FORMAT_BASE_SIZE_V_SHIFT; - txf |= log2i(pt->depth0) << NV34TCL_TX_FORMAT_BASE_SIZE_W_SHIFT; - txf |= NV34TCL_TX_FORMAT_NO_BORDER | 0x10000; - - switch (pt->target) { - case PIPE_TEXTURE_CUBE: - txf |= NV34TCL_TX_FORMAT_CUBIC; - /* fall-through */ - case PIPE_TEXTURE_2D: - txf |= NV34TCL_TX_FORMAT_DIMS_2D; - break; - case PIPE_TEXTURE_3D: - txf |= NV34TCL_TX_FORMAT_DIMS_3D; - break; - case PIPE_TEXTURE_1D: - txf |= NV34TCL_TX_FORMAT_DIMS_1D; - break; - default: - NOUVEAU_ERR("Unknown target %d\n", pt->target); - return; + if(sv->u.nv30.rect < 0) + { + /* in the case of compressed or 1D textures, we can get away with this, + * since the layout is the same + */ + use_rect = ps->fmt; + } + else + { + static boolean warned = FALSE; + if( !!ps->fmt != sv->u.nv30.rect && !warned) { + warned = TRUE; + fprintf(stderr, + "Unimplemented: coordinate normalization mismatch. Possible reasons:\n" + "1. ARB_texture_non_power_of_two is being used despite the fact it isn't supported\n" + "2. The state tracker is not using the appropriate coordinate normalization\n" + "3. The state tracker is not supported\n"); + } + + use_rect = sv->u.nv30.rect; } - txs = tf->swizzle; + txf = sv->u.nv30.fmt[ps->compare + (use_rect ? 2 : 0)]; MARK_RING(chan, 9, 2); OUT_RING(chan, RING_3D(NV34TCL_TX_OFFSET(unit), 8)); - OUT_RELOC(chan, bo, 0, tex_flags | NOUVEAU_BO_LOW, 0, 0); - OUT_RELOC(chan, bo, txf, tex_flags | NOUVEAU_BO_OR, - NV34TCL_TX_FORMAT_DMA0, NV34TCL_TX_FORMAT_DMA1); - OUT_RING(chan, ps->wrap); - OUT_RING(chan, NV34TCL_TX_ENABLE_ENABLE | ps->en); - OUT_RING(chan, txs); - OUT_RING(chan, ps->filt | 0x2000 /*voodoo*/); - OUT_RING(chan, (pt->width0 << NV34TCL_TX_NPOT_SIZE_W_SHIFT) | - pt->height0); + OUT_RELOC(chan, bo, sv->offset, tex_flags | NOUVEAU_BO_LOW, 0, 0); + OUT_RELOC(chan, bo, txf, + tex_flags | NOUVEAU_BO_OR, + NV34TCL_TX_FORMAT_DMA0, NV34TCL_TX_FORMAT_DMA1); + OUT_RING(chan, (ps->wrap & sv->wrap_mask) | sv->wrap); + OUT_RING(chan, ps->en | (min_lod << NV34TCL_TX_ENABLE_MIPMAP_MIN_LOD_SHIFT) | (max_lod << NV34TCL_TX_ENABLE_MIPMAP_MAX_LOD_SHIFT)); + OUT_RING(chan, sv->swizzle); + OUT_RING(chan, ps->filt | sv->filt); + OUT_RING(chan, sv->npot_size); OUT_RING(chan, ps->bcol); nvfx->hw_txf[unit] = txf; diff --git a/src/gallium/drivers/nvfx/nv30_vertprog.h b/src/gallium/drivers/nvfx/nv30_vertprog.h index ec0444c07f..9a68f5c1fb 100644 --- a/src/gallium/drivers/nvfx/nv30_vertprog.h +++ b/src/gallium/drivers/nvfx/nv30_vertprog.h @@ -68,7 +68,7 @@ #define NV30_VP_INST_DEST_TEMP_ID_SHIFT 16 #define NV30_VP_INST_DEST_TEMP_ID_MASK (0x0F << 16) #define NV30_VP_INST_COND_UPDATE_ENABLE (1<<15) -#define NV30_VP_INST_VEC_DEST_TEMP_MASK (0xF << 16) +#define NV30_VP_INST_VEC_DEST_TEMP_MASK (0x1F << 16) #define NV30_VP_INST_COND_TEST_ENABLE (1<<14) #define NV30_VP_INST_COND_SHIFT 11 #define NV30_VP_INST_COND_MASK (0x07 << 11) @@ -111,7 +111,7 @@ #define NV30_VP_INST_SRC2H_SHIFT 0 /*NV20*/ #define NV30_VP_INST_SRC2H_MASK (0x7FF << 0) /* NV30_VP_SRC2_HIGH_MASK >> 4*/ #define NV30_VP_INST_IADDR_SHIFT 2 -#define NV30_VP_INST_IADDR_MASK (0xF << 28) /* NV30_VP_SRC2_LOW_MASK << 28 */ +#define NV30_VP_INST_IADDR_MASK (0x1FF << 2) /* NV30_VP_SRC2_LOW_MASK << 28 */ /* DWORD 3 */ #define NV30_VP_INST_SRC2L_SHIFT 28 /*NV20*/ @@ -125,7 +125,7 @@ #define NV30_VP_INST_VDEST_WRITEMASK_SHIFT 12 /*NV20*/ #define NV30_VP_INST_VDEST_WRITEMASK_MASK (0x0F << 12) /*NV20*/ #define NV30_VP_INST_DEST_SHIFT 2 -#define NV30_VP_INST_DEST_MASK (0x0F << 2) +#define NV30_VP_INST_DEST_MASK (0x1F << 2) # define NV30_VP_INST_DEST_POS 0 # define NV30_VP_INST_DEST_BFC0 1 # define NV30_VP_INST_DEST_BFC1 2 @@ -133,7 +133,8 @@ # define NV30_VP_INST_DEST_COL1 4 # define NV30_VP_INST_DEST_FOGC 5 # define NV30_VP_INST_DEST_PSZ 6 -# define NV30_VP_INST_DEST_TC(n) (8+n) +# define NV30_VP_INST_DEST_TC(n) (8+(n)) +# define NV30_VP_INST_DEST_CLP(n) (17 + (n)) /* Useful to split the source selection regs into their pieces */ #define NV30_VP_SRC0_HIGH_SHIFT 6 diff --git a/src/gallium/drivers/nvfx/nv40_fragtex.c b/src/gallium/drivers/nvfx/nv40_fragtex.c index 0068b1ba54..106ce71a07 100644 --- a/src/gallium/drivers/nvfx/nv40_fragtex.c +++ b/src/gallium/drivers/nvfx/nv40_fragtex.c @@ -8,168 +8,97 @@ nv40_sampler_state_init(struct pipe_context *pipe, struct nvfx_sampler_state *ps, const struct pipe_sampler_state *cso) { + float limit; if (cso->max_anisotropy >= 2) { /* no idea, binary driver sets it, works without it.. meh.. */ ps->wrap |= (1 << 5); - if (cso->max_anisotropy >= 16) { + if (cso->max_anisotropy >= 16) ps->en |= NV40TCL_TEX_ENABLE_ANISO_16X; - } else - if (cso->max_anisotropy >= 12) { + else if (cso->max_anisotropy >= 12) ps->en |= NV40TCL_TEX_ENABLE_ANISO_12X; - } else - if (cso->max_anisotropy >= 10) { + else if (cso->max_anisotropy >= 10) ps->en |= NV40TCL_TEX_ENABLE_ANISO_10X; - } else - if (cso->max_anisotropy >= 8) { + else if (cso->max_anisotropy >= 8) ps->en |= NV40TCL_TEX_ENABLE_ANISO_8X; - } else - if (cso->max_anisotropy >= 6) { + else if (cso->max_anisotropy >= 6) ps->en |= NV40TCL_TEX_ENABLE_ANISO_6X; - } else - if (cso->max_anisotropy >= 4) { + else if (cso->max_anisotropy >= 4) ps->en |= NV40TCL_TEX_ENABLE_ANISO_4X; - } else { + else ps->en |= NV40TCL_TEX_ENABLE_ANISO_2X; - } } - { - float limit; + limit = CLAMP(cso->lod_bias, -16.0, 15.0 + (255.0 / 256.0)); + ps->filt |= (int)(cso->lod_bias * 256.0) & 0x1fff; - limit = CLAMP(cso->lod_bias, -16.0, 15.0); - ps->filt |= (int)(cso->lod_bias * 256.0) & 0x1fff; + ps->max_lod = (int)(CLAMP(cso->max_lod, 0.0, 15.0 + (255.0 / 256.0)) * 256.0); + ps->min_lod = (int)(CLAMP(cso->min_lod, 0.0, 15.0 + (255.0 / 256.0)) * 256.0); - limit = CLAMP(cso->max_lod, 0.0, 15.0); - ps->en |= (int)(limit * 256.0) << 7; - - limit = CLAMP(cso->min_lod, 0.0, 15.0); - ps->en |= (int)(limit * 256.0) << 19; - } -} - -#define _(m,tf,ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w,sx,sy,sz,sw) \ -{ \ - TRUE, \ - PIPE_FORMAT_##m, \ - NV40TCL_TEX_FORMAT_FORMAT_##tf, \ - (NV34TCL_TX_SWIZZLE_S0_X_##ts0x | NV34TCL_TX_SWIZZLE_S0_Y_##ts0y | \ - NV34TCL_TX_SWIZZLE_S0_Z_##ts0z | NV34TCL_TX_SWIZZLE_S0_W_##ts0w | \ - NV34TCL_TX_SWIZZLE_S1_X_##ts1x | NV34TCL_TX_SWIZZLE_S1_Y_##ts1y | \ - NV34TCL_TX_SWIZZLE_S1_Z_##ts1z | NV34TCL_TX_SWIZZLE_S1_W_##ts1w), \ - ((NV34TCL_TX_FILTER_SIGNED_RED*sx) | (NV34TCL_TX_FILTER_SIGNED_GREEN*sy) | \ - (NV34TCL_TX_FILTER_SIGNED_BLUE*sz) | (NV34TCL_TX_FILTER_SIGNED_ALPHA*sw)) \ + ps->en |= NV40TCL_TEX_ENABLE_ENABLE; } -struct nv40_texture_format { - boolean defined; - uint pipe; - int format; - int swizzle; - int sign; -}; - -static struct nv40_texture_format -nv40_texture_formats[] = { - _(B8G8R8X8_UNORM, A8R8G8B8, S1, S1, S1, ONE, X, Y, Z, W, 0, 0, 0, 0), - _(B8G8R8A8_UNORM, A8R8G8B8, S1, S1, S1, S1, X, Y, Z, W, 0, 0, 0, 0), - _(B5G5R5A1_UNORM, A1R5G5B5, S1, S1, S1, S1, X, Y, Z, W, 0, 0, 0, 0), - _(B4G4R4A4_UNORM, A4R4G4B4, S1, S1, S1, S1, X, Y, Z, W, 0, 0, 0, 0), - _(B5G6R5_UNORM , R5G6B5 , S1, S1, S1, ONE, X, Y, Z, W, 0, 0, 0, 0), - _(L8_UNORM , L8 , S1, S1, S1, ONE, X, X, X, X, 0, 0, 0, 0), - _(A8_UNORM , L8 , ZERO, ZERO, ZERO, S1, X, X, X, X, 0, 0, 0, 0), - _(R16_SNORM , A16 , ZERO, ZERO, S1, ONE, X, X, X, Y, 1, 1, 1, 1), - _(I8_UNORM , L8 , S1, S1, S1, S1, X, X, X, X, 0, 0, 0, 0), - _(L8A8_UNORM , A8L8 , S1, S1, S1, S1, X, X, X, Y, 0, 0, 0, 0), - _(Z16_UNORM , Z16 , S1, S1, S1, ONE, X, X, X, X, 0, 0, 0, 0), - _(S8_USCALED_Z24_UNORM , Z24 , S1, S1, S1, ONE, X, X, X, X, 0, 0, 0, 0), - _(DXT1_RGB , DXT1 , S1, S1, S1, ONE, X, Y, Z, W, 0, 0, 0, 0), - _(DXT1_RGBA , DXT1 , S1, S1, S1, S1, X, Y, Z, W, 0, 0, 0, 0), - _(DXT3_RGBA , DXT3 , S1, S1, S1, S1, X, Y, Z, W, 0, 0, 0, 0), - _(DXT5_RGBA , DXT5 , S1, S1, S1, S1, X, Y, Z, W, 0, 0, 0, 0), - {}, -}; - -static struct nv40_texture_format * -nv40_fragtex_format(uint pipe_format) +void +nv40_sampler_view_init(struct pipe_context *pipe, + struct nvfx_sampler_view *sv) { - struct nv40_texture_format *tf = nv40_texture_formats; - - while (tf->defined) { - if (tf->pipe == pipe_format) - return tf; - tf++; + struct pipe_resource* pt = sv->base.texture; + struct nvfx_miptree* mt = (struct nvfx_miptree*)pt; + struct nvfx_texture_format *tf = &nvfx_texture_formats[sv->base.format]; + unsigned txf; + unsigned level = pt->target == PIPE_TEXTURE_CUBE ? 0 : sv->base.first_level; + assert(tf->fmt[4] >= 0); + + txf = sv->u.init_fmt; + txf |= 0x8000; + if(pt->target == PIPE_TEXTURE_CUBE) + txf |= ((pt->last_level + 1) << NV40TCL_TEX_FORMAT_MIPMAP_COUNT_SHIFT); + else + txf |= (((sv->base.last_level - sv->base.first_level) + 1) << NV40TCL_TEX_FORMAT_MIPMAP_COUNT_SHIFT); + + if (!mt->linear_pitch) + sv->u.nv40.npot_size2 = 0; + else { + sv->u.nv40.npot_size2 = mt->linear_pitch; + txf |= NV40TCL_TEX_FORMAT_LINEAR; } - NOUVEAU_ERR("unknown texture format %s\n", util_format_name(pipe_format)); - return NULL; -} + sv->u.nv40.fmt[0] = tf->fmt[4] | txf; + sv->u.nv40.fmt[1] = tf->fmt[5] | txf; + sv->u.nv40.npot_size2 |= (u_minify(pt->depth0, level) << NV40TCL_TEX_SIZE1_DEPTH_SHIFT); + + sv->lod_offset = (sv->base.first_level - level) * 256; + sv->max_lod_limit = (sv->base.last_level - level) * 256; +} void nv40_fragtex_set(struct nvfx_context *nvfx, int unit) { struct nouveau_channel* chan = nvfx->screen->base.channel; struct nvfx_sampler_state *ps = nvfx->tex_sampler[unit]; - struct nvfx_miptree *nv40mt = (struct nvfx_miptree *)nvfx->fragment_sampler_views[unit]->texture; - struct nouveau_bo *bo = nv40mt->base.bo; - struct pipe_resource *pt = &nv40mt->base.base; - struct nv40_texture_format *tf; - - uint32_t txf, txs, txp; + struct nvfx_sampler_view* sv = (struct nvfx_sampler_view*)nvfx->fragment_sampler_views[unit]; + struct nouveau_bo *bo = ((struct nvfx_miptree *)sv->base.texture)->base.bo; unsigned tex_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD; + unsigned txf; + unsigned max_lod = MIN2(ps->max_lod + sv->lod_offset, sv->max_lod_limit); + unsigned min_lod = MIN2(ps->min_lod + sv->lod_offset, max_lod); - tf = nv40_fragtex_format(pt->format); - if (!tf) - assert(0); - - txf = ps->fmt; - txf |= tf->format | 0x8000; - txf |= ((pt->last_level + 1) << NV40TCL_TEX_FORMAT_MIPMAP_COUNT_SHIFT); - - if (1) /* XXX */ - txf |= NV34TCL_TX_FORMAT_NO_BORDER; - - switch (pt->target) { - case PIPE_TEXTURE_CUBE: - txf |= NV34TCL_TX_FORMAT_CUBIC; - /* fall-through */ - case PIPE_TEXTURE_2D: - txf |= NV34TCL_TX_FORMAT_DIMS_2D; - break; - case PIPE_TEXTURE_3D: - txf |= NV34TCL_TX_FORMAT_DIMS_3D; - break; - case PIPE_TEXTURE_1D: - txf |= NV34TCL_TX_FORMAT_DIMS_1D; - break; - default: - NOUVEAU_ERR("Unknown target %d\n", pt->target); - return; - } - - if (!(pt->flags & NVFX_RESOURCE_FLAG_LINEAR)) { - txp = 0; - } else { - txp = nv40mt->level[0].pitch; - txf |= NV40TCL_TEX_FORMAT_LINEAR; - } - - txs = tf->swizzle; + txf = sv->u.nv40.fmt[ps->compare] | ps->fmt; - MARK_RING(chan, 11 + 2 * !unit, 2); + MARK_RING(chan, 11, 2); OUT_RING(chan, RING_3D(NV34TCL_TX_OFFSET(unit), 8)); - OUT_RELOC(chan, bo, 0, tex_flags | NOUVEAU_BO_LOW, 0, 0); + OUT_RELOC(chan, bo, sv->offset, tex_flags | NOUVEAU_BO_LOW, 0, 0); OUT_RELOC(chan, bo, txf, tex_flags | NOUVEAU_BO_OR, NV34TCL_TX_FORMAT_DMA0, NV34TCL_TX_FORMAT_DMA1); - OUT_RING(chan, ps->wrap); - OUT_RING(chan, NV40TCL_TEX_ENABLE_ENABLE | ps->en); - OUT_RING(chan, txs); - OUT_RING(chan, ps->filt | tf->sign | 0x2000 /*voodoo*/); - OUT_RING(chan, (pt->width0 << NV34TCL_TX_NPOT_SIZE_W_SHIFT) | pt->height0); + OUT_RING(chan, (ps->wrap & sv->wrap_mask) | sv->wrap); + OUT_RING(chan, ps->en | (min_lod << 19) | (max_lod << 7)); + OUT_RING(chan, sv->swizzle); + OUT_RING(chan, ps->filt | sv->filt); + OUT_RING(chan, sv->npot_size); OUT_RING(chan, ps->bcol); OUT_RING(chan, RING_3D(NV40TCL_TEX_SIZE1(unit), 1)); - OUT_RING(chan, (pt->depth0 << NV40TCL_TEX_SIZE1_DEPTH_SHIFT) | txp); + OUT_RING(chan, sv->u.nv40.npot_size2); nvfx->hw_txf[unit] = txf; nvfx->hw_samplers |= (1 << unit); diff --git a/src/gallium/drivers/nvfx/nv40_vertprog.h b/src/gallium/drivers/nvfx/nv40_vertprog.h index 7337293bab..3d0a1fe3d1 100644 --- a/src/gallium/drivers/nvfx/nv40_vertprog.h +++ b/src/gallium/drivers/nvfx/nv40_vertprog.h @@ -44,7 +44,7 @@ #define NV40_VP_INST_SRC1_ABS (1 << 22) #define NV40_VP_INST_SRC0_ABS (1 << 21) #define NV40_VP_INST_VEC_DEST_TEMP_SHIFT 15 -#define NV40_VP_INST_VEC_DEST_TEMP_MASK (0x1F << 15) +#define NV40_VP_INST_VEC_DEST_TEMP_MASK (0x3F << 15) #define NV40_VP_INST_COND_TEST_ENABLE (1 << 13) #define NV40_VP_INST_COND_SHIFT 10 #define NV40_VP_INST_COND_MASK (0x7 << 10) @@ -100,7 +100,7 @@ #define NV40_VP_INST_SRC2H_SHIFT 0 #define NV40_VP_INST_SRC2H_MASK (0x3F << 0) #define NV40_VP_INST_IADDRH_SHIFT 0 -#define NV40_VP_INST_IADDRH_MASK (0x1F << 0) +#define NV40_VP_INST_IADDRH_MASK (0x3F << 0) /* ---- OPCODE BITS 31:0 / data DWORD 3 --- */ #define NV40_VP_INST_IADDRL_SHIFT 29 diff --git a/src/gallium/drivers/nvfx/nvfx_buffer.c b/src/gallium/drivers/nvfx/nvfx_buffer.c index 05b824b8f7..041099e0e5 100644 --- a/src/gallium/drivers/nvfx/nvfx_buffer.c +++ b/src/gallium/drivers/nvfx/nvfx_buffer.c @@ -6,115 +6,39 @@ #include "nouveau/nouveau_screen.h" #include "nouveau/nouveau_winsys.h" #include "nvfx_resource.h" +#include "nvfx_screen.h" - -/* Currently using separate implementations for buffers and textures, - * even though gallium has a unified abstraction of these objects. - * Eventually these should be combined, and mechanisms like transfers - * be adapted to work for both buffer and texture uploads. - */ -static void nvfx_buffer_destroy(struct pipe_screen *pscreen, +void nvfx_buffer_destroy(struct pipe_screen *pscreen, struct pipe_resource *presource) { - struct nvfx_resource *buffer = nvfx_resource(presource); + struct nvfx_buffer *buffer = nvfx_buffer(presource); - nouveau_screen_bo_release(pscreen, buffer->bo); + if(!(buffer->base.base.flags & NVFX_RESOURCE_FLAG_USER)) + align_free(buffer->data); + nouveau_screen_bo_release(pscreen, buffer->base.bo); FREE(buffer); } - - - -/* Utility functions for transfer create/destroy are hooked in and - * just record the arguments to those functions. - */ -static void * -nvfx_buffer_transfer_map( struct pipe_context *pipe, - struct pipe_transfer *transfer ) -{ - struct nvfx_resource *buffer = nvfx_resource(transfer->resource); - uint8_t *map; - - map = nouveau_screen_bo_map_range( pipe->screen, - buffer->bo, - transfer->box.x, - transfer->box.width, - nouveau_screen_transfer_flags(transfer->usage) ); - if (map == NULL) - return NULL; - - return map + transfer->box.x; -} - - - -static void nvfx_buffer_transfer_flush_region( struct pipe_context *pipe, - struct pipe_transfer *transfer, - const struct pipe_box *box) -{ - struct nvfx_resource *buffer = nvfx_resource(transfer->resource); - - nouveau_screen_bo_map_flush_range(pipe->screen, - buffer->bo, - transfer->box.x + box->x, - box->width); -} - -static void nvfx_buffer_transfer_unmap( struct pipe_context *pipe, - struct pipe_transfer *transfer ) -{ - struct nvfx_resource *buffer = nvfx_resource(transfer->resource); - - nouveau_screen_bo_unmap(pipe->screen, buffer->bo); -} - - - - -struct u_resource_vtbl nvfx_buffer_vtbl = -{ - u_default_resource_get_handle, /* get_handle */ - nvfx_buffer_destroy, /* resource_destroy */ - NULL, /* is_resource_referenced */ - u_default_get_transfer, /* get_transfer */ - u_default_transfer_destroy, /* transfer_destroy */ - nvfx_buffer_transfer_map, /* transfer_map */ - nvfx_buffer_transfer_flush_region, /* transfer_flush_region */ - nvfx_buffer_transfer_unmap, /* transfer_unmap */ - u_default_transfer_inline_write /* transfer_inline_write */ -}; - - - struct pipe_resource * nvfx_buffer_create(struct pipe_screen *pscreen, const struct pipe_resource *template) { - struct nvfx_resource *buffer; + struct nvfx_screen* screen = nvfx_screen(pscreen); + struct nvfx_buffer* buffer; - buffer = CALLOC_STRUCT(nvfx_resource); + buffer = CALLOC_STRUCT(nvfx_buffer); if (!buffer) return NULL; - buffer->base = *template; - buffer->vtbl = &nvfx_buffer_vtbl; - pipe_reference_init(&buffer->base.reference, 1); - buffer->base.screen = pscreen; - - buffer->bo = nouveau_screen_bo_new(pscreen, - 16, - buffer->base.usage, - buffer->base.bind, - buffer->base.width0); - - if (buffer->bo == NULL) - goto fail; - - return &buffer->base; + buffer->base.base = *template; + buffer->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; + pipe_reference_init(&buffer->base.base.reference, 1); + buffer->base.base.screen = pscreen; + buffer->size = util_format_get_stride(template->format, template->width0); + buffer->bytes_to_draw_until_static = buffer->size * screen->static_reuse_threshold; + buffer->data = align_malloc(buffer->size, 16); -fail: - FREE(buffer); - return NULL; + return &buffer->base.base; } @@ -124,30 +48,49 @@ nvfx_user_buffer_create(struct pipe_screen *pscreen, unsigned bytes, unsigned usage) { - struct nvfx_resource *buffer; + struct nvfx_screen* screen = nvfx_screen(pscreen); + struct nvfx_buffer* buffer; - buffer = CALLOC_STRUCT(nvfx_resource); + buffer = CALLOC_STRUCT(nvfx_buffer); if (!buffer) return NULL; - pipe_reference_init(&buffer->base.reference, 1); - buffer->vtbl = &nvfx_buffer_vtbl; - buffer->base.screen = pscreen; - buffer->base.format = PIPE_FORMAT_R8_UNORM; - buffer->base.usage = PIPE_USAGE_IMMUTABLE; - buffer->base.bind = usage; - buffer->base.width0 = bytes; - buffer->base.height0 = 1; - buffer->base.depth0 = 1; - - buffer->bo = nouveau_screen_bo_user(pscreen, ptr, bytes); - if (!buffer->bo) - goto fail; - - return &buffer->base; - -fail: - FREE(buffer); - return NULL; + pipe_reference_init(&buffer->base.base.reference, 1); + buffer->base.base.flags = NVFX_RESOURCE_FLAG_LINEAR | NVFX_RESOURCE_FLAG_USER; + buffer->base.base.screen = pscreen; + buffer->base.base.format = PIPE_FORMAT_R8_UNORM; + buffer->base.base.usage = PIPE_USAGE_IMMUTABLE; + buffer->base.base.bind = usage; + buffer->base.base.width0 = bytes; + buffer->base.base.height0 = 1; + buffer->base.base.depth0 = 1; + buffer->data = ptr; + buffer->size = bytes; + buffer->bytes_to_draw_until_static = bytes * screen->static_reuse_threshold; + buffer->dirty_end = bytes; + + return &buffer->base.base; } +void nvfx_buffer_upload(struct nvfx_buffer* buffer) +{ + unsigned dirty = buffer->dirty_end - buffer->dirty_begin; + if(!buffer->base.bo) + { + buffer->base.bo = nouveau_screen_bo_new(buffer->base.base.screen, + 16, + buffer->base.base.usage, + buffer->base.base.bind, + buffer->base.base.width0); + } + + if(dirty) + { + // TODO: may want to use a temporary in some cases + nouveau_bo_map(buffer->base.bo, NOUVEAU_BO_WR + | (buffer->dirty_unsynchronized ? NOUVEAU_BO_NOSYNC : 0)); + memcpy((uint8_t*)buffer->base.bo->map + buffer->dirty_begin, buffer->data + buffer->dirty_begin, dirty); + nouveau_bo_unmap(buffer->base.bo); + buffer->dirty_begin = buffer->dirty_end = 0; + } +} diff --git a/src/gallium/drivers/nvfx/nvfx_context.c b/src/gallium/drivers/nvfx/nvfx_context.c index 7218abff22..5a2fa14c88 100644 --- a/src/gallium/drivers/nvfx/nvfx_context.c +++ b/src/gallium/drivers/nvfx/nvfx_context.c @@ -1,5 +1,6 @@ #include "draw/draw_context.h" #include "pipe/p_defines.h" +#include "util/u_framebuffer.h" #include "nvfx_context.h" #include "nvfx_screen.h" @@ -14,6 +15,7 @@ nvfx_flush(struct pipe_context *pipe, unsigned flags, struct nouveau_channel *chan = screen->base.channel; struct nouveau_grobj *eng3d = screen->eng3d; + /* XXX: we need to actually be intelligent here */ if (flags & PIPE_FLUSH_TEXTURE_CACHE) { BEGIN_RING(chan, eng3d, 0x1fd8, 1); OUT_RING (chan, 2); @@ -31,8 +33,22 @@ nvfx_destroy(struct pipe_context *pipe) { struct nvfx_context *nvfx = nvfx_context(pipe); + if(nvfx->dummy_fs) + pipe->delete_fs_state(pipe, nvfx->dummy_fs); + + for(unsigned i = 0; i < nvfx->vtxbuf_nr; ++i) + pipe_resource_reference(&nvfx->vtxbuf[i].buffer, 0); + pipe_resource_reference(&nvfx->idxbuf.buffer, 0); + util_unreference_framebuffer_state(&nvfx->framebuffer); + for(unsigned i = 0; i < PIPE_MAX_SAMPLERS; ++i) + pipe_sampler_view_reference(&nvfx->fragment_sampler_views[i], 0); + if (nvfx->draw) draw_destroy(nvfx->draw); + + if(nvfx->screen->cur_ctx == nvfx) + nvfx->screen->cur_ctx = NULL; + FREE(nvfx); } @@ -59,14 +75,21 @@ nvfx_create(struct pipe_screen *pscreen, void *priv) nvfx->pipe.clear = nvfx_clear; nvfx->pipe.flush = nvfx_flush; - screen->base.channel->user_private = nvfx; - nvfx->is_nv4x = screen->is_nv4x; + /* TODO: it seems that nv30 might have fixed function clipping usable with vertex programs + * However, my code for that doesn't work, so use vp clipping for all cards, which works. + */ + nvfx->use_vp_clipping = TRUE; nvfx_init_query_functions(nvfx); nvfx_init_surface_functions(nvfx); nvfx_init_state_functions(nvfx); + nvfx_init_sampling_functions(nvfx); + nvfx_init_vbo_functions(nvfx); + nvfx_init_fragprog_functions(nvfx); + nvfx_init_vertprog_functions(nvfx); nvfx_init_resource_functions(&nvfx->pipe); + nvfx_init_transfer_functions(&nvfx->pipe); /* Create, configure, and install fallback swtnl path */ nvfx->draw = draw_create(&nvfx->pipe); @@ -78,6 +101,12 @@ nvfx_create(struct pipe_screen *pscreen, void *priv) /* set these to that we init them on first validation */ nvfx->state.scissor_enabled = ~0; - nvfx->state.stipple_enabled = ~0; + nvfx->hw_pointsprite_control = -1; + nvfx->hw_vp_output = -1; + nvfx->use_vertex_buffers = -1; + nvfx->relocs_needed = NVFX_RELOCATE_ALL; + + LIST_INITHEAD(&nvfx->render_cache); + return &nvfx->pipe; } diff --git a/src/gallium/drivers/nvfx/nvfx_context.h b/src/gallium/drivers/nvfx/nvfx_context.h index 89f94c10bd..4c654bfa8b 100644 --- a/src/gallium/drivers/nvfx/nvfx_context.h +++ b/src/gallium/drivers/nvfx/nvfx_context.h @@ -11,8 +11,10 @@ #include "util/u_memory.h" #include "util/u_math.h" #include "util/u_inlines.h" +#include "util/u_double_list.h" #include "draw/draw_vertex.h" +#include "util/u_blitter.h" #include "nouveau/nouveau_winsys.h" #include "nouveau/nouveau_gldefs.h" @@ -42,17 +44,26 @@ #define NVFX_NEW_SR (1 << 13) #define NVFX_NEW_VERTCONST (1 << 14) #define NVFX_NEW_FRAGCONST (1 << 15) +#define NVFX_NEW_INDEX (1 << 16) +#define NVFX_NEW_SPRITE (1 << 17) + +#define NVFX_RELOCATE_FRAMEBUFFER (1 << 0) +#define NVFX_RELOCATE_FRAGTEX (1 << 1) +#define NVFX_RELOCATE_FRAGPROG (1 << 2) +#define NVFX_RELOCATE_VTXBUF (1 << 3) +#define NVFX_RELOCATE_IDXBUF (1 << 4) +#define NVFX_RELOCATE_ALL 0x1f struct nvfx_rasterizer_state { struct pipe_rasterizer_state pipe; unsigned sb_len; - uint32_t sb[32]; + uint32_t sb[34]; }; struct nvfx_zsa_state { struct pipe_depth_stencil_alpha_state pipe; unsigned sb_len; - uint32_t sb[26]; + uint32_t sb[24]; }; struct nvfx_blend_state { @@ -64,13 +75,57 @@ struct nvfx_blend_state { struct nvfx_state { unsigned scissor_enabled; - unsigned stipple_enabled; unsigned fp_samplers; + unsigned render_temps; +}; + +struct nvfx_per_vertex_element { + unsigned idx; + unsigned vertex_buffer_index; + unsigned src_offset; +}; + +struct nvfx_low_frequency_element { + unsigned idx; + unsigned vertex_buffer_index; + unsigned src_offset; + void (*fetch_rgba_float)(float *dst, const uint8_t *src, unsigned i, unsigned j); + unsigned ncomp; +}; + +struct nvfx_per_instance_element { + struct nvfx_low_frequency_element base; + unsigned instance_divisor; +}; + +struct nvfx_per_vertex_buffer_info +{ + unsigned vertex_buffer_index; + unsigned per_vertex_size; }; struct nvfx_vtxelt_state { struct pipe_vertex_element pipe[16]; unsigned num_elements; + unsigned vtxfmt[16]; + + unsigned num_per_vertex_buffer_infos; + struct nvfx_per_vertex_buffer_info per_vertex_buffer_info[16]; + + unsigned num_per_vertex; + struct nvfx_per_vertex_element per_vertex[16]; + + unsigned num_per_instance; + struct nvfx_per_instance_element per_instance[16]; + + unsigned num_constant; + struct nvfx_low_frequency_element constant[16]; + + boolean needs_translate; + struct translate* translate; + + unsigned vertex_length; + unsigned max_vertices_per_packet; }; struct nvfx_render_target { @@ -86,8 +141,11 @@ struct nvfx_context { struct nvfx_screen *screen; unsigned is_nv4x; /* either 0 or ~0 */ + boolean use_vp_clipping; struct draw_context *draw; + struct blitter_context* blitter; + struct list_head render_cache; /* HW state derived from pipe states */ struct nvfx_state state; @@ -111,7 +169,7 @@ struct nvfx_context { unsigned stipple[32]; struct pipe_clip_state clip; struct nvfx_vertex_program *vertprog; - struct nvfx_fragment_program *fragprog; + struct nvfx_pipe_fragment_program *fragprog; struct pipe_resource *constbuf[PIPE_SHADER_TYPES]; unsigned constbuf_nr[PIPE_SHADER_TYPES]; struct nvfx_rasterizer_state *rasterizer; @@ -122,23 +180,34 @@ struct nvfx_context { struct pipe_viewport_state viewport; struct pipe_framebuffer_state framebuffer; struct pipe_index_buffer idxbuf; - struct pipe_resource *idxbuf_buffer; - unsigned idxbuf_format; struct nvfx_sampler_state *tex_sampler[PIPE_MAX_SAMPLERS]; struct pipe_sampler_view *fragment_sampler_views[PIPE_MAX_SAMPLERS]; + struct nvfx_pipe_fragment_program* dummy_fs; + unsigned nr_samplers; unsigned nr_textures; unsigned dirty_samplers; struct pipe_vertex_buffer vtxbuf[PIPE_MAX_ATTRIBS]; unsigned vtxbuf_nr; struct nvfx_vtxelt_state *vtxelt; + int base_vertex; + boolean use_index_buffer; + /* -1 = hardware input setup is outdated + * 0 = hardware input setup is for inline vertices + * 1 = hardware input setup is for hardware vertices + */ + int use_vertex_buffers; - unsigned vbo_bo; unsigned hw_vtxelt_nr; uint8_t hw_samplers; uint32_t hw_txf[8]; struct nvfx_render_target hw_rt[4]; struct nvfx_render_target hw_zeta; + int hw_pointsprite_control; + int hw_vp_output; + struct nvfx_fragment_program* hw_fragprog; + + unsigned relocs_needed; }; static INLINE struct nvfx_context * @@ -175,15 +244,12 @@ extern void nvfx_clear(struct pipe_context *pipe, unsigned buffers, /* nvfx_draw.c */ extern struct draw_stage *nvfx_draw_render_stage(struct nvfx_context *nvfx); -extern void nvfx_draw_elements_swtnl(struct pipe_context *pipe, - struct pipe_resource *idxbuf, - unsigned ib_size, int ib_bias, - unsigned mode, - unsigned start, unsigned count); +extern void nvfx_draw_vbo_swtnl(struct pipe_context *pipe, const struct pipe_draw_info* info); extern void nvfx_vtxfmt_validate(struct nvfx_context *nvfx); /* nvfx_fb.c */ -extern void nvfx_state_framebuffer_validate(struct nvfx_context *nvfx); +extern int nvfx_framebuffer_prepare(struct nvfx_context *nvfx); +extern void nvfx_framebuffer_validate(struct nvfx_context *nvfx, unsigned prepare_result); void nvfx_framebuffer_relocate(struct nvfx_context *nvfx); @@ -191,19 +257,24 @@ nvfx_framebuffer_relocate(struct nvfx_context *nvfx); extern void nvfx_fragprog_destroy(struct nvfx_context *, struct nvfx_fragment_program *); extern void nvfx_fragprog_validate(struct nvfx_context *nvfx); -extern void -nvfx_fragprog_relocate(struct nvfx_context *nvfx); +extern void nvfx_fragprog_relocate(struct nvfx_context *nvfx); +extern void nvfx_init_fragprog_functions(struct nvfx_context *nvfx); /* nvfx_fragtex.c */ +extern void nvfx_init_sampling_functions(struct nvfx_context *nvfx); extern void nvfx_fragtex_validate(struct nvfx_context *nvfx); -extern void -nvfx_fragtex_relocate(struct nvfx_context *nvfx); +extern void nvfx_fragtex_relocate(struct nvfx_context *nvfx); + +struct nvfx_sampler_view; /* nv30_fragtex.c */ extern void nv30_sampler_state_init(struct pipe_context *pipe, struct nvfx_sampler_state *ps, const struct pipe_sampler_state *cso); +extern void +nv30_sampler_view_init(struct pipe_context *pipe, + struct nvfx_sampler_view *sv); extern void nv30_fragtex_set(struct nvfx_context *nvfx, int unit); /* nv40_fragtex.c */ @@ -211,6 +282,9 @@ extern void nv40_sampler_state_init(struct pipe_context *pipe, struct nvfx_sampler_state *ps, const struct pipe_sampler_state *cso); +extern void +nv40_sampler_view_init(struct pipe_context *pipe, + struct nvfx_sampler_view *sv); extern void nv40_fragtex_set(struct nvfx_context *nvfx, int unit); /* nvfx_state.c */ @@ -225,23 +299,75 @@ extern void nvfx_state_sr_validate(struct nvfx_context *nvfx); extern void nvfx_state_zsa_validate(struct nvfx_context *nvfx); /* nvfx_state_emit.c */ -extern void nvfx_state_relocate(struct nvfx_context *nvfx); +extern void nvfx_state_relocate(struct nvfx_context *nvfx, unsigned relocs); extern boolean nvfx_state_validate(struct nvfx_context *nvfx); extern boolean nvfx_state_validate_swtnl(struct nvfx_context *nvfx); -extern void nvfx_state_emit(struct nvfx_context *nvfx); + +static inline void +nvfx_state_emit(struct nvfx_context *nvfx) +{ + unsigned relocs = NVFX_RELOCATE_FRAMEBUFFER | NVFX_RELOCATE_FRAGTEX | NVFX_RELOCATE_FRAGPROG; + if (nvfx->render_mode == HW) + { + relocs |= NVFX_RELOCATE_VTXBUF; + if(nvfx->use_index_buffer) + relocs |= NVFX_RELOCATE_IDXBUF; + } + + relocs &= nvfx->relocs_needed; + if(relocs) + nvfx_state_relocate(nvfx, relocs); +} /* nvfx_transfer.c */ -extern void nvfx_init_transfer_functions(struct nvfx_context *nvfx); +extern void nvfx_init_transfer_functions(struct pipe_context *pipe); /* nvfx_vbo.c */ extern boolean nvfx_vbo_validate(struct nvfx_context *nvfx); extern void nvfx_vbo_relocate(struct nvfx_context *nvfx); +extern void nvfx_idxbuf_validate(struct nvfx_context* nvfx); +extern void nvfx_idxbuf_relocate(struct nvfx_context* nvfx); extern void nvfx_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info); +extern void nvfx_init_vbo_functions(struct nvfx_context *nvfx); +extern unsigned nvfx_vertex_formats[]; /* nvfx_vertprog.c */ extern boolean nvfx_vertprog_validate(struct nvfx_context *nvfx); extern void nvfx_vertprog_destroy(struct nvfx_context *, struct nvfx_vertex_program *); +extern void nvfx_init_vertprog_functions(struct nvfx_context *nvfx); + +/* nvfx_push.c */ +extern void nvfx_push_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info); + +/* must WAIT_RING(chan, ncomp + 1) or equivalent beforehand! */ +static inline void nvfx_emit_vtx_attr(struct nouveau_channel* chan, unsigned attrib, const float* v, unsigned ncomp) +{ + switch (ncomp) { + case 4: + OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_4F_X(attrib), 4)); + OUT_RING(chan, fui(v[0])); + OUT_RING(chan, fui(v[1])); + OUT_RING(chan, fui(v[2])); + OUT_RING(chan, fui(v[3])); + break; + case 3: + OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_3F_X(attrib), 3)); + OUT_RING(chan, fui(v[0])); + OUT_RING(chan, fui(v[1])); + OUT_RING(chan, fui(v[2])); + break; + case 2: + OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_2F_X(attrib), 2)); + OUT_RING(chan, fui(v[0])); + OUT_RING(chan, fui(v[1])); + break; + case 1: + OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_1F(attrib), 1)); + OUT_RING(chan, fui(v[0])); + break; + } +} #endif diff --git a/src/gallium/drivers/nvfx/nvfx_draw.c b/src/gallium/drivers/nvfx/nvfx_draw.c index 22cff370b7..2601d5b8e2 100644 --- a/src/gallium/drivers/nvfx/nvfx_draw.c +++ b/src/gallium/drivers/nvfx/nvfx_draw.c @@ -9,6 +9,7 @@ #include "draw/draw_pipe.h" #include "nvfx_context.h" +#include "nvfx_resource.h" /* Simple, but crappy, swtnl path, hopefully we wont need to hit this very * often at all. Uses "quadro style" vertex submission + a fixed vertex @@ -39,30 +40,21 @@ nvfx_render_vertex(struct nvfx_context *nvfx, const struct vertex_header *v) unsigned idx = nvfx->swtnl.draw[i]; unsigned hw = nvfx->swtnl.hw[i]; + WAIT_RING(chan, 5); switch (nvfx->swtnl.emit[i]) { case EMIT_OMIT: break; case EMIT_1F: - BEGIN_RING(chan, eng3d, NV34TCL_VTX_ATTR_1F(hw), 1); - OUT_RING (chan, fui(v->data[idx][0])); + nvfx_emit_vtx_attr(chan, hw, v->data[idx], 1); break; case EMIT_2F: - BEGIN_RING(chan, eng3d, NV34TCL_VTX_ATTR_2F_X(hw), 2); - OUT_RING (chan, fui(v->data[idx][0])); - OUT_RING (chan, fui(v->data[idx][1])); + nvfx_emit_vtx_attr(chan, hw, v->data[idx], 2); break; case EMIT_3F: - BEGIN_RING(chan, eng3d, NV34TCL_VTX_ATTR_3F_X(hw), 3); - OUT_RING (chan, fui(v->data[idx][0])); - OUT_RING (chan, fui(v->data[idx][1])); - OUT_RING (chan, fui(v->data[idx][2])); + nvfx_emit_vtx_attr(chan, hw, v->data[idx], 3); break; case EMIT_4F: - BEGIN_RING(chan, eng3d, NV34TCL_VTX_ATTR_4F_X(hw), 4); - OUT_RING (chan, fui(v->data[idx][0])); - OUT_RING (chan, fui(v->data[idx][1])); - OUT_RING (chan, fui(v->data[idx][2])); - OUT_RING (chan, fui(v->data[idx][3])); + nvfx_emit_vtx_attr(chan, hw, v->data[idx], 4); break; case 0xff: BEGIN_RING(chan, eng3d, NV34TCL_VTX_ATTR_4F_X(hw), 4); @@ -231,15 +223,9 @@ nvfx_draw_render_stage(struct nvfx_context *nvfx) } void -nvfx_draw_elements_swtnl(struct pipe_context *pipe, - struct pipe_resource *idxbuf, - unsigned idxbuf_size, int idxbuf_bias, - unsigned mode, unsigned start, unsigned count) +nvfx_draw_vbo_swtnl(struct pipe_context *pipe, const struct pipe_draw_info* info) { struct nvfx_context *nvfx = nvfx_context(pipe); - struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; - struct pipe_transfer *ib_transfer = NULL; - struct pipe_transfer *cb_transfer = NULL; unsigned i; void *map; @@ -247,47 +233,28 @@ nvfx_draw_elements_swtnl(struct pipe_context *pipe, return; nvfx_state_emit(nvfx); + /* these must be passed without adding the offsets */ for (i = 0; i < nvfx->vtxbuf_nr; i++) { - map = pipe_buffer_map(pipe, nvfx->vtxbuf[i].buffer, - PIPE_TRANSFER_READ, - &vb_transfer[i]); + map = nvfx_buffer(nvfx->vtxbuf[i].buffer)->data; draw_set_mapped_vertex_buffer(nvfx->draw, i, map); } - if (idxbuf) { - map = pipe_buffer_map(pipe, idxbuf, - PIPE_TRANSFER_READ, - &ib_transfer); - draw_set_mapped_element_buffer(nvfx->draw, idxbuf_size, idxbuf_bias, map); - } else { - draw_set_mapped_element_buffer(nvfx->draw, 0, 0, NULL); - } + map = NULL; + if (info->indexed && nvfx->idxbuf.buffer) + map = nvfx_buffer(nvfx->idxbuf.buffer)->data; + draw_set_mapped_index_buffer(nvfx->draw, map); if (nvfx->constbuf[PIPE_SHADER_VERTEX]) { const unsigned nr = nvfx->constbuf_nr[PIPE_SHADER_VERTEX]; - map = pipe_buffer_map(pipe, - nvfx->constbuf[PIPE_SHADER_VERTEX], - PIPE_TRANSFER_READ, - &cb_transfer); + map = nvfx_buffer(nvfx->constbuf[PIPE_SHADER_VERTEX])->data; draw_set_mapped_constant_buffer(nvfx->draw, PIPE_SHADER_VERTEX, 0, map, nr); } - draw_arrays(nvfx->draw, mode, start, count); - - for (i = 0; i < nvfx->vtxbuf_nr; i++) - pipe_buffer_unmap(pipe, nvfx->vtxbuf[i].buffer, vb_transfer[i]); - - if (idxbuf) - pipe_buffer_unmap(pipe, idxbuf, ib_transfer); - - if (nvfx->constbuf[PIPE_SHADER_VERTEX]) - pipe_buffer_unmap(pipe, nvfx->constbuf[PIPE_SHADER_VERTEX], - cb_transfer); + draw_vbo(nvfx->draw, info); draw_flush(nvfx->draw); - pipe->flush(pipe, 0, NULL); } static INLINE void @@ -305,19 +272,19 @@ emit_attrib(struct nvfx_context *nvfx, unsigned hw, unsigned emit, void nvfx_vtxfmt_validate(struct nvfx_context *nvfx) { - struct nvfx_fragment_program *fp = nvfx->fragprog; + struct nvfx_pipe_fragment_program *pfp = nvfx->fragprog; unsigned colour = 0, texcoords = 0, fog = 0, i; /* Determine needed fragprog inputs */ - for (i = 0; i < fp->info.num_inputs; i++) { - switch (fp->info.input_semantic_name[i]) { + for (i = 0; i < pfp->info.num_inputs; i++) { + switch (pfp->info.input_semantic_name[i]) { case TGSI_SEMANTIC_POSITION: break; case TGSI_SEMANTIC_COLOR: - colour |= (1 << fp->info.input_semantic_index[i]); + colour |= (1 << pfp->info.input_semantic_index[i]); break; case TGSI_SEMANTIC_GENERIC: - texcoords |= (1 << fp->info.input_semantic_index[i]); + texcoords |= (1 << pfp->info.input_semantic_index[i]); break; case TGSI_SEMANTIC_FOG: fog = 1; diff --git a/src/gallium/drivers/nvfx/nvfx_fragprog.c b/src/gallium/drivers/nvfx/nvfx_fragprog.c index ee41f03b9b..275672a31f 100644 --- a/src/gallium/drivers/nvfx/nvfx_fragprog.c +++ b/src/gallium/drivers/nvfx/nvfx_fragprog.c @@ -2,25 +2,31 @@ #include "pipe/p_defines.h" #include "pipe/p_state.h" #include "util/u_inlines.h" +#include "util/u_debug.h" #include "pipe/p_shader_tokens.h" #include "tgsi/tgsi_parse.h" #include "tgsi/tgsi_util.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_ureg.h" #include "nvfx_context.h" #include "nvfx_shader.h" +#include "nvfx_resource.h" #define MAX_CONSTS 128 #define MAX_IMM 32 + struct nvfx_fpc { + struct nvfx_pipe_fragment_program* pfp; struct nvfx_fragment_program *fp; - uint attrib_map[PIPE_MAX_SHADER_INPUTS]; - - unsigned r_temps; - unsigned r_temps_discard; - struct nvfx_sreg r_result[PIPE_MAX_SHADER_OUTPUTS]; - struct nvfx_sreg *r_temp; + unsigned max_temps; + unsigned long long r_temps; + unsigned long long r_temps_discard; + struct nvfx_reg r_result[PIPE_MAX_SHADER_OUTPUTS]; + struct nvfx_reg *r_temp; + unsigned sprite_coord_temp; int num_regs; @@ -33,34 +39,40 @@ struct nvfx_fpc { } consts[MAX_CONSTS]; int nr_consts; - struct nvfx_sreg imm[MAX_IMM]; + struct nvfx_reg imm[MAX_IMM]; unsigned nr_imm; + + unsigned char generic_to_slot[256]; /* semantic idx for each input semantic */ + + struct util_dynarray if_stack; + //struct util_dynarray loop_stack; + struct util_dynarray label_relocs; }; -static INLINE struct nvfx_sreg +static INLINE struct nvfx_reg temp(struct nvfx_fpc *fpc) { - int idx = ffs(~fpc->r_temps) - 1; + int idx = __builtin_ctzll(~fpc->r_temps); - if (idx < 0) { + if (idx >= fpc->max_temps) { NOUVEAU_ERR("out of temps!!\n"); assert(0); - return nvfx_sr(NVFXSR_TEMP, 0); + return nvfx_reg(NVFXSR_TEMP, 0); } - fpc->r_temps |= (1 << idx); - fpc->r_temps_discard |= (1 << idx); - return nvfx_sr(NVFXSR_TEMP, idx); + fpc->r_temps |= (1ULL << idx); + fpc->r_temps_discard |= (1ULL << idx); + return nvfx_reg(NVFXSR_TEMP, idx); } static INLINE void release_temps(struct nvfx_fpc *fpc) { fpc->r_temps &= ~fpc->r_temps_discard; - fpc->r_temps_discard = 0; + fpc->r_temps_discard = 0ULL; } -static INLINE struct nvfx_sreg +static INLINE struct nvfx_reg constant(struct nvfx_fpc *fpc, int pipe, float vals[4]) { int idx; @@ -72,16 +84,9 @@ constant(struct nvfx_fpc *fpc, int pipe, float vals[4]) fpc->consts[idx].pipe = pipe; if (pipe == -1) memcpy(fpc->consts[idx].vals, vals, 4 * sizeof(float)); - return nvfx_sr(NVFXSR_CONST, idx); + return nvfx_reg(NVFXSR_CONST, idx); } -#define arith(cc,s,o,d,m,s0,s1,s2) \ - nvfx_fp_arith((cc), (s), NVFX_FP_OP_OPCODE_##o, \ - (d), (m), (s0), (s1), (s2)) -#define tex(cc,s,o,u,d,m,s0,s1,s2) \ - nvfx_fp_tex((cc), (s), NVFX_FP_OP_OPCODE_##o, (u), \ - (d), (m), (s0), none, none) - static void grow_insns(struct nvfx_fpc *fpc, int size) { @@ -92,23 +97,29 @@ grow_insns(struct nvfx_fpc *fpc, int size) } static void -emit_src(struct nvfx_fpc *fpc, int pos, struct nvfx_sreg src) +emit_src(struct nvfx_fpc *fpc, int pos, struct nvfx_src src) { struct nvfx_fragment_program *fp = fpc->fp; uint32_t *hw = &fp->insn[fpc->inst_offset]; uint32_t sr = 0; - switch (src.type) { + switch (src.reg.type) { case NVFXSR_INPUT: sr |= (NVFX_FP_REG_TYPE_INPUT << NVFX_FP_REG_TYPE_SHIFT); - hw[0] |= (src.index << NVFX_FP_OP_INPUT_SRC_SHIFT); + hw[0] |= (src.reg.index << NVFX_FP_OP_INPUT_SRC_SHIFT); break; case NVFXSR_OUTPUT: sr |= NVFX_FP_REG_SRC_HALF; /* fall-through */ case NVFXSR_TEMP: sr |= (NVFX_FP_REG_TYPE_TEMP << NVFX_FP_REG_TYPE_SHIFT); - sr |= (src.index << NVFX_FP_REG_SRC_SHIFT); + sr |= (src.reg.index << NVFX_FP_REG_SRC_SHIFT); + break; + case NVFXSR_RELOCATED: + sr |= (NVFX_FP_REG_TYPE_TEMP << NVFX_FP_REG_TYPE_SHIFT); + sr |= (fpc->sprite_coord_temp << NVFX_FP_REG_SRC_SHIFT); + //printf("adding relocation at %x for %x\n", fpc->inst_offset, src.index); + util_dynarray_append(&fpc->fp->slot_relocations[src.reg.index], unsigned, fpc->inst_offset + pos + 1); break; case NVFXSR_CONST: if (!fpc->have_const) { @@ -117,18 +128,18 @@ emit_src(struct nvfx_fpc *fpc, int pos, struct nvfx_sreg src) } hw = &fp->insn[fpc->inst_offset]; - if (fpc->consts[src.index].pipe >= 0) { + if (fpc->consts[src.reg.index].pipe >= 0) { struct nvfx_fragment_program_data *fpd; fp->consts = realloc(fp->consts, ++fp->nr_consts * sizeof(*fpd)); fpd = &fp->consts[fp->nr_consts - 1]; fpd->offset = fpc->inst_offset + 4; - fpd->index = fpc->consts[src.index].pipe; + fpd->index = fpc->consts[src.reg.index].pipe; memset(&fp->insn[fpd->offset], 0, sizeof(uint32_t) * 4); } else { memcpy(&fp->insn[fpc->inst_offset + 4], - fpc->consts[src.index].vals, + fpc->consts[src.reg.index].vals, sizeof(uint32_t) * 4); } @@ -156,7 +167,7 @@ emit_src(struct nvfx_fpc *fpc, int pos, struct nvfx_sreg src) } static void -emit_dst(struct nvfx_fpc *fpc, struct nvfx_sreg dst) +emit_dst(struct nvfx_fpc *fpc, struct nvfx_reg dst) { struct nvfx_fragment_program *fp = fpc->fp; uint32_t *hw = &fp->insn[fpc->inst_offset]; @@ -184,9 +195,7 @@ emit_dst(struct nvfx_fpc *fpc, struct nvfx_sreg dst) } static void -nvfx_fp_arith(struct nvfx_fpc *fpc, int sat, int op, - struct nvfx_sreg dst, int mask, - struct nvfx_sreg s0, struct nvfx_sreg s1, struct nvfx_sreg s2) +nvfx_fp_emit(struct nvfx_fpc *fpc, struct nvfx_insn insn) { struct nvfx_fragment_program *fp = fpc->fp; uint32_t *hw; @@ -197,68 +206,225 @@ nvfx_fp_arith(struct nvfx_fpc *fpc, int sat, int op, hw = &fp->insn[fpc->inst_offset]; memset(hw, 0, sizeof(uint32_t) * 4); - if (op == NVFX_FP_OP_OPCODE_KIL) + if (insn.op == NVFX_FP_OP_OPCODE_KIL) fp->fp_control |= NV34TCL_FP_CONTROL_USES_KIL; - hw[0] |= (op << NVFX_FP_OP_OPCODE_SHIFT); - hw[0] |= (mask << NVFX_FP_OP_OUTMASK_SHIFT); - hw[2] |= (dst.dst_scale << NVFX_FP_OP_DST_SCALE_SHIFT); + hw[0] |= (insn.op << NVFX_FP_OP_OPCODE_SHIFT); + hw[0] |= (insn.mask << NVFX_FP_OP_OUTMASK_SHIFT); + hw[2] |= (insn.scale << NVFX_FP_OP_DST_SCALE_SHIFT); - if (sat) + if (insn.sat) hw[0] |= NVFX_FP_OP_OUT_SAT; - if (dst.cc_update) + if (insn.cc_update) hw[0] |= NVFX_FP_OP_COND_WRITE_ENABLE; - hw[1] |= (dst.cc_test << NVFX_FP_OP_COND_SHIFT); - hw[1] |= ((dst.cc_swz[0] << NVFX_FP_OP_COND_SWZ_X_SHIFT) | - (dst.cc_swz[1] << NVFX_FP_OP_COND_SWZ_Y_SHIFT) | - (dst.cc_swz[2] << NVFX_FP_OP_COND_SWZ_Z_SHIFT) | - (dst.cc_swz[3] << NVFX_FP_OP_COND_SWZ_W_SHIFT)); - - emit_dst(fpc, dst); - emit_src(fpc, 0, s0); - emit_src(fpc, 1, s1); - emit_src(fpc, 2, s2); + hw[1] |= (insn.cc_test << NVFX_FP_OP_COND_SHIFT); + hw[1] |= ((insn.cc_swz[0] << NVFX_FP_OP_COND_SWZ_X_SHIFT) | + (insn.cc_swz[1] << NVFX_FP_OP_COND_SWZ_Y_SHIFT) | + (insn.cc_swz[2] << NVFX_FP_OP_COND_SWZ_Z_SHIFT) | + (insn.cc_swz[3] << NVFX_FP_OP_COND_SWZ_W_SHIFT)); + + if(insn.unit >= 0) + { + hw[0] |= (insn.unit << NVFX_FP_OP_TEX_UNIT_SHIFT); + fp->samplers |= (1 << insn.unit); + } + + emit_dst(fpc, insn.dst); + emit_src(fpc, 0, insn.src[0]); + emit_src(fpc, 1, insn.src[1]); + emit_src(fpc, 2, insn.src[2]); } +#define arith(s,o,d,m,s0,s1,s2) \ + nvfx_insn((s), NVFX_FP_OP_OPCODE_##o, -1, \ + (d), (m), (s0), (s1), (s2)) + +#define tex(s,o,u,d,m,s0,s1,s2) \ + nvfx_insn((s), NVFX_FP_OP_OPCODE_##o, (u), \ + (d), (m), (s0), none, none) + +/* IF src.x != 0, as TGSI specifies */ static void -nvfx_fp_tex(struct nvfx_fpc *fpc, int sat, int op, int unit, - struct nvfx_sreg dst, int mask, - struct nvfx_sreg s0, struct nvfx_sreg s1, struct nvfx_sreg s2) +nv40_fp_if(struct nvfx_fpc *fpc, struct nvfx_src src) { - struct nvfx_fragment_program *fp = fpc->fp; + const struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE, 0)); + struct nvfx_insn insn = arith(0, MOV, none.reg, NVFX_FP_MASK_X, src, none, none); + uint32_t *hw; + insn.cc_update = 1; + nvfx_fp_emit(fpc, insn); - nvfx_fp_arith(fpc, sat, op, dst, mask, s0, s1, s2); + fpc->inst_offset = fpc->fp->insn_len; + grow_insns(fpc, 4); + hw = &fpc->fp->insn[fpc->inst_offset]; + /* I really wonder why fp16 precision is used. Presumably the hardware ignores it? */ + hw[0] = (NV40_FP_OP_BRA_OPCODE_IF << NVFX_FP_OP_OPCODE_SHIFT) | + NV40_FP_OP_OUT_NONE | + (NVFX_FP_PRECISION_FP16 << NVFX_FP_OP_PRECISION_SHIFT); + /* Use .xxxx swizzle so that we check only src[0].x*/ + hw[1] = (0 << NVFX_FP_OP_COND_SWZ_X_SHIFT) | + (0 << NVFX_FP_OP_COND_SWZ_Y_SHIFT) | + (0 << NVFX_FP_OP_COND_SWZ_Z_SHIFT) | + (0 << NVFX_FP_OP_COND_SWZ_W_SHIFT) | + (NVFX_FP_OP_COND_NE << NVFX_FP_OP_COND_SHIFT); + hw[2] = 0; /* | NV40_FP_OP_OPCODE_IS_BRANCH | else_offset */ + hw[3] = 0; /* | endif_offset */ + util_dynarray_append(&fpc->if_stack, unsigned, fpc->inst_offset); +} + +/* IF src.x != 0, as TGSI specifies */ +static void +nv40_fp_cal(struct nvfx_fpc *fpc, unsigned target) +{ + struct nvfx_relocation reloc; + uint32_t *hw; + fpc->inst_offset = fpc->fp->insn_len; + grow_insns(fpc, 4); + hw = &fpc->fp->insn[fpc->inst_offset]; + /* I really wonder why fp16 precision is used. Presumably the hardware ignores it? */ + hw[0] = (NV40_FP_OP_BRA_OPCODE_CAL << NVFX_FP_OP_OPCODE_SHIFT); + /* Use .xxxx swizzle so that we check only src[0].x*/ + hw[1] = (NVFX_SWZ_IDENTITY << NVFX_FP_OP_COND_SWZ_ALL_SHIFT) | + (NVFX_FP_OP_COND_TR << NVFX_FP_OP_COND_SHIFT); + hw[2] = NV40_FP_OP_OPCODE_IS_BRANCH; /* | call_offset */ + hw[3] = 0; + reloc.target = target; + reloc.location = fpc->inst_offset + 2; + util_dynarray_append(&fpc->label_relocs, struct nvfx_relocation, reloc); +} + +static void +nv40_fp_ret(struct nvfx_fpc *fpc) +{ + uint32_t *hw; + fpc->inst_offset = fpc->fp->insn_len; + grow_insns(fpc, 4); + hw = &fpc->fp->insn[fpc->inst_offset]; + /* I really wonder why fp16 precision is used. Presumably the hardware ignores it? */ + hw[0] = (NV40_FP_OP_BRA_OPCODE_RET << NVFX_FP_OP_OPCODE_SHIFT); + /* Use .xxxx swizzle so that we check only src[0].x*/ + hw[1] = (NVFX_SWZ_IDENTITY << NVFX_FP_OP_COND_SWZ_ALL_SHIFT) | + (NVFX_FP_OP_COND_TR << NVFX_FP_OP_COND_SHIFT); + hw[2] = NV40_FP_OP_OPCODE_IS_BRANCH; /* | call_offset */ + hw[3] = 0; +} - fp->insn[fpc->inst_offset] |= (unit << NVFX_FP_OP_TEX_UNIT_SHIFT); - fp->samplers |= (1 << unit); +static void +nv40_fp_rep(struct nvfx_fpc *fpc, unsigned count, unsigned target) +{ + struct nvfx_relocation reloc; + uint32_t *hw; + fpc->inst_offset = fpc->fp->insn_len; + grow_insns(fpc, 4); + hw = &fpc->fp->insn[fpc->inst_offset]; + /* I really wonder why fp16 precision is used. Presumably the hardware ignores it? */ + hw[0] = (NV40_FP_OP_BRA_OPCODE_REP << NVFX_FP_OP_OPCODE_SHIFT) | + NV40_FP_OP_OUT_NONE | + (NVFX_FP_PRECISION_FP16 << NVFX_FP_OP_PRECISION_SHIFT); + /* Use .xxxx swizzle so that we check only src[0].x*/ + hw[1] = (NVFX_SWZ_IDENTITY << NVFX_FP_OP_COND_SWZ_ALL_SHIFT) | + (NVFX_FP_OP_COND_TR << NVFX_FP_OP_COND_SHIFT); + hw[2] = NV40_FP_OP_OPCODE_IS_BRANCH | + (count << NV40_FP_OP_REP_COUNT1_SHIFT) | + (count << NV40_FP_OP_REP_COUNT2_SHIFT) | + (count << NV40_FP_OP_REP_COUNT3_SHIFT); + hw[3] = 0; /* | end_offset */ + reloc.target = target; + reloc.location = fpc->inst_offset + 3; + util_dynarray_append(&fpc->label_relocs, struct nvfx_relocation, reloc); + //util_dynarray_append(&fpc->loop_stack, unsigned, target); } -static INLINE struct nvfx_sreg +/* warning: this only works forward, and probably only if not inside any IF */ +static void +nv40_fp_bra(struct nvfx_fpc *fpc, unsigned target) +{ + struct nvfx_relocation reloc; + uint32_t *hw; + fpc->inst_offset = fpc->fp->insn_len; + grow_insns(fpc, 4); + hw = &fpc->fp->insn[fpc->inst_offset]; + /* I really wonder why fp16 precision is used. Presumably the hardware ignores it? */ + hw[0] = (NV40_FP_OP_BRA_OPCODE_IF << NVFX_FP_OP_OPCODE_SHIFT) | + NV40_FP_OP_OUT_NONE | + (NVFX_FP_PRECISION_FP16 << NVFX_FP_OP_PRECISION_SHIFT); + /* Use .xxxx swizzle so that we check only src[0].x*/ + hw[1] = (NVFX_SWZ_IDENTITY << NVFX_FP_OP_COND_SWZ_X_SHIFT) | + (NVFX_FP_OP_COND_FL << NVFX_FP_OP_COND_SHIFT); + hw[2] = NV40_FP_OP_OPCODE_IS_BRANCH; /* | else_offset */ + hw[3] = 0; /* | endif_offset */ + reloc.target = target; + reloc.location = fpc->inst_offset + 2; + util_dynarray_append(&fpc->label_relocs, struct nvfx_relocation, reloc); + reloc.target = target; + reloc.location = fpc->inst_offset + 3; + util_dynarray_append(&fpc->label_relocs, struct nvfx_relocation, reloc); +} + +static void +nv40_fp_brk(struct nvfx_fpc *fpc) +{ + uint32_t *hw; + fpc->inst_offset = fpc->fp->insn_len; + grow_insns(fpc, 4); + hw = &fpc->fp->insn[fpc->inst_offset]; + /* I really wonder why fp16 precision is used. Presumably the hardware ignores it? */ + hw[0] = (NV40_FP_OP_BRA_OPCODE_BRK << NVFX_FP_OP_OPCODE_SHIFT) | + NV40_FP_OP_OUT_NONE; + /* Use .xxxx swizzle so that we check only src[0].x*/ + hw[1] = (NVFX_SWZ_IDENTITY << NVFX_FP_OP_COND_SWZ_X_SHIFT) | + (NVFX_FP_OP_COND_TR << NVFX_FP_OP_COND_SHIFT); + hw[2] = NV40_FP_OP_OPCODE_IS_BRANCH; + hw[3] = 0; +} + +static INLINE struct nvfx_src tgsi_src(struct nvfx_fpc *fpc, const struct tgsi_full_src_register *fsrc) { - struct nvfx_sreg src = { 0 }; + struct nvfx_src src; switch (fsrc->Register.File) { case TGSI_FILE_INPUT: - src = nvfx_sr(NVFXSR_INPUT, - fpc->attrib_map[fsrc->Register.Index]); + if(fpc->pfp->info.input_semantic_name[fsrc->Register.Index] == TGSI_SEMANTIC_POSITION) { + assert(fpc->pfp->info.input_semantic_index[fsrc->Register.Index] == 0); + src.reg = nvfx_reg(NVFXSR_INPUT, NVFX_FP_OP_INPUT_SRC_POSITION); + } else if(fpc->pfp->info.input_semantic_name[fsrc->Register.Index] == TGSI_SEMANTIC_COLOR) { + if(fpc->pfp->info.input_semantic_index[fsrc->Register.Index] == 0) + src.reg = nvfx_reg(NVFXSR_INPUT, NVFX_FP_OP_INPUT_SRC_COL0); + else if(fpc->pfp->info.input_semantic_index[fsrc->Register.Index] == 1) + src.reg = nvfx_reg(NVFXSR_INPUT, NVFX_FP_OP_INPUT_SRC_COL1); + else + assert(0); + } else if(fpc->pfp->info.input_semantic_name[fsrc->Register.Index] == TGSI_SEMANTIC_FOG) { + assert(fpc->pfp->info.input_semantic_index[fsrc->Register.Index] == 0); + src.reg = nvfx_reg(NVFXSR_INPUT, NVFX_FP_OP_INPUT_SRC_FOGC); + } else if(fpc->pfp->info.input_semantic_name[fsrc->Register.Index] == TGSI_SEMANTIC_FACE) { + /* TODO: check this has the correct values */ + /* XXX: what do we do for nv30 here (assuming it lacks facing)?! */ + assert(fpc->pfp->info.input_semantic_index[fsrc->Register.Index] == 0); + src.reg = nvfx_reg(NVFXSR_INPUT, NV40_FP_OP_INPUT_SRC_FACING); + } else { + assert(fpc->pfp->info.input_semantic_name[fsrc->Register.Index] == TGSI_SEMANTIC_GENERIC); + src.reg = nvfx_reg(NVFXSR_RELOCATED, fpc->generic_to_slot[fpc->pfp->info.input_semantic_index[fsrc->Register.Index]]); + } break; case TGSI_FILE_CONSTANT: - src = constant(fpc, fsrc->Register.Index, NULL); + src.reg = constant(fpc, fsrc->Register.Index, NULL); break; case TGSI_FILE_IMMEDIATE: assert(fsrc->Register.Index < fpc->nr_imm); - src = fpc->imm[fsrc->Register.Index]; + src.reg = fpc->imm[fsrc->Register.Index]; break; case TGSI_FILE_TEMPORARY: - src = fpc->r_temp[fsrc->Register.Index]; + src.reg = fpc->r_temp[fsrc->Register.Index]; break; /* NV40 fragprog result regs are just temps, so this is simple */ case TGSI_FILE_OUTPUT: - src = fpc->r_result[fsrc->Register.Index]; + src.reg = fpc->r_result[fsrc->Register.Index]; break; default: NOUVEAU_ERR("bad src file\n"); + src.reg.index = 0; + src.reg.type = 0; break; } @@ -271,7 +437,7 @@ tgsi_src(struct nvfx_fpc *fpc, const struct tgsi_full_src_register *fsrc) return src; } -static INLINE struct nvfx_sreg +static INLINE struct nvfx_reg tgsi_dst(struct nvfx_fpc *fpc, const struct tgsi_full_dst_register *fdst) { switch (fdst->Register.File) { case TGSI_FILE_OUTPUT: @@ -279,10 +445,10 @@ tgsi_dst(struct nvfx_fpc *fpc, const struct tgsi_full_dst_register *fdst) { case TGSI_FILE_TEMPORARY: return fpc->r_temp[fdst->Register.Index]; case TGSI_FILE_NULL: - return nvfx_sr(NVFXSR_NONE, 0); + return nvfx_reg(NVFXSR_NONE, 0); default: NOUVEAU_ERR("bad dst file %d\n", fdst->Register.File); - return nvfx_sr(NVFXSR_NONE, 0); + return nvfx_reg(NVFXSR_NONE, 0); } } @@ -302,8 +468,10 @@ static boolean nvfx_fragprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_fpc *fpc, const struct tgsi_full_instruction *finst) { - const struct nvfx_sreg none = nvfx_sr(NVFXSR_NONE, 0); - struct nvfx_sreg src[3], dst, tmp; + const struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE, 0)); + struct nvfx_insn insn; + struct nvfx_src src[3], tmp, tmp2; + struct nvfx_reg dst; int mask, sat, unit = 0; int ai = -1, ci = -1, ii = -1; int i; @@ -331,9 +499,8 @@ nvfx_fragprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_fpc *fpc, ai = fsrc->Register.Index; src[i] = tgsi_src(fpc, fsrc); } else { - src[i] = temp(fpc); - arith(fpc, 0, MOV, src[i], NVFX_FP_MASK_ALL, - tgsi_src(fpc, fsrc), none, none); + src[i] = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, MOV, src[i].reg, NVFX_FP_MASK_ALL, tgsi_src(fpc, fsrc), none, none)); } break; case TGSI_FILE_CONSTANT: @@ -342,9 +509,8 @@ nvfx_fragprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_fpc *fpc, ci = fsrc->Register.Index; src[i] = tgsi_src(fpc, fsrc); } else { - src[i] = temp(fpc); - arith(fpc, 0, MOV, src[i], NVFX_FP_MASK_ALL, - tgsi_src(fpc, fsrc), none, none); + src[i] = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, MOV, src[i].reg, NVFX_FP_MASK_ALL, tgsi_src(fpc, fsrc), none, none)); } break; case TGSI_FILE_IMMEDIATE: @@ -353,9 +519,8 @@ nvfx_fragprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_fpc *fpc, ii = fsrc->Register.Index; src[i] = tgsi_src(fpc, fsrc); } else { - src[i] = temp(fpc); - arith(fpc, 0, MOV, src[i], NVFX_FP_MASK_ALL, - tgsi_src(fpc, fsrc), none, none); + src[i] = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, MOV, src[i].reg, NVFX_FP_MASK_ALL, tgsi_src(fpc, fsrc), none, none)); } break; case TGSI_FILE_TEMPORARY: @@ -378,277 +543,345 @@ nvfx_fragprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_fpc *fpc, switch (finst->Instruction.Opcode) { case TGSI_OPCODE_ABS: - arith(fpc, sat, MOV, dst, mask, abs(src[0]), none, none); + nvfx_fp_emit(fpc, arith(sat, MOV, dst, mask, abs(src[0]), none, none)); break; case TGSI_OPCODE_ADD: - arith(fpc, sat, ADD, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, ADD, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_CMP: - tmp = nvfx_sr(NVFXSR_NONE, 0); - tmp.cc_update = 1; - arith(fpc, 0, MOV, tmp, 0xf, src[0], none, none); - dst.cc_test = NVFX_COND_GE; - arith(fpc, sat, MOV, dst, mask, src[2], none, none); - dst.cc_test = NVFX_COND_LT; - arith(fpc, sat, MOV, dst, mask, src[1], none, none); + insn = arith(0, MOV, none.reg, mask, src[0], none, none); + insn.cc_update = 1; + nvfx_fp_emit(fpc, insn); + + insn = arith(sat, MOV, dst, mask, src[2], none, none); + insn.cc_test = NVFX_COND_GE; + nvfx_fp_emit(fpc, insn); + + insn = arith(sat, MOV, dst, mask, src[1], none, none); + insn.cc_test = NVFX_COND_LT; + nvfx_fp_emit(fpc, insn); break; case TGSI_OPCODE_COS: - arith(fpc, sat, COS, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, arith(sat, COS, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_DDX: if (mask & (NVFX_FP_MASK_Z | NVFX_FP_MASK_W)) { - tmp = temp(fpc); - arith(fpc, sat, DDX, tmp, NVFX_FP_MASK_X | NVFX_FP_MASK_Y, - swz(src[0], Z, W, Z, W), none, none); - arith(fpc, 0, MOV, tmp, NVFX_FP_MASK_Z | NVFX_FP_MASK_W, - swz(tmp, X, Y, X, Y), none, none); - arith(fpc, sat, DDX, tmp, NVFX_FP_MASK_X | NVFX_FP_MASK_Y, src[0], - none, none); - arith(fpc, 0, MOV, dst, mask, tmp, none, none); + tmp = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(sat, DDX, tmp.reg, NVFX_FP_MASK_X | NVFX_FP_MASK_Y, swz(src[0], Z, W, Z, W), none, none)); + nvfx_fp_emit(fpc, arith(0, MOV, tmp.reg, NVFX_FP_MASK_Z | NVFX_FP_MASK_W, swz(tmp, X, Y, X, Y), none, none)); + nvfx_fp_emit(fpc, arith(sat, DDX, tmp.reg, NVFX_FP_MASK_X | NVFX_FP_MASK_Y, src[0], none, none)); + nvfx_fp_emit(fpc, arith(0, MOV, dst, mask, tmp, none, none)); } else { - arith(fpc, sat, DDX, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, arith(sat, DDX, dst, mask, src[0], none, none)); } break; case TGSI_OPCODE_DDY: if (mask & (NVFX_FP_MASK_Z | NVFX_FP_MASK_W)) { - tmp = temp(fpc); - arith(fpc, sat, DDY, tmp, NVFX_FP_MASK_X | NVFX_FP_MASK_Y, - swz(src[0], Z, W, Z, W), none, none); - arith(fpc, 0, MOV, tmp, NVFX_FP_MASK_Z | NVFX_FP_MASK_W, - swz(tmp, X, Y, X, Y), none, none); - arith(fpc, sat, DDY, tmp, NVFX_FP_MASK_X | NVFX_FP_MASK_Y, src[0], - none, none); - arith(fpc, 0, MOV, dst, mask, tmp, none, none); + tmp = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(sat, DDY, tmp.reg, NVFX_FP_MASK_X | NVFX_FP_MASK_Y, swz(src[0], Z, W, Z, W), none, none)); + nvfx_fp_emit(fpc, arith(0, MOV, tmp.reg, NVFX_FP_MASK_Z | NVFX_FP_MASK_W, swz(tmp, X, Y, X, Y), none, none)); + nvfx_fp_emit(fpc, arith(sat, DDY, tmp.reg, NVFX_FP_MASK_X | NVFX_FP_MASK_Y, src[0], none, none)); + nvfx_fp_emit(fpc, arith(0, MOV, dst, mask, tmp, none, none)); } else { - arith(fpc, sat, DDY, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, arith(sat, DDY, dst, mask, src[0], none, none)); } break; + case TGSI_OPCODE_DP2: + tmp = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, MUL, tmp.reg, NVFX_FP_MASK_X | NVFX_FP_MASK_Y, src[0], src[1], none)); + nvfx_fp_emit(fpc, arith(0, ADD, dst, mask, swz(tmp, X, X, X, X), swz(tmp, Y, Y, Y, Y), none)); + break; case TGSI_OPCODE_DP3: - arith(fpc, sat, DP3, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, DP3, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_DP4: - arith(fpc, sat, DP4, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, DP4, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_DPH: - tmp = temp(fpc); - arith(fpc, 0, DP3, tmp, NVFX_FP_MASK_X, src[0], src[1], none); - arith(fpc, sat, ADD, dst, mask, swz(tmp, X, X, X, X), - swz(src[1], W, W, W, W), none); + tmp = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, DP3, tmp.reg, NVFX_FP_MASK_X, src[0], src[1], none)); + nvfx_fp_emit(fpc, arith(sat, ADD, dst, mask, swz(tmp, X, X, X, X), swz(src[1], W, W, W, W), none)); break; case TGSI_OPCODE_DST: - arith(fpc, sat, DST, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, DST, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_EX2: - arith(fpc, sat, EX2, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, arith(sat, EX2, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_FLR: - arith(fpc, sat, FLR, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, arith(sat, FLR, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_FRC: - arith(fpc, sat, FRC, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, arith(sat, FRC, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_KILP: - arith(fpc, 0, KIL, none, 0, none, none, none); + nvfx_fp_emit(fpc, arith(0, KIL, none.reg, 0, none, none, none)); break; case TGSI_OPCODE_KIL: - dst = nvfx_sr(NVFXSR_NONE, 0); - dst.cc_update = 1; - arith(fpc, 0, MOV, dst, NVFX_FP_MASK_ALL, src[0], none, none); - dst.cc_update = 0; dst.cc_test = NVFX_COND_LT; - arith(fpc, 0, KIL, dst, 0, none, none, none); + insn = arith(0, MOV, none.reg, NVFX_FP_MASK_ALL, src[0], none, none); + insn.cc_update = 1; + nvfx_fp_emit(fpc, insn); + + insn = arith(0, KIL, none.reg, 0, none, none, none); + insn.cc_test = NVFX_COND_LT; + nvfx_fp_emit(fpc, insn); break; case TGSI_OPCODE_LG2: - arith(fpc, sat, LG2, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, arith(sat, LG2, dst, mask, src[0], none, none)); break; // case TGSI_OPCODE_LIT: case TGSI_OPCODE_LRP: if(!nvfx->is_nv4x) - arith(fpc, sat, LRP_NV30, dst, mask, src[0], src[1], src[2]); + nvfx_fp_emit(fpc, arith(sat, LRP_NV30, dst, mask, src[0], src[1], src[2])); else { - tmp = temp(fpc); - arith(fpc, 0, MAD, tmp, mask, neg(src[0]), src[2], src[2]); - arith(fpc, sat, MAD, dst, mask, src[0], src[1], tmp); + tmp = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, MAD, tmp.reg, mask, neg(src[0]), src[2], src[2])); + nvfx_fp_emit(fpc, arith(sat, MAD, dst, mask, src[0], src[1], tmp)); } break; case TGSI_OPCODE_MAD: - arith(fpc, sat, MAD, dst, mask, src[0], src[1], src[2]); + nvfx_fp_emit(fpc, arith(sat, MAD, dst, mask, src[0], src[1], src[2])); break; case TGSI_OPCODE_MAX: - arith(fpc, sat, MAX, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, MAX, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_MIN: - arith(fpc, sat, MIN, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, MIN, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_MOV: - arith(fpc, sat, MOV, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, arith(sat, MOV, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_MUL: - arith(fpc, sat, MUL, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, MUL, dst, mask, src[0], src[1], none)); + break; + case TGSI_OPCODE_NOP: break; case TGSI_OPCODE_POW: if(!nvfx->is_nv4x) - arith(fpc, sat, POW_NV30, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, POW_NV30, dst, mask, src[0], src[1], none)); else { - tmp = temp(fpc); - arith(fpc, 0, LG2, tmp, NVFX_FP_MASK_X, - swz(src[0], X, X, X, X), none, none); - arith(fpc, 0, MUL, tmp, NVFX_FP_MASK_X, swz(tmp, X, X, X, X), - swz(src[1], X, X, X, X), none); - arith(fpc, sat, EX2, dst, mask, - swz(tmp, X, X, X, X), none, none); + tmp = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, LG2, tmp.reg, NVFX_FP_MASK_X, swz(src[0], X, X, X, X), none, none)); + nvfx_fp_emit(fpc, arith(0, MUL, tmp.reg, NVFX_FP_MASK_X, swz(tmp, X, X, X, X), swz(src[1], X, X, X, X), none)); + nvfx_fp_emit(fpc, arith(sat, EX2, dst, mask, swz(tmp, X, X, X, X), none, none)); } break; case TGSI_OPCODE_RCP: - arith(fpc, sat, RCP, dst, mask, src[0], none, none); - break; - case TGSI_OPCODE_RET: - assert(0); + nvfx_fp_emit(fpc, arith(sat, RCP, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_RFL: if(!nvfx->is_nv4x) - arith(fpc, 0, RFL_NV30, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(0, RFL_NV30, dst, mask, src[0], src[1], none)); else { - tmp = temp(fpc); - arith(fpc, 0, DP3, tmp, NVFX_FP_MASK_X, src[0], src[0], none); - arith(fpc, 0, DP3, tmp, NVFX_FP_MASK_Y, src[0], src[1], none); - arith(fpc, 0, DIV, scale(tmp, 2X), NVFX_FP_MASK_Z, - swz(tmp, Y, Y, Y, Y), swz(tmp, X, X, X, X), none); - arith(fpc, sat, MAD, dst, mask, - swz(tmp, Z, Z, Z, Z), src[0], neg(src[1])); + tmp = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, DP3, tmp.reg, NVFX_FP_MASK_X, src[0], src[0], none)); + nvfx_fp_emit(fpc, arith(0, DP3, tmp.reg, NVFX_FP_MASK_Y, src[0], src[1], none)); + insn = arith(0, DIV, tmp.reg, NVFX_FP_MASK_Z, swz(tmp, Y, Y, Y, Y), swz(tmp, X, X, X, X), none); + insn.scale = NVFX_FP_OP_DST_SCALE_2X; + nvfx_fp_emit(fpc, insn); + nvfx_fp_emit(fpc, arith(sat, MAD, dst, mask, swz(tmp, Z, Z, Z, Z), src[0], neg(src[1]))); } break; case TGSI_OPCODE_RSQ: if(!nvfx->is_nv4x) - arith(fpc, sat, RSQ_NV30, dst, mask, abs(swz(src[0], X, X, X, X)), none, none); + nvfx_fp_emit(fpc, arith(sat, RSQ_NV30, dst, mask, abs(swz(src[0], X, X, X, X)), none, none)); else { - tmp = temp(fpc); - arith(fpc, 0, LG2, scale(tmp, INV_2X), NVFX_FP_MASK_X, - abs(swz(src[0], X, X, X, X)), none, none); - arith(fpc, sat, EX2, dst, mask, - neg(swz(tmp, X, X, X, X)), none, none); + tmp = nvfx_src(temp(fpc)); + insn = arith(0, LG2, tmp.reg, NVFX_FP_MASK_X, abs(swz(src[0], X, X, X, X)), none, none); + insn.scale = NVFX_FP_OP_DST_SCALE_INV_2X; + nvfx_fp_emit(fpc, insn); + nvfx_fp_emit(fpc, arith(sat, EX2, dst, mask, neg(swz(tmp, X, X, X, X)), none, none)); } break; case TGSI_OPCODE_SCS: /* avoid overwriting the source */ if(src[0].swz[NVFX_SWZ_X] != NVFX_SWZ_X) { - if (mask & NVFX_FP_MASK_X) { - arith(fpc, sat, COS, dst, NVFX_FP_MASK_X, - swz(src[0], X, X, X, X), none, none); - } - if (mask & NVFX_FP_MASK_Y) { - arith(fpc, sat, SIN, dst, NVFX_FP_MASK_Y, - swz(src[0], X, X, X, X), none, none); - } + if (mask & NVFX_FP_MASK_X) + nvfx_fp_emit(fpc, arith(sat, COS, dst, NVFX_FP_MASK_X, swz(src[0], X, X, X, X), none, none)); + if (mask & NVFX_FP_MASK_Y) + nvfx_fp_emit(fpc, arith(sat, SIN, dst, NVFX_FP_MASK_Y, swz(src[0], X, X, X, X), none, none)); } else { - if (mask & NVFX_FP_MASK_Y) { - arith(fpc, sat, SIN, dst, NVFX_FP_MASK_Y, - swz(src[0], X, X, X, X), none, none); - } - if (mask & NVFX_FP_MASK_X) { - arith(fpc, sat, COS, dst, NVFX_FP_MASK_X, - swz(src[0], X, X, X, X), none, none); - } + if (mask & NVFX_FP_MASK_Y) + nvfx_fp_emit(fpc, arith(sat, SIN, dst, NVFX_FP_MASK_Y, swz(src[0], X, X, X, X), none, none)); + if (mask & NVFX_FP_MASK_X) + nvfx_fp_emit(fpc, arith(sat, COS, dst, NVFX_FP_MASK_X, swz(src[0], X, X, X, X), none, none)); } break; case TGSI_OPCODE_SEQ: - arith(fpc, sat, SEQ, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, SEQ, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SFL: - arith(fpc, sat, SFL, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, SFL, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SGE: - arith(fpc, sat, SGE, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, SGE, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SGT: - arith(fpc, sat, SGT, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, SGT, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SIN: - arith(fpc, sat, SIN, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, arith(sat, SIN, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_SLE: - arith(fpc, sat, SLE, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, SLE, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SLT: - arith(fpc, sat, SLT, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, SLT, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SNE: - arith(fpc, sat, SNE, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, SNE, dst, mask, src[0], src[1], none)); + break; + case TGSI_OPCODE_SSG: + tmp = nvfx_src(temp(fpc)); + tmp2 = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, SGT, tmp.reg, mask, src[0], nvfx_src(nvfx_reg(NVFXSR_CONST, 0)), none)); + nvfx_fp_emit(fpc, arith(0, SLT, tmp.reg, mask, src[0], nvfx_src(nvfx_reg(NVFXSR_CONST, 0)), none)); + nvfx_fp_emit(fpc, arith(sat, ADD, dst, mask, tmp, neg(tmp2), none)); break; case TGSI_OPCODE_STR: - arith(fpc, sat, STR, dst, mask, src[0], src[1], none); + nvfx_fp_emit(fpc, arith(sat, STR, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SUB: - arith(fpc, sat, ADD, dst, mask, src[0], neg(src[1]), none); + nvfx_fp_emit(fpc, arith(sat, ADD, dst, mask, src[0], neg(src[1]), none)); break; case TGSI_OPCODE_TEX: - tex(fpc, sat, TEX, unit, dst, mask, src[0], none, none); + nvfx_fp_emit(fpc, tex(sat, TEX, unit, dst, mask, src[0], none, none)); break; - case TGSI_OPCODE_TXB: - tex(fpc, sat, TXB, unit, dst, mask, src[0], none, none); + case TGSI_OPCODE_TRUNC: + tmp = nvfx_src(temp(fpc)); + insn = arith(0, MOV, none.reg, mask, src[0], none, none); + insn.cc_update = 1; + nvfx_fp_emit(fpc, insn); + + nvfx_fp_emit(fpc, arith(0, FLR, tmp.reg, mask, abs(src[0]), none, none)); + nvfx_fp_emit(fpc, arith(sat, MOV, dst, mask, tmp, none, none)); + + insn = arith(sat, MOV, dst, mask, neg(tmp), none, none); + insn.cc_test = NVFX_COND_LT; + nvfx_fp_emit(fpc, insn); + break; + case TGSI_OPCODE_TXB: + nvfx_fp_emit(fpc, tex(sat, TXB, unit, dst, mask, src[0], none, none)); + break; + case TGSI_OPCODE_TXL: + if(nvfx->is_nv4x) + nvfx_fp_emit(fpc, tex(sat, TXL_NV40, unit, dst, mask, src[0], none, none)); + else /* unsupported on nv30, use TEX and hope they like it */ + nvfx_fp_emit(fpc, tex(sat, TEX, unit, dst, mask, src[0], none, none)); + break; + case TGSI_OPCODE_TXP: + nvfx_fp_emit(fpc, tex(sat, TXP, unit, dst, mask, src[0], none, none)); + break; + case TGSI_OPCODE_XPD: + tmp = nvfx_src(temp(fpc)); + nvfx_fp_emit(fpc, arith(0, MUL, tmp.reg, mask, swz(src[0], Z, X, Y, Y), swz(src[1], Y, Z, X, X), none)); + nvfx_fp_emit(fpc, arith(sat, MAD, dst, (mask & ~NVFX_FP_MASK_W), swz(src[0], Y, Z, X, X), swz(src[1], Z, X, Y, Y), neg(tmp))); break; - case TGSI_OPCODE_TXP: - tex(fpc, sat, TXP, unit, dst, mask, src[0], none, none); + + case TGSI_OPCODE_IF: + // MOVRC0 R31 (TR0.xyzw), R<src>: + // IF (NE.xxxx) ELSE <else> END <end> + if(!nvfx->is_nv4x) + goto nv3x_cflow; + nv40_fp_if(fpc, src[0]); break; - case TGSI_OPCODE_XPD: - tmp = temp(fpc); - arith(fpc, 0, MUL, tmp, mask, - swz(src[0], Z, X, Y, Y), swz(src[1], Y, Z, X, X), none); - arith(fpc, sat, MAD, dst, (mask & ~NVFX_FP_MASK_W), - swz(src[0], Y, Z, X, X), swz(src[1], Z, X, Y, Y), - neg(tmp)); + + case TGSI_OPCODE_ELSE: + { + uint32_t *hw; + if(!nvfx->is_nv4x) + goto nv3x_cflow; + assert(util_dynarray_contains(&fpc->if_stack, unsigned)); + hw = &fpc->fp->insn[util_dynarray_top(&fpc->if_stack, unsigned)]; + hw[2] = NV40_FP_OP_OPCODE_IS_BRANCH | fpc->fp->insn_len; break; - default: - NOUVEAU_ERR("invalid opcode %d\n", finst->Instruction.Opcode); - return FALSE; } - release_temps(fpc); - return TRUE; -} + case TGSI_OPCODE_ENDIF: + { + uint32_t *hw; + if(!nvfx->is_nv4x) + goto nv3x_cflow; + assert(util_dynarray_contains(&fpc->if_stack, unsigned)); + hw = &fpc->fp->insn[util_dynarray_pop(&fpc->if_stack, unsigned)]; + if(!hw[2]) + hw[2] = NV40_FP_OP_OPCODE_IS_BRANCH | fpc->fp->insn_len; + hw[3] = fpc->fp->insn_len; + break; + } -static boolean -nvfx_fragprog_parse_decl_attrib(struct nvfx_context* nvfx, struct nvfx_fpc *fpc, - const struct tgsi_full_declaration *fdec) -{ - int hw; + case TGSI_OPCODE_BRA: + /* This can in limited cases be implemented with an IF with the else and endif labels pointing to the target */ + /* no state tracker uses this, so don't implement this for now */ + assert(0); + nv40_fp_bra(fpc, finst->Label.Label); + break; - switch (fdec->Semantic.Name) { - case TGSI_SEMANTIC_POSITION: - hw = NVFX_FP_OP_INPUT_SRC_POSITION; + case TGSI_OPCODE_BGNSUB: + case TGSI_OPCODE_ENDSUB: + /* nothing to do here */ break; - case TGSI_SEMANTIC_COLOR: - if (fdec->Semantic.Index == 0) { - hw = NVFX_FP_OP_INPUT_SRC_COL0; - } else - if (fdec->Semantic.Index == 1) { - hw = NVFX_FP_OP_INPUT_SRC_COL1; - } else { - NOUVEAU_ERR("bad colour semantic index\n"); - return FALSE; - } + + case TGSI_OPCODE_CAL: + if(!nvfx->is_nv4x) + goto nv3x_cflow; + nv40_fp_cal(fpc, finst->Label.Label); break; - case TGSI_SEMANTIC_FOG: - hw = NVFX_FP_OP_INPUT_SRC_FOGC; + + case TGSI_OPCODE_RET: + if(!nvfx->is_nv4x) + goto nv3x_cflow; + nv40_fp_ret(fpc); break; - case TGSI_SEMANTIC_GENERIC: - if (fdec->Semantic.Index <= 7) { - hw = NVFX_FP_OP_INPUT_SRC_TC(fdec->Semantic. - Index); - } else { - NOUVEAU_ERR("bad generic semantic index\n"); - return FALSE; + + case TGSI_OPCODE_BGNLOOP: + if(!nvfx->is_nv4x) + goto nv3x_cflow; + /* TODO: we should support using two nested REPs to allow a > 255 iteration count */ + nv40_fp_rep(fpc, 255, finst->Label.Label); + break; + + case TGSI_OPCODE_ENDLOOP: + break; + + case TGSI_OPCODE_BRK: + if(!nvfx->is_nv4x) + goto nv3x_cflow; + nv40_fp_brk(fpc); + break; + + case TGSI_OPCODE_CONT: + { + static int warned = 0; + if(!warned) { + NOUVEAU_ERR("Sorry, the continue keyword is not implemented: ignoring it.\n"); + warned = 1; } break; - default: - NOUVEAU_ERR("bad input semantic\n"); + } + + default: + NOUVEAU_ERR("invalid opcode %d\n", finst->Instruction.Opcode); return FALSE; } - fpc->attrib_map[fdec->Range.First] = hw; +out: + release_temps(fpc); return TRUE; +nv3x_cflow: + { + static int warned = 0; + if(!warned) { + NOUVEAU_ERR( + "Sorry, control flow instructions are not supported in hardware on nv3x: ignoring them\n" + "If rendering is incorrect, try to disable GLSL support in the application.\n"); + warned = 1; + } + } + goto out; } static boolean @@ -680,8 +913,8 @@ nvfx_fragprog_parse_decl_output(struct nvfx_context* nvfx, struct nvfx_fpc *fpc, return FALSE; } - fpc->r_result[idx] = nvfx_sr(NVFXSR_OUTPUT, hw); - fpc->r_temps |= (1 << hw); + fpc->r_result[idx] = nvfx_reg(NVFXSR_OUTPUT, hw); + fpc->r_temps |= (1ULL << hw); return TRUE; } @@ -690,8 +923,22 @@ nvfx_fragprog_prepare(struct nvfx_context* nvfx, struct nvfx_fpc *fpc) { struct tgsi_parse_context p; int high_temp = -1, i; + struct util_semantic_set set; + float const0v[4] = {0, 0, 0, 0}; + struct nvfx_reg const0; + + fpc->fp->num_slots = util_semantic_set_from_program_file(&set, fpc->pfp->pipe.tokens, TGSI_FILE_INPUT); + if(fpc->fp->num_slots > 8) + return FALSE; + util_semantic_layout_from_set(fpc->fp->slot_to_generic, &set, 0, 8); + util_semantic_table_from_layout(fpc->generic_to_slot, fpc->fp->slot_to_generic, 0, 8); - tgsi_parse_init(&p, fpc->fp->pipe.tokens); + memset(fpc->fp->slot_to_fp_input, 0xff, sizeof(fpc->fp->slot_to_fp_input)); + + const0 = constant(fpc, -1, const0v); + assert(const0.index == 0); + + tgsi_parse_init(&p, fpc->pfp->pipe.tokens); while (!tgsi_parse_end_of_tokens(&p)) { const union tgsi_full_token *tok = &p.FullToken; @@ -702,10 +949,6 @@ nvfx_fragprog_prepare(struct nvfx_context* nvfx, struct nvfx_fpc *fpc) const struct tgsi_full_declaration *fdec; fdec = &p.FullToken.FullDeclaration; switch (fdec->Declaration.File) { - case TGSI_FILE_INPUT: - if (!nvfx_fragprog_parse_decl_attrib(nvfx, fpc, fdec)) - goto out_err; - break; case TGSI_FILE_OUTPUT: if (!nvfx_fragprog_parse_decl_output(nvfx, fpc, fdec)) goto out_err; @@ -744,40 +987,66 @@ nvfx_fragprog_prepare(struct nvfx_context* nvfx, struct nvfx_fpc *fpc) tgsi_parse_free(&p); if (++high_temp) { - fpc->r_temp = CALLOC(high_temp, sizeof(struct nvfx_sreg)); + fpc->r_temp = CALLOC(high_temp, sizeof(struct nvfx_reg)); for (i = 0; i < high_temp; i++) fpc->r_temp[i] = temp(fpc); - fpc->r_temps_discard = 0; + fpc->r_temps_discard = 0ULL; } return TRUE; out_err: - if (fpc->r_temp) + if (fpc->r_temp) { FREE(fpc->r_temp); + fpc->r_temp = NULL; + } tgsi_parse_free(&p); return FALSE; } -static void +DEBUG_GET_ONCE_BOOL_OPTION(nvfx_dump_fp, "NVFX_DUMP_FP", FALSE) + +static struct nvfx_fragment_program* nvfx_fragprog_translate(struct nvfx_context *nvfx, - struct nvfx_fragment_program *fp) + struct nvfx_pipe_fragment_program *pfp, + boolean emulate_sprite_flipping) { struct tgsi_parse_context parse; struct nvfx_fpc *fpc = NULL; + struct util_dynarray insns; + struct nvfx_fragment_program* fp = NULL; + const int min_size = 4096; - fpc = CALLOC(1, sizeof(struct nvfx_fpc)); + fp = CALLOC_STRUCT(nvfx_fragment_program); + if(!fp) + goto out_err; + + fpc = CALLOC_STRUCT(nvfx_fpc); if (!fpc) - return; + goto out_err; + + fpc->max_temps = nvfx->is_nv4x ? 48 : 32; + fpc->pfp = pfp; fpc->fp = fp; fpc->num_regs = 2; - if (!nvfx_fragprog_prepare(nvfx, fpc)) { - FREE(fpc); - return; - } + if (!nvfx_fragprog_prepare(nvfx, fpc)) + goto out_err; - tgsi_parse_init(&parse, fp->pipe.tokens); + tgsi_parse_init(&parse, pfp->pipe.tokens); + util_dynarray_init(&insns); + + if(emulate_sprite_flipping) + { + struct nvfx_reg reg = temp(fpc); + struct nvfx_src sprite_input = nvfx_src(nvfx_reg(NVFXSR_RELOCATED, fp->num_slots)); + float v[4] = {1, -1, 0, 0}; + struct nvfx_src imm = nvfx_src(constant(fpc, -1, v)); + + fpc->sprite_coord_temp = reg.index; + fpc->r_temps_discard = 0ULL; + nvfx_fp_emit(fpc, arith(0, MAD, reg, NVFX_FP_MASK_ALL, sprite_input, swz(imm, X, Y, X, X), swz(imm, Z, X, Z, Z))); + } while (!tgsi_parse_end_of_tokens(&parse)) { tgsi_parse_token(&parse); @@ -787,6 +1056,7 @@ nvfx_fragprog_translate(struct nvfx_context *nvfx, { const struct tgsi_full_instruction *finst; + util_dynarray_append(&insns, unsigned, fp->insn_len); finst = &parse.FullToken.FullInstruction; if (!nvfx_fragprog_parse_instruction(nvfx, fpc, finst)) goto out_err; @@ -796,6 +1066,14 @@ nvfx_fragprog_translate(struct nvfx_context *nvfx, break; } } + util_dynarray_append(&insns, unsigned, fp->insn_len); + + for(unsigned i = 0; i < fpc->label_relocs.size; i += sizeof(struct nvfx_relocation)) + { + struct nvfx_relocation* label_reloc = (struct nvfx_relocation*)((char*)fpc->label_relocs.data + i); + fp->insn[label_reloc->location] |= ((unsigned*)insns.data)[label_reloc->target]; + } + util_dynarray_fini(&insns); if(!nvfx->is_nv4x) fp->fp_control |= (fpc->num_regs-1)/2; @@ -804,9 +1082,9 @@ nvfx_fragprog_translate(struct nvfx_context *nvfx, /* Terminate final instruction */ if(fp->insn) - fp->insn[fpc->inst_offset] |= 0x00000001; + fp->insn[fpc->inst_offset] |= 0x00000001; - /* Append NOP + END instruction, may or may not be necessary. */ + /* Append NOP + END instruction for branches to the end of the program */ fpc->inst_offset = fp->insn_len; grow_insns(fpc, 4); fp->insn[fpc->inst_offset + 0] = 0x00000001; @@ -814,12 +1092,48 @@ nvfx_fragprog_translate(struct nvfx_context *nvfx, fp->insn[fpc->inst_offset + 2] = 0x00000000; fp->insn[fpc->inst_offset + 3] = 0x00000000; - fp->translated = TRUE; -out_err: + if(debug_get_option_nvfx_dump_fp()) + { + debug_printf("\n"); + tgsi_dump(pfp->pipe.tokens, 0); + + debug_printf("\n%s fragment program:\n", nvfx->is_nv4x ? "nv4x" : "nv3x"); + for (unsigned i = 0; i < fp->insn_len; i += 4) + debug_printf("%3u: %08x %08x %08x %08x\n", i >> 2, fp->insn[i], fp->insn[i + 1], fp->insn[i + 2], fp->insn[i + 3]); + debug_printf("\n"); + } + + fp->prog_size = (fp->insn_len * 4 + 63) & ~63; + + if(fp->prog_size >= min_size) + fp->progs_per_bo = 1; + else + fp->progs_per_bo = min_size / fp->prog_size; + fp->bo_prog_idx = fp->progs_per_bo - 1; + +out: tgsi_parse_free(&parse); - if (fpc->r_temp) - FREE(fpc->r_temp); - FREE(fpc); + if(fpc) + { + if (fpc->r_temp) + FREE(fpc->r_temp); + util_dynarray_fini(&fpc->if_stack); + util_dynarray_fini(&fpc->label_relocs); + //util_dynarray_fini(&fpc->loop_stack); + FREE(fpc); + } + return fp; + +out_err: + _debug_printf("Error: failed to compile this fragment program:\n"); + tgsi_dump(pfp->pipe.tokens, 0); + + if(fp) + { + FREE(fp); + fp = NULL; + } + goto out; } static inline void @@ -836,53 +1150,189 @@ nvfx_fp_memcpy(void* dst, const void* src, size_t len) #endif } +/* The hardware only supports immediate constants inside the fragment program, + * and at least on nv30 doesn't support an indirect linkage table. + * + * Hence, we need to patch the fragment program itself both to update constants + * and update linkage. + * + * Using a single fragment program would entail unacceptable stalls if the GPU is + * already rendering with that fragment program. + * Thus, we instead use a "rotating queue" of buffer objects, each of which is + * packed with multiple versions of the same program. + * + * Whenever we need to patch something, we move to the next program and + * patch it. If all buffer objects are in use by the GPU, we allocate another one, + * expanding the queue. + * + * As an additional optimization, we record when all the programs have the + * current input slot configuration, and at that point we stop patching inputs. + * This happens, for instance, if a given fragment program is always used with + * the same vertex program (i.e. always with GLSL), or if the layouts match + * enough (non-GLSL). + * + * Note that instead of using multiple programs, we could push commands + * on the FIFO to patch a single program: it's not fully clear which option is + * faster, but my guess is that the current way is faster. + * + * We also track the previous slot assignments for each version and don't + * patch if they are the same (this could perhaps be removed). + */ + void nvfx_fragprog_validate(struct nvfx_context *nvfx) { struct nouveau_channel* chan = nvfx->screen->base.channel; - struct nvfx_fragment_program *fp = nvfx->fragprog; - int update = 0; - - if (!fp->translated) + struct nvfx_pipe_fragment_program *pfp = nvfx->fragprog; + struct nvfx_vertex_program* vp; + /* Gallium always puts the point coord in GENERIC[0] + * TODO: this is wrong, Gallium needs to be fixed + */ + unsigned sprite_coord_enable = nvfx->rasterizer->pipe.point_quad_rasterization * (nvfx->rasterizer->pipe.sprite_coord_enable | 1); + + boolean emulate_sprite_flipping = sprite_coord_enable && nvfx->rasterizer->pipe.sprite_coord_mode; + unsigned key = emulate_sprite_flipping; + struct nvfx_fragment_program* fp; + + fp = pfp->fps[key]; + if (!fp) { - const int min_size = 4096; + fp = nvfx_fragprog_translate(nvfx, pfp, emulate_sprite_flipping); - nvfx_fragprog_translate(nvfx, fp); - if (!fp->translated) { - static unsigned dummy[8] = {1, 0, 0, 0, 1, 0, 0, 0}; - static int warned = 0; - if(!warned) + if(!fp) + { + if(!nvfx->dummy_fs) { - fprintf(stderr, "nvfx: failed to translate fragment program!\n"); - warned = 1; + struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); + if (ureg) + { + ureg_END( ureg ); + nvfx->dummy_fs = ureg_create_shader_and_destroy( ureg, &nvfx->pipe ); + } + + if(!nvfx->dummy_fs) + { + _debug_printf("Error: unable to create a dummy fragment shader: aborting."); + abort(); + } } - /* use dummy program: we cannot fail here */ - fp->translated = TRUE; - fp->insn = malloc(sizeof(dummy)); - memcpy(fp->insn, dummy, sizeof(dummy)); - fp->insn_len = sizeof(dummy) / sizeof(dummy[0]); + fp = nvfx_fragprog_translate(nvfx, nvfx->dummy_fs, FALSE); + emulate_sprite_flipping = FALSE; + + if(!fp) + { + _debug_printf("Error: unable to compile even a dummy fragment shader: aborting."); + abort(); + } } - update = TRUE; - fp->prog_size = (fp->insn_len * 4 + 63) & ~63; + pfp->fps[key] = fp; + } + + vp = nvfx->render_mode == HW ? nvfx->vertprog : nvfx->swtnl.vertprog; - if(fp->prog_size >= min_size) - fp->progs_per_bo = 1; + if (fp->last_vp_id != vp->id || fp->last_sprite_coord_enable != sprite_coord_enable) { + int sprite_real_input = -1; + int sprite_reloc_input; + unsigned i; + fp->last_vp_id = vp->id; + fp->last_sprite_coord_enable = sprite_coord_enable; + + if(sprite_coord_enable) + { + sprite_real_input = vp->sprite_fp_input; + if(sprite_real_input < 0) + { + unsigned used_texcoords = 0; + for(unsigned i = 0; i < fp->num_slots; ++i) { + unsigned generic = fp->slot_to_generic[i]; + if(!((1 << generic) & sprite_coord_enable)) + { + unsigned char slot_mask = vp->generic_to_fp_input[generic]; + if(slot_mask >= 0xf0) + used_texcoords |= 1 << ((slot_mask & 0xf) - NVFX_FP_OP_INPUT_SRC_TC0); + } + } + + sprite_real_input = NVFX_FP_OP_INPUT_SRC_TC(__builtin_ctz(~used_texcoords)); + } + + fp->point_sprite_control |= (1 << (sprite_real_input - NVFX_FP_OP_INPUT_SRC_TC0 + 8)); + } else - fp->progs_per_bo = min_size / fp->prog_size; - fp->bo_prog_idx = fp->progs_per_bo - 1; - } + fp->point_sprite_control = 0; - /* we must update constants even on "just" fragprog changes, because - we don't check whether the current constant buffer matches the latest - one bound to this fragment program */ - if (nvfx->dirty & (NVFX_NEW_FRAGCONST | NVFX_NEW_FRAGPROG)) - update = TRUE; + if(emulate_sprite_flipping) + sprite_reloc_input = 0; + else + sprite_reloc_input = sprite_real_input; - if(update) { + for(i = 0; i < fp->num_slots; ++i) { + unsigned generic = fp->slot_to_generic[i]; + if((1 << generic) & sprite_coord_enable) + { + if(fp->slot_to_fp_input[i] != sprite_reloc_input) + goto update_slots; + } + else + { + unsigned char slot_mask = vp->generic_to_fp_input[generic]; + if((slot_mask >> 4) & (slot_mask ^ fp->slot_to_fp_input[i])) + goto update_slots; + } + } + + if(emulate_sprite_flipping) + { + if(fp->slot_to_fp_input[fp->num_slots] != sprite_real_input) + goto update_slots; + } + + if(0) + { +update_slots: + /* optimization: we start updating from the slot we found the first difference in */ + for(; i < fp->num_slots; ++i) + { + unsigned generic = fp->slot_to_generic[i]; + if((1 << generic) & sprite_coord_enable) + fp->slot_to_fp_input[i] = sprite_reloc_input; + else + fp->slot_to_fp_input[i] = vp->generic_to_fp_input[generic] & 0xf; + } + + fp->slot_to_fp_input[fp->num_slots] = sprite_real_input; + + if(nvfx->is_nv4x) + { + fp->or = 0; + for(i = 0; i <= fp->num_slots; ++i) { + unsigned fp_input = fp->slot_to_fp_input[i]; + if(fp_input == NVFX_FP_OP_INPUT_SRC_TC(8)) + fp->or |= (1 << 12); + else if(fp_input == NVFX_FP_OP_INPUT_SRC_TC(9)) + fp->or |= (1 << 13); + else if(fp_input >= NVFX_FP_OP_INPUT_SRC_TC(0) && fp_input <= NVFX_FP_OP_INPUT_SRC_TC(7)) + fp->or |= (1 << (fp_input - NVFX_FP_OP_INPUT_SRC_TC0 + 14)); + } + } + + fp->progs_left_with_obsolete_slot_assignments = fp->progs; + goto update; + } + } + + /* We must update constants even on "just" fragprog changes, because + * we don't check whether the current constant buffer matches the latest + * one bound to this fragment program. + * Doing such a check would likely be a pessimization. + */ + if ((nvfx->hw_fragprog != fp) || (nvfx->dirty & (NVFX_NEW_FRAGPROG | NVFX_NEW_FRAGCONST))) { int offset; + uint32_t* fpmap; +update: ++fp->bo_prog_idx; if(fp->bo_prog_idx >= fp->progs_per_bo) { @@ -892,10 +1342,12 @@ nvfx_fragprog_validate(struct nvfx_context *nvfx) } else { - struct nvfx_fragment_program_bo* fpbo = os_malloc_aligned(sizeof(struct nvfx_fragment_program) + fp->prog_size * fp->progs_per_bo, 16); - char *map, *buf; - int i; + struct nvfx_fragment_program_bo* fpbo = os_malloc_aligned(sizeof(struct nvfx_fragment_program) + (fp->prog_size + 8) * fp->progs_per_bo, 16); + uint8_t* map; + uint8_t* buf; + fpbo->slots = (unsigned char*)&fpbo->insn[(fp->prog_size) * fp->progs_per_bo]; + memset(fpbo->slots, 0, 8 * fp->progs_per_bo); if(fp->fpbo) { fpbo->next = fp->fpbo->next; @@ -905,12 +1357,14 @@ nvfx_fragprog_validate(struct nvfx_context *nvfx) fpbo->next = fpbo; fp->fpbo = fpbo; fpbo->bo = 0; + fp->progs += fp->progs_per_bo; + fp->progs_left_with_obsolete_slot_assignments += fp->progs_per_bo; nouveau_bo_new(nvfx->screen->base.device, NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP, 64, fp->prog_size * fp->progs_per_bo, &fpbo->bo); nouveau_bo_map(fpbo->bo, NOUVEAU_BO_NOSYNC); map = fpbo->bo->map; - buf = fpbo->insn; - for(i = 0; i < fp->progs_per_bo; ++i) + buf = (uint8_t*)fpbo->insn; + for(unsigned i = 0; i < fp->progs_per_bo; ++i) { memcpy(buf, fp->insn, fp->insn_len * 4); nvfx_fp_memcpy(map, fp->insn, fp->insn_len * 4); @@ -922,13 +1376,11 @@ nvfx_fragprog_validate(struct nvfx_context *nvfx) } offset = fp->bo_prog_idx * fp->prog_size; + fpmap = (uint32_t*)((char*)fp->fpbo->bo->map + offset); if(nvfx->constbuf[PIPE_SHADER_FRAGMENT]) { struct pipe_resource* constbuf = nvfx->constbuf[PIPE_SHADER_FRAGMENT]; - // TODO: avoid using transfers, just directly the buffer - struct pipe_transfer* transfer; - // TODO: does this check make any sense, or should we do this unconditionally? - uint32_t* map = pipe_buffer_map(&nvfx->pipe, constbuf, PIPE_TRANSFER_READ, &transfer); + uint32_t* map = (uint32_t*)nvfx_buffer(constbuf)->data; uint32_t* fpmap = (uint32_t*)((char*)fp->fpbo->bo->map + offset); uint32_t* buf = (uint32_t*)((char*)fp->fpbo->insn + offset); int i; @@ -942,12 +1394,61 @@ nvfx_fragprog_validate(struct nvfx_context *nvfx) nvfx_fp_memcpy(&fpmap[off], &map[idx], 4 * sizeof(uint32_t)); } } - pipe_buffer_unmap(&nvfx->pipe, constbuf, transfer); } - } - if(update || (nvfx->dirty & NVFX_NEW_FRAGPROG)) { - int offset = fp->bo_prog_idx * fp->prog_size; + /* we only do this if we aren't sure that all program versions have the + * current slot assignments, otherwise we just update constants for speed + */ + if(fp->progs_left_with_obsolete_slot_assignments) { + unsigned char* fpbo_slots = &fp->fpbo->slots[fp->bo_prog_idx * 8]; + /* also relocate sprite coord slot, if any */ + for(unsigned i = 0; i <= fp->num_slots; ++i) { + unsigned value = fp->slot_to_fp_input[i];; + if(value != fpbo_slots[i]) { + unsigned* p; + unsigned* begin = (unsigned*)fp->slot_relocations[i].data; + unsigned* end = (unsigned*)((char*)fp->slot_relocations[i].data + fp->slot_relocations[i].size); + //printf("fp %p reloc slot %u/%u: %u -> %u\n", fp, i, fp->num_slots, fpbo_slots[i], value); + if(value == 0) + { + /* was relocated to an input, switch type to temporary */ + for(p = begin; p != end; ++p) { + unsigned off = *p; + unsigned dw = fp->insn[off]; + dw &=~ NVFX_FP_REG_TYPE_MASK; + //printf("reloc_tmp at %x\n", off); + nvfx_fp_memcpy(&fpmap[off], &dw, sizeof(dw)); + } + } else { + if(!fpbo_slots[i]) + { + /* was relocated to a temporary, switch type to input */ + for(p= begin; p != end; ++p) { + unsigned off = *p; + unsigned dw = fp->insn[off]; + //printf("reloc_in at %x\n", off); + dw |= NVFX_FP_REG_TYPE_INPUT << NVFX_FP_REG_TYPE_SHIFT; + nvfx_fp_memcpy(&fpmap[off], &dw, sizeof(dw)); + } + } + + /* set the correct input index */ + for(p = begin; p != end; ++p) { + unsigned off = *p & ~3; + unsigned dw = fp->insn[off]; + //printf("reloc&~3 at %x\n", off); + dw = (dw & ~NVFX_FP_OP_INPUT_SRC_MASK) | (value << NVFX_FP_OP_INPUT_SRC_SHIFT); + nvfx_fp_memcpy(&fpmap[off], &dw, sizeof(dw)); + } + } + fpbo_slots[i] = value; + } + } + --fp->progs_left_with_obsolete_slot_assignments; + } + + nvfx->hw_fragprog = fp; + MARK_RING(chan, 8, 1); OUT_RING(chan, RING_3D(NV34TCL_FP_ACTIVE_PROGRAM, 1)); OUT_RELOC(chan, fp->fpbo->bo, offset, NOUVEAU_BO_VRAM | @@ -963,13 +1464,26 @@ nvfx_fragprog_validate(struct nvfx_context *nvfx) OUT_RING(chan, fp->samplers); } } + + { + unsigned pointsprite_control = fp->point_sprite_control | nvfx->rasterizer->pipe.point_quad_rasterization; + if(pointsprite_control != nvfx->hw_pointsprite_control) + { + WAIT_RING(chan, 2); + OUT_RING(chan, RING_3D(NV34TCL_POINT_SPRITE, 1)); + OUT_RING(chan, pointsprite_control); + nvfx->hw_pointsprite_control = pointsprite_control; + } + } + + nvfx->relocs_needed &=~ NVFX_RELOCATE_FRAGPROG; } void nvfx_fragprog_relocate(struct nvfx_context *nvfx) { struct nouveau_channel* chan = nvfx->screen->base.channel; - struct nvfx_fragment_program *fp = nvfx->fragprog; + struct nvfx_fragment_program *fp = nvfx->hw_fragprog; struct nouveau_bo* bo = fp->fpbo->bo; int offset = fp->bo_prog_idx * fp->prog_size; unsigned fp_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD; // TODO: GART? @@ -979,12 +1493,14 @@ nvfx_fragprog_relocate(struct nvfx_context *nvfx) OUT_RELOC(chan, bo, offset, fp_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR, NV34TCL_FP_ACTIVE_PROGRAM_DMA0, NV34TCL_FP_ACTIVE_PROGRAM_DMA1); + nvfx->relocs_needed &=~ NVFX_RELOCATE_FRAGPROG; } void nvfx_fragprog_destroy(struct nvfx_context *nvfx, struct nvfx_fragment_program *fp) { + unsigned i; struct nvfx_fragment_program_bo* fpbo = fp->fpbo; if(fpbo) { @@ -999,7 +1515,60 @@ nvfx_fragprog_destroy(struct nvfx_context *nvfx, while(fpbo != fp->fpbo); } + for(i = 0; i < Elements(fp->slot_relocations); ++i) + util_dynarray_fini(&fp->slot_relocations[i]); + if (fp->insn_len) FREE(fp->insn); } +static void * +nvfx_fp_state_create(struct pipe_context *pipe, + const struct pipe_shader_state *cso) +{ + struct nvfx_pipe_fragment_program *pfp; + + pfp = CALLOC(1, sizeof(struct nvfx_pipe_fragment_program)); + pfp->pipe.tokens = tgsi_dup_tokens(cso->tokens); + + tgsi_scan_shader(pfp->pipe.tokens, &pfp->info); + + return (void *)pfp; +} + +static void +nvfx_fp_state_bind(struct pipe_context *pipe, void *hwcso) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + + nvfx->fragprog = hwcso; + nvfx->dirty |= NVFX_NEW_FRAGPROG; +} + +static void +nvfx_fp_state_delete(struct pipe_context *pipe, void *hwcso) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + struct nvfx_pipe_fragment_program *pfp = hwcso; + unsigned i; + + for(i = 0; i < Elements(pfp->fps); ++i) + { + if(pfp->fps[i]) + { + nvfx_fragprog_destroy(nvfx, pfp->fps[i]); + FREE(pfp->fps[i]); + } + } + + FREE((void*)pfp->pipe.tokens); + FREE(pfp); +} + +void +nvfx_init_fragprog_functions(struct nvfx_context *nvfx) +{ + nvfx->pipe.create_fs_state = nvfx_fp_state_create; + nvfx->pipe.bind_fs_state = nvfx_fp_state_bind; + nvfx->pipe.delete_fs_state = nvfx_fp_state_delete; +} diff --git a/src/gallium/drivers/nvfx/nvfx_fragtex.c b/src/gallium/drivers/nvfx/nvfx_fragtex.c index 0b4a434fec..6503c7afcb 100644 --- a/src/gallium/drivers/nvfx/nvfx_fragtex.c +++ b/src/gallium/drivers/nvfx/nvfx_fragtex.c @@ -1,5 +1,177 @@ #include "nvfx_context.h" #include "nvfx_resource.h" +#include "nvfx_tex.h" + +static void * +nvfx_sampler_state_create(struct pipe_context *pipe, + const struct pipe_sampler_state *cso) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + struct nvfx_sampler_state *ps; + + ps = MALLOC(sizeof(struct nvfx_sampler_state)); + + /* on nv30, we use this as an internal flag */ + ps->fmt = cso->normalized_coords ? 0 : NV40TCL_TEX_FORMAT_RECT; + ps->en = 0; + ps->filt = nvfx_tex_filter(cso) | 0x2000; /*voodoo*/ + ps->wrap = (nvfx_tex_wrap_mode(cso->wrap_s) << NV34TCL_TX_WRAP_S_SHIFT) | + (nvfx_tex_wrap_mode(cso->wrap_t) << NV34TCL_TX_WRAP_T_SHIFT) | + (nvfx_tex_wrap_mode(cso->wrap_r) << NV34TCL_TX_WRAP_R_SHIFT); + ps->compare = FALSE; + + if(cso->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) + { + ps->wrap |= nvfx_tex_wrap_compare_mode(cso->compare_func); + ps->compare = TRUE; + } + ps->bcol = nvfx_tex_border_color(cso->border_color); + + if(nvfx->is_nv4x) + nv40_sampler_state_init(pipe, ps, cso); + else + nv30_sampler_state_init(pipe, ps, cso); + + return (void *)ps; +} + +static void +nvfx_sampler_state_delete(struct pipe_context *pipe, void *hwcso) +{ + FREE(hwcso); +} + +static void +nvfx_sampler_state_bind(struct pipe_context *pipe, unsigned nr, void **sampler) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + unsigned unit; + + for (unit = 0; unit < nr; unit++) { + nvfx->tex_sampler[unit] = sampler[unit]; + nvfx->dirty_samplers |= (1 << unit); + } + + for (unit = nr; unit < nvfx->nr_samplers; unit++) { + nvfx->tex_sampler[unit] = NULL; + nvfx->dirty_samplers |= (1 << unit); + } + + nvfx->nr_samplers = nr; + nvfx->dirty |= NVFX_NEW_SAMPLER; +} + +static struct pipe_sampler_view * +nvfx_create_sampler_view(struct pipe_context *pipe, + struct pipe_resource *pt, + const struct pipe_sampler_view *templ) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + struct nvfx_sampler_view *sv = CALLOC_STRUCT(nvfx_sampler_view); + struct nvfx_texture_format *tf = &nvfx_texture_formats[templ->format]; + unsigned txf; + + if (!sv) + return NULL; + + sv->base = *templ; + sv->base.reference.count = 1; + sv->base.texture = NULL; + pipe_resource_reference(&sv->base.texture, pt); + sv->base.context = pipe; + + txf = NV34TCL_TX_FORMAT_NO_BORDER; + + switch (pt->target) { + case PIPE_TEXTURE_CUBE: + txf |= NV34TCL_TX_FORMAT_CUBIC; + /* fall-through */ + case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: + txf |= NV34TCL_TX_FORMAT_DIMS_2D; + break; + case PIPE_TEXTURE_3D: + txf |= NV34TCL_TX_FORMAT_DIMS_3D; + break; + case PIPE_TEXTURE_1D: + txf |= NV34TCL_TX_FORMAT_DIMS_1D; + break; + default: + assert(0); + } + sv->u.init_fmt = txf; + + sv->swizzle = 0 + | (tf->src[sv->base.swizzle_r] << NV34TCL_TX_SWIZZLE_S0_Z_SHIFT) + | (tf->src[sv->base.swizzle_g] << NV34TCL_TX_SWIZZLE_S0_Y_SHIFT) + | (tf->src[sv->base.swizzle_b] << NV34TCL_TX_SWIZZLE_S0_X_SHIFT) + | (tf->src[sv->base.swizzle_a] << NV34TCL_TX_SWIZZLE_S0_W_SHIFT) + | (tf->comp[sv->base.swizzle_r] << NV34TCL_TX_SWIZZLE_S1_Z_SHIFT) + | (tf->comp[sv->base.swizzle_g] << NV34TCL_TX_SWIZZLE_S1_Y_SHIFT) + | (tf->comp[sv->base.swizzle_b] << NV34TCL_TX_SWIZZLE_S1_X_SHIFT) + | (tf->comp[sv->base.swizzle_a] << NV34TCL_TX_SWIZZLE_S1_W_SHIFT); + + sv->filt = tf->sign; + sv->wrap = tf->wrap; + sv->wrap_mask = ~0; + + if (pt->target == PIPE_TEXTURE_CUBE) + { + sv->offset = 0; + sv->npot_size = (pt->width0 << NV34TCL_TX_NPOT_SIZE_W_SHIFT) | pt->height0; + } + else + { + sv->offset = nvfx_subresource_offset(pt, 0, sv->base.first_level, 0); + sv->npot_size = (u_minify(pt->width0, sv->base.first_level) << NV34TCL_TX_NPOT_SIZE_W_SHIFT) | u_minify(pt->height0, sv->base.first_level); + + /* apparently, we need to ignore the t coordinate for 1D textures to fix piglit tex1d-2dborder */ + if(pt->target == PIPE_TEXTURE_1D) + { + sv->wrap_mask &=~ NV34TCL_TX_WRAP_T_MASK; + sv->wrap |= NV34TCL_TX_WRAP_T_REPEAT; + } + } + + if(nvfx->is_nv4x) + nv40_sampler_view_init(pipe, sv); + else + nv30_sampler_view_init(pipe, sv); + + return &sv->base; +} + +static void +nvfx_sampler_view_destroy(struct pipe_context *pipe, + struct pipe_sampler_view *view) +{ + pipe_resource_reference(&view->texture, NULL); + FREE(view); +} + +static void +nvfx_set_fragment_sampler_views(struct pipe_context *pipe, + unsigned nr, + struct pipe_sampler_view **views) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + unsigned unit; + + for (unit = 0; unit < nr; unit++) { + pipe_sampler_view_reference(&nvfx->fragment_sampler_views[unit], + views[unit]); + nvfx->dirty_samplers |= (1 << unit); + } + + for (unit = nr; unit < nvfx->nr_textures; unit++) { + pipe_sampler_view_reference(&nvfx->fragment_sampler_views[unit], + NULL); + nvfx->dirty_samplers |= (1 << unit); + } + + nvfx->nr_textures = nr; + nvfx->dirty |= NVFX_NEW_SAMPLER; +} void nvfx_fragtex_validate(struct nvfx_context *nvfx) @@ -16,6 +188,10 @@ nvfx_fragtex_validate(struct nvfx_context *nvfx) samplers &= ~(1 << unit); if(nvfx->fragment_sampler_views[unit] && nvfx->tex_sampler[unit]) { + util_dirty_surfaces_use_for_sampling(&nvfx->pipe, + &((struct nvfx_miptree*)nvfx->fragment_sampler_views[unit]->texture)->dirty_surfaces, + nvfx_surface_flush); + if(!nvfx->is_nv4x) nv30_fragtex_set(nvfx, unit); else @@ -29,6 +205,7 @@ nvfx_fragtex_validate(struct nvfx_context *nvfx) } } nvfx->dirty_samplers = 0; + nvfx->relocs_needed &=~ NVFX_RELOCATE_FRAGTEX; } void @@ -55,4 +232,128 @@ nvfx_fragtex_relocate(struct nvfx_context *nvfx) OUT_RELOC(chan, bo, nvfx->hw_txf[unit], tex_flags | NOUVEAU_BO_OR | NOUVEAU_BO_DUMMY, NV34TCL_TX_FORMAT_DMA0, NV34TCL_TX_FORMAT_DMA1); } + nvfx->relocs_needed &=~ NVFX_RELOCATE_FRAGTEX; +} + +void +nvfx_init_sampling_functions(struct nvfx_context *nvfx) +{ + nvfx->pipe.create_sampler_state = nvfx_sampler_state_create; + nvfx->pipe.bind_fragment_sampler_states = nvfx_sampler_state_bind; + nvfx->pipe.delete_sampler_state = nvfx_sampler_state_delete; + nvfx->pipe.set_fragment_sampler_views = nvfx_set_fragment_sampler_views; + nvfx->pipe.create_sampler_view = nvfx_create_sampler_view; + nvfx->pipe.sampler_view_destroy = nvfx_sampler_view_destroy; +} + +#define NV34TCL_TX_FORMAT_FORMAT_DXT1_RECT NV34TCL_TX_FORMAT_FORMAT_DXT1 +#define NV34TCL_TX_FORMAT_FORMAT_DXT3_RECT NV34TCL_TX_FORMAT_FORMAT_DXT3 +#define NV34TCL_TX_FORMAT_FORMAT_DXT5_RECT NV34TCL_TX_FORMAT_FORMAT_DXT5 + +#define NV40TCL_TEX_FORMAT_FORMAT_HILO16 NV40TCL_TEX_FORMAT_FORMAT_A16L16 + +#define NV34TCL_TX_FORMAT_FORMAT_RGBA16F 0x00004a00 +#define NV34TCL_TX_FORMAT_FORMAT_RGBA16F_RECT NV34TCL_TX_FORMAT_FORMAT_RGBA16F +#define NV34TCL_TX_FORMAT_FORMAT_RGBA32F 0x00004b00 +#define NV34TCL_TX_FORMAT_FORMAT_RGBA32F_RECT NV34TCL_TX_FORMAT_FORMAT_RGBA32F +#define NV34TCL_TX_FORMAT_FORMAT_R32F 0x00004c00 +#define NV34TCL_TX_FORMAT_FORMAT_R32F_RECT NV34TCL_TX_FORMAT_FORMAT_R32F + +// TODO: guess! +#define NV40TCL_TEX_FORMAT_FORMAT_R32F 0x00001c00 + +#define SRGB 0x00700000 + +#define __(m,tf,tfc,ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w,sign,wrap) \ +[PIPE_FORMAT_##m] = { \ + {NV34TCL_TX_FORMAT_FORMAT_##tf, \ + NV34TCL_TX_FORMAT_FORMAT_##tfc, \ + NV34TCL_TX_FORMAT_FORMAT_##tf##_RECT, \ + NV34TCL_TX_FORMAT_FORMAT_##tfc##_RECT, \ + NV40TCL_TEX_FORMAT_FORMAT_##tf, \ + NV40TCL_TEX_FORMAT_FORMAT_##tfc}, \ + sign, wrap, \ + {ts0z, ts0y, ts0x, ts0w, 0, 1}, {ts1z, ts1y, ts1x, ts1w, 0, 0} \ } + +#define _(m,tf,ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w,sign, wrap) \ + __(m,tf,tf,ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w,sign, wrap) + +/* Depth formats works by reading the depth value most significant 8/16 bits. + * We are losing precision, but nVidia loses even more by using A8R8G8B8 instead of HILO16 + * There is no 32-bit integer texture support, so other things are infeasible. + * + * TODO: is it possible to read 16 bits for Z16? A16 doesn't seem to work, either due to normalization or endianness issues + */ + +#define T 2 + +#define X 3 +#define Y 2 +#define Z 1 +#define W 0 + +#define SNORM ((NV34TCL_TX_FILTER_SIGNED_RED) | (NV34TCL_TX_FILTER_SIGNED_GREEN) | (NV34TCL_TX_FILTER_SIGNED_BLUE) | (NV34TCL_TX_FILTER_SIGNED_ALPHA)) +#define UNORM 0 + +struct nvfx_texture_format +nvfx_texture_formats[PIPE_FORMAT_COUNT] = { + [0 ... PIPE_FORMAT_COUNT - 1] = {{-1, -1, -1, -1, -1, -1}}, + _(B8G8R8X8_UNORM, A8R8G8B8, T, T, T, 1, X, Y, Z, W, UNORM, 0), + _(B8G8R8X8_SRGB, A8R8G8B8, T, T, T, 1, X, Y, Z, W, UNORM, SRGB), + _(B8G8R8A8_UNORM, A8R8G8B8, T, T, T, T, X, Y, Z, W, UNORM, 0), + _(B8G8R8A8_SRGB, A8R8G8B8, T, T, T, T, X, Y, Z, W, UNORM, SRGB), + + _(R8G8B8A8_UNORM, A8R8G8B8, T, T, T, T, Z, Y, X, W, UNORM, 0), + _(R8G8B8A8_SRGB, A8R8G8B8, T, T, T, T, Z, Y, X, W, UNORM, SRGB), + _(R8G8B8X8_UNORM, A8R8G8B8, T, T, T, 1, Z, Y, X, W, UNORM, 0), + + _(A8R8G8B8_UNORM, A8R8G8B8, T, T, T, T, W, Z, Y, X, UNORM, 0), + _(A8R8G8B8_SRGB, A8R8G8B8, T, T, T, T, W, Z, Y, X, UNORM, SRGB), + _(A8B8G8R8_UNORM, A8R8G8B8, T, T, T, T, W, X, Y, Z, UNORM, 0), + _(A8B8G8R8_SRGB, A8R8G8B8, T, T, T, T, W, X, Y, Z, UNORM, SRGB), + _(X8R8G8B8_UNORM, A8R8G8B8, T, T, T, 1, W, Z, Y, X, UNORM, 0), + _(X8R8G8B8_SRGB, A8R8G8B8, T, T, T, 1, W, Z, Y, X, UNORM, SRGB), + + _(B5G5R5A1_UNORM, A1R5G5B5, T, T, T, T, X, Y, Z, W, UNORM, 0), + _(B5G5R5X1_UNORM, A1R5G5B5, T, T, T, 1, X, Y, Z, W, UNORM, 0), + + _(B4G4R4A4_UNORM, A4R4G4B4, T, T, T, T, X, Y, Z, W, UNORM, 0), + _(B4G4R4X4_UNORM, A4R4G4B4, T, T, T, 1, X, Y, Z, W, UNORM, 0), + + _(B5G6R5_UNORM, R5G6B5, T, T, T, 1, X, Y, Z, W, UNORM, 0), + + _(R8_UNORM, L8, T, 0, 0, 1, X, X, X, X, UNORM, 0), + _(R8_SNORM, L8, T, 0, 0, 1, X, X, X, X, SNORM, 0), + _(L8_UNORM, L8, T, T, T, 1, X, X, X, X, UNORM, 0), + _(L8_SRGB, L8, T, T, T, 1, X, X, X, X, UNORM, SRGB), + _(A8_UNORM, L8, 0, 0, 0, T, X, X, X, X, UNORM, 0), + _(I8_UNORM, L8, T, T, T, T, X, X, X, X, UNORM, 0), + + _(R8G8_UNORM, A8L8, T, T, T, T, X, X, X, W, UNORM, 0), + _(R8G8_SNORM, A8L8, T, T, T, T, X, X, X, W, SNORM, 0), + _(L8A8_UNORM, A8L8, T, T, T, T, X, X, X, W, UNORM, 0), + _(L8A8_SRGB, A8L8, T, T, T, T, X, X, X, W, UNORM, SRGB), + + _(DXT1_RGB, DXT1, T, T, T, 1, X, Y, Z, W, UNORM, 0), + _(DXT1_SRGB, DXT1, T, T, T, 1, X, Y, Z, W, UNORM, SRGB), + _(DXT1_RGBA, DXT1, T, T, T, T, X, Y, Z, W, UNORM, 0), + _(DXT1_SRGBA, DXT1, T, T, T, T, X, Y, Z, W, UNORM, SRGB), + _(DXT3_RGBA, DXT3, T, T, T, T, X, Y, Z, W, UNORM, 0), + _(DXT3_SRGBA, DXT3, T, T, T, T, X, Y, Z, W, UNORM, SRGB), + _(DXT5_RGBA, DXT5, T, T, T, T, X, Y, Z, W, UNORM, 0), + _(DXT5_SRGBA, DXT5, T, T, T, T, X, Y, Z, W, UNORM, SRGB), + + __(Z16_UNORM, A8L8, Z16, T, T, T, 1, W, W, W, W, UNORM, 0), + __(S8_USCALED_Z24_UNORM,HILO16,Z24, T, T, T, 1, W, W, W, W, UNORM, 0), + __(X8Z24_UNORM, HILO16,Z24, T, T, T, 1, W, W, W, W, UNORM, 0), + + _(R16_UNORM, A16, T, 0, 0, 1, X, X, X, X, UNORM, 0), + _(R16_SNORM, A16, T, 0, 0, 1, X, X, X, X, SNORM, 0), + _(R16G16_UNORM, HILO16, T, T, 0, 1, X, Y, X, X, UNORM, 0), + _(R16G16_SNORM, HILO16, T, T, 0, 1, X, Y, X, X, SNORM, 0), + + _(R16G16B16A16_FLOAT, RGBA16F, T, T, T, T, X, Y, Z, W, UNORM, 0), + _(R32G32B32A32_FLOAT, RGBA32F, T, T, T, T, X, Y, Z, W, UNORM, 0), + _(R32_FLOAT, R32F, T, 0, 0, 1, X, X, X, X, UNORM, 0) +}; diff --git a/src/gallium/drivers/nvfx/nvfx_miptree.c b/src/gallium/drivers/nvfx/nvfx_miptree.c index b5639bb464..0916aaa828 100644 --- a/src/gallium/drivers/nvfx/nvfx_miptree.c +++ b/src/gallium/drivers/nvfx/nvfx_miptree.c @@ -2,309 +2,220 @@ #include "pipe/p_defines.h" #include "util/u_inlines.h" #include "util/u_format.h" +#include "util/u_memory.h" #include "util/u_math.h" - -#include "nvfx_context.h" +#include "util/u_staging.h" +#include "state_tracker/drm_driver.h" +#include "nouveau/nouveau_winsys.h" +#include "nouveau/nouveau_screen.h" +#include "nvfx_screen.h" #include "nvfx_resource.h" -#include "nvfx_transfer.h" -#include "nv04_surface_2d.h" - -/* Currently using separate implementations for buffers and textures, - * even though gallium has a unified abstraction of these objects. - * Eventually these should be combined, and mechanisms like transfers - * be adapted to work for both buffer and texture uploads. - */ static void -nvfx_miptree_layout(struct nvfx_miptree *mt) +nvfx_miptree_choose_format(struct nvfx_miptree *mt) { struct pipe_resource *pt = &mt->base.base; - uint width = pt->width0; - uint offset = 0; - int nr_faces, l, f; - uint wide_pitch = pt->bind & (PIPE_BIND_SAMPLER_VIEW | - PIPE_BIND_DEPTH_STENCIL | - PIPE_BIND_RENDER_TARGET | - PIPE_BIND_DISPLAY_TARGET | - PIPE_BIND_SCANOUT); - - if (pt->target == PIPE_TEXTURE_CUBE) { - nr_faces = 6; - } else - if (pt->target == PIPE_TEXTURE_3D) { - nr_faces = pt->depth0; - } else { - nr_faces = 1; + unsigned uniform_pitch = 0; + static int no_swizzle = -1; + if(no_swizzle < 0) + no_swizzle = debug_get_bool_option("NV40_NO_SWIZZLE", FALSE); /* this will break things on nv30 */ + + if (!util_is_power_of_two(pt->width0) || + !util_is_power_of_two(pt->height0) || + !util_is_power_of_two(pt->depth0) || + (!nvfx_screen(pt->screen)->is_nv4x && pt->target == PIPE_TEXTURE_RECT) + ) + uniform_pitch = 1; + + if ( + (pt->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET)) + || (pt->usage & PIPE_USAGE_DYNAMIC) || (pt->usage & PIPE_USAGE_STAGING) + || util_format_is_compressed(pt->format) + || no_swizzle + ) + mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; + + /* non compressed formats with uniform pitch must be linear, and vice versa */ + if(!util_format_is_s3tc(pt->format) + && (uniform_pitch || mt->base.base.flags & NVFX_RESOURCE_FLAG_LINEAR)) + { + mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; + uniform_pitch = 1; } - for (l = 0; l <= pt->last_level; l++) { - if (wide_pitch && (pt->flags & NVFX_RESOURCE_FLAG_LINEAR)) - mt->level[l].pitch = align(util_format_get_stride(pt->format, pt->width0), 64); - else - mt->level[l].pitch = util_format_get_stride(pt->format, width); + if(uniform_pitch) + { + mt->linear_pitch = util_format_get_stride(pt->format, pt->width0); - mt->level[l].image_offset = - CALLOC(nr_faces, sizeof(unsigned)); + // TODO: this is only a constraint for rendering and not sampling, apparently + // we may also want this unconditionally + if(pt->bind & (PIPE_BIND_SAMPLER_VIEW | + PIPE_BIND_DEPTH_STENCIL | + PIPE_BIND_RENDER_TARGET | + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SCANOUT)) + mt->linear_pitch = align(mt->linear_pitch, 64); + } + else + mt->linear_pitch = 0; +} + +static unsigned +nvfx_miptree_layout(struct nvfx_miptree *mt) +{ + struct pipe_resource* pt = &mt->base.base; + uint offset = 0; - width = u_minify(width, 1); + if(!nvfx_screen(pt->screen)->is_nv4x) + { + assert(pt->target == PIPE_TEXTURE_RECT + || (util_is_power_of_two(pt->width0) && util_is_power_of_two(pt->height0))); } - for (f = 0; f < nr_faces; f++) { - for (l = 0; l < pt->last_level; l++) { - mt->level[l].image_offset[f] = offset; + for (unsigned l = 0; l <= pt->last_level; l++) + { + unsigned size; + mt->level_offset[l] = offset; - if (!(pt->flags & NVFX_RESOURCE_FLAG_LINEAR) && - u_minify(pt->width0, l + 1) > 1 && u_minify(pt->height0, l + 1) > 1) - offset += align(mt->level[l].pitch * u_minify(pt->height0, l), 64); - else - offset += mt->level[l].pitch * u_minify(pt->height0, l); - } + if(mt->linear_pitch) + size = mt->linear_pitch; + else + size = util_format_get_stride(pt->format, u_minify(pt->width0, l)); + size = util_format_get_2d_size(pt->format, size, u_minify(pt->height0, l)); - mt->level[l].image_offset[f] = offset; - offset += mt->level[l].pitch * u_minify(pt->height0, l); + if(pt->target == PIPE_TEXTURE_3D) + size *= u_minify(pt->depth0, l); + + offset += size; } - mt->total_size = offset; + offset = align(offset, 128); + mt->face_size = offset; + if(mt->base.base.target == PIPE_TEXTURE_CUBE) + offset += 5 * mt->face_size; + return offset; } -static boolean -nvfx_miptree_get_handle(struct pipe_screen *pscreen, - struct pipe_resource *ptexture, - struct winsys_handle *whandle) +static void +nvfx_miptree_surface_final_destroy(struct pipe_surface* ps) { - struct nvfx_miptree* mt = (struct nvfx_miptree*)ptexture; - - if (!mt || !mt->base.bo) - return FALSE; - - return nouveau_screen_bo_get_handle(pscreen, - mt->base.bo, - mt->level[0].pitch, - whandle); + struct nvfx_surface* ns = (struct nvfx_surface*)ps; + pipe_resource_reference(&ps->texture, 0); + pipe_resource_reference((struct pipe_resource**)&ns->temp, 0); + FREE(ps); } - -static void +void nvfx_miptree_destroy(struct pipe_screen *screen, struct pipe_resource *pt) { struct nvfx_miptree *mt = (struct nvfx_miptree *)pt; - int l; - + util_surfaces_destroy(&mt->surfaces, pt, nvfx_miptree_surface_final_destroy); nouveau_screen_bo_release(screen, mt->base.bo); - - for (l = 0; l <= pt->last_level; l++) { - if (mt->level[l].image_offset) - FREE(mt->level[l].image_offset); - } - FREE(mt); } - - - -struct u_resource_vtbl nvfx_miptree_vtbl = +static struct nvfx_miptree* +nvfx_miptree_create_skeleton(struct pipe_screen *pscreen, const struct pipe_resource *pt) { - nvfx_miptree_get_handle, /* get_handle */ - nvfx_miptree_destroy, /* resource_destroy */ - NULL, /* is_resource_referenced */ - nvfx_miptree_transfer_new, /* get_transfer */ - nvfx_miptree_transfer_del, /* transfer_destroy */ - nvfx_miptree_transfer_map, /* transfer_map */ - u_default_transfer_flush_region, /* transfer_flush_region */ - nvfx_miptree_transfer_unmap, /* transfer_unmap */ - u_default_transfer_inline_write /* transfer_inline_write */ -}; + struct nvfx_miptree *mt; + if(pt->width0 > 4096 || pt->height0 > 4096) + return NULL; + mt = CALLOC_STRUCT(nvfx_miptree); + if (!mt) + return NULL; -struct pipe_resource * -nvfx_miptree_create(struct pipe_screen *pscreen, const struct pipe_resource *pt) -{ - struct nvfx_miptree *mt; - static int no_swizzle = -1; - if(no_swizzle < 0) - no_swizzle = debug_get_bool_option("NOUVEAU_NO_SWIZZLE", FALSE); - - mt = CALLOC_STRUCT(nvfx_miptree); - if (!mt) - return NULL; - - mt->base.base = *pt; - mt->base.vtbl = &nvfx_miptree_vtbl; - pipe_reference_init(&mt->base.base.reference, 1); - mt->base.base.screen = pscreen; + mt->base.base = *pt; + util_dirty_surfaces_init(&mt->dirty_surfaces); - /* Swizzled textures must be POT */ - if (pt->width0 & (pt->width0 - 1) || - pt->height0 & (pt->height0 - 1)) - mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; - else - if (pt->bind & (PIPE_BIND_SCANOUT | - PIPE_BIND_DISPLAY_TARGET | - PIPE_BIND_DEPTH_STENCIL)) - mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; - else - if (pt->usage == PIPE_USAGE_DYNAMIC) - mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; - else { - switch (pt->format) { - case PIPE_FORMAT_B5G6R5_UNORM: - case PIPE_FORMAT_L8A8_UNORM: - case PIPE_FORMAT_A8_UNORM: - case PIPE_FORMAT_L8_UNORM: - case PIPE_FORMAT_I8_UNORM: - /* TODO: we can actually swizzle these formats on nv40, we - are just preserving the pre-unification behavior. - The whole 2D code is going to be rewritten anyway. */ - if(nvfx_screen(pscreen)->is_nv4x) { - mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; - break; - } - /* TODO: Figure out which formats can be swizzled */ - case PIPE_FORMAT_B8G8R8A8_UNORM: - case PIPE_FORMAT_B8G8R8X8_UNORM: - case PIPE_FORMAT_R16_SNORM: - { - if (no_swizzle) - mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; - break; - } - default: - mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; - } - } + pipe_reference_init(&mt->base.base.reference, 1); + mt->base.base.screen = pscreen; - /* apparently we can't render to swizzled surfaces smaller than 64 bytes, so make them linear. - * If the user did not ask for a render target, they can still render to it, but it will cost them an extra copy. - * This also happens for small mipmaps of large textures. */ - if (pt->bind & PIPE_BIND_RENDER_TARGET && - util_format_get_stride(pt->format, pt->width0) < 64) - mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; + // set this to the actual capabilities, we use it to decide whether to use the 3D engine for copies + // TODO: is this the correct way to use Gallium? + mt->base.base.bind = pt->bind | PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DEPTH_STENCIL; - nvfx_miptree_layout(mt); + // on our current driver (and the driver too), format support does not depend on geometry, so don't bother computing it + // TODO: may want to revisit this + if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_RENDER_TARGET, 0)) + mt->base.base.bind &=~ PIPE_BIND_RENDER_TARGET; + if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_SAMPLER_VIEW, 0)) + mt->base.base.bind &=~ PIPE_BIND_SAMPLER_VIEW; + if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_DEPTH_STENCIL, 0)) + mt->base.base.bind &=~ PIPE_BIND_DEPTH_STENCIL; - mt->base.bo = nouveau_screen_bo_new(pscreen, 256, - pt->usage, pt->bind, mt->total_size); - if (!mt->base.bo) { - FREE(mt); - return NULL; - } - return &mt->base.base; + return mt; } - - struct pipe_resource * -nvfx_miptree_from_handle(struct pipe_screen *pscreen, - const struct pipe_resource *template, - struct winsys_handle *whandle) +nvfx_miptree_create(struct pipe_screen *pscreen, const struct pipe_resource *pt) { - struct nvfx_miptree *mt; - unsigned stride; + struct nvfx_miptree* mt = nvfx_miptree_create_skeleton(pscreen, pt); + unsigned size; + nvfx_miptree_choose_format(mt); - /* Only supports 2D, non-mipmapped textures for the moment */ - if (template->target != PIPE_TEXTURE_2D || - template->last_level != 0 || - template->depth0 != 1) - return NULL; + size = nvfx_miptree_layout(mt); - mt = CALLOC_STRUCT(nvfx_miptree); - if (!mt) - return NULL; + mt->base.bo = nouveau_screen_bo_new(pscreen, 256, pt->usage, pt->bind, size); - mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride); - if (mt->base.bo == NULL) { + if (!mt->base.bo) { FREE(mt); return NULL; } - - mt->base.base = *template; - mt->base.vtbl = &nvfx_miptree_vtbl; - pipe_reference_init(&mt->base.base.reference, 1); - mt->base.base.screen = pscreen; - mt->level[0].pitch = stride; - mt->level[0].image_offset = CALLOC(1, sizeof(unsigned)); - - /* Assume whoever created this buffer expects it to be linear for now */ - mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; - - /* XXX: Need to adjust bo refcount?? - */ - /* nouveau_bo_ref(bo, &mt->base.bo); */ return &mt->base.base; } +// TODO: redo this, just calling miptree_layout +struct pipe_resource * +nvfx_miptree_from_handle(struct pipe_screen *pscreen, const struct pipe_resource *template, struct winsys_handle *whandle) +{ + struct nvfx_miptree* mt = nvfx_miptree_create_skeleton(pscreen, template); + unsigned stride; + if(whandle->stride) { + mt->linear_pitch = whandle->stride; + mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR; + } else + nvfx_miptree_choose_format(mt); + nvfx_miptree_layout(mt); + mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride); + if (mt->base.bo == NULL) { + FREE(mt); + return NULL; + } + return &mt->base.base; +} - -/* Surface helpers, not strictly required to implement the resource vtbl: - */ struct pipe_surface * nvfx_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_resource *pt, unsigned face, unsigned level, unsigned zslice, unsigned flags) { - struct nvfx_miptree *mt = (struct nvfx_miptree *)pt; - struct nv04_surface *ns; - - ns = CALLOC_STRUCT(nv04_surface); - if (!ns) - return NULL; - pipe_resource_reference(&ns->base.texture, pt); - ns->base.format = pt->format; - ns->base.width = u_minify(pt->width0, level); - ns->base.height = u_minify(pt->height0, level); - ns->base.usage = flags; - pipe_reference_init(&ns->base.reference, 1); - ns->base.face = face; - ns->base.level = level; - ns->base.zslice = zslice; - ns->pitch = mt->level[level].pitch; - - if (pt->target == PIPE_TEXTURE_CUBE) { - ns->base.offset = mt->level[level].image_offset[face]; - } else - if (pt->target == PIPE_TEXTURE_3D) { - ns->base.offset = mt->level[level].image_offset[zslice]; - } else { - ns->base.offset = mt->level[level].image_offset[0]; - } - - /* create a linear temporary that we can render into if - * necessary. - * - * Note that ns->pitch is always a multiple of 64 for linear - * surfaces and swizzled surfaces are POT, so ns->pitch & 63 - * is equivalent to (ns->pitch < 64 && swizzled) - */ - - if ((ns->pitch & 63) && - (ns->base.usage & PIPE_BIND_RENDER_TARGET)) - { - struct nv04_surface_2d* eng2d = - ((struct nvfx_screen*)pscreen)->eng2d; - - ns = nv04_surface_wrap_for_render(pscreen, eng2d, ns); + struct nvfx_miptree* mt = (struct nvfx_miptree*)pt; + struct nvfx_surface *ns; + + ns = (struct nvfx_surface*)util_surfaces_get(&mt->surfaces, sizeof(struct nvfx_surface), pscreen, pt, face, level, zslice, flags); + if(ns->base.base.offset == ~0) { + util_dirty_surface_init(&ns->base); + ns->pitch = nvfx_subresource_pitch(pt, level); + ns->base.base.offset = nvfx_subresource_offset(pt, face, level, zslice); } - return &ns->base; + return &ns->base.base; } void nvfx_miptree_surface_del(struct pipe_surface *ps) { - struct nv04_surface* ns = (struct nv04_surface*)ps; - if(ns->backing) + struct nvfx_surface* ns = (struct nvfx_surface*)ps; + + if(!ns->temp) { - struct nvfx_screen* screen = (struct nvfx_screen*)ps->texture->screen; - if(1 /*ns->backing->base.usage & PIPE_BIND_BLIT_DESTINATION*/) - screen->eng2d->copy(screen->eng2d, &ns->backing->base, 0, 0, ps, 0, 0, ns->base.width, ns->base.height); - nvfx_miptree_surface_del(&ns->backing->base); + util_surfaces_detach(&((struct nvfx_miptree*)ps->texture)->surfaces, ps); + pipe_resource_reference(&ps->texture, 0); + FREE(ps); } - - pipe_resource_reference(&ps->texture, NULL); - FREE(ps); } diff --git a/src/gallium/drivers/nvfx/nvfx_push.c b/src/gallium/drivers/nvfx/nvfx_push.c new file mode 100644 index 0000000000..ffe7e98357 --- /dev/null +++ b/src/gallium/drivers/nvfx/nvfx_push.c @@ -0,0 +1,414 @@ +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "util/u_inlines.h" +#include "util/u_format.h" +#include "util/u_split_prim.h" +#include "translate/translate.h" + +#include "nvfx_context.h" +#include "nvfx_resource.h" + +struct push_context { + struct nouveau_channel* chan; + + void *idxbuf; + int32_t idxbias; + + float edgeflag; + int edgeflag_attr; + + unsigned vertex_length; + unsigned max_vertices_per_packet; + + struct translate* translate; +}; + +static void +emit_edgeflag(void *priv, boolean enabled) +{ + struct push_context* ctx = priv; + struct nouveau_channel *chan = ctx->chan; + + OUT_RING(chan, RING_3D(NV34TCL_EDGEFLAG_ENABLE, 1)); + OUT_RING(chan, enabled ? 1 : 0); +} + +static void +emit_vertices_lookup8(void *priv, unsigned start, unsigned count) +{ + struct push_context *ctx = priv; + uint8_t* elts = (uint8_t*)ctx->idxbuf + start; + + while(count) + { + unsigned push = MIN2(count, ctx->max_vertices_per_packet); + unsigned length = push * ctx->vertex_length; + + OUT_RING(ctx->chan, RING_3D_NI(NV34TCL_VERTEX_DATA, length)); + ctx->translate->run_elts8(ctx->translate, elts, push, 0, ctx->chan->cur); + ctx->chan->cur += length; + + count -= push; + elts += push; + } +} + +static void +emit_vertices_lookup16(void *priv, unsigned start, unsigned count) +{ + struct push_context *ctx = priv; + uint16_t* elts = (uint16_t*)ctx->idxbuf + start; + + while(count) + { + unsigned push = MIN2(count, ctx->max_vertices_per_packet); + unsigned length = push * ctx->vertex_length; + + OUT_RING(ctx->chan, RING_3D_NI(NV34TCL_VERTEX_DATA, length)); + ctx->translate->run_elts16(ctx->translate, elts, push, 0, ctx->chan->cur); + ctx->chan->cur += length; + + count -= push; + elts += push; + } +} + +static void +emit_vertices_lookup32(void *priv, unsigned start, unsigned count) +{ + struct push_context *ctx = priv; + uint32_t* elts = (uint32_t*)ctx->idxbuf + start; + + while(count) + { + unsigned push = MIN2(count, ctx->max_vertices_per_packet); + unsigned length = push * ctx->vertex_length; + + OUT_RING(ctx->chan, RING_3D_NI(NV34TCL_VERTEX_DATA, length)); + ctx->translate->run_elts(ctx->translate, elts, push, 0, ctx->chan->cur); + ctx->chan->cur += length; + + count -= push; + elts += push; + } +} + +static void +emit_vertices(void *priv, unsigned start, unsigned count) +{ + struct push_context *ctx = priv; + + while(count) + { + unsigned push = MIN2(count, ctx->max_vertices_per_packet); + unsigned length = push * ctx->vertex_length; + + OUT_RING(ctx->chan, RING_3D_NI(NV34TCL_VERTEX_DATA, length)); + ctx->translate->run(ctx->translate, start, push, 0, ctx->chan->cur); + ctx->chan->cur += length; + + count -= push; + start += push; + } +} + +static void +emit_ranges(void* priv, unsigned start, unsigned vc, unsigned reg) +{ + struct push_context* ctx = priv; + struct nouveau_channel *chan = ctx->chan; + unsigned nr = (vc & 0xff); + if (nr) { + OUT_RING(chan, RING_3D(reg, 1)); + OUT_RING (chan, ((nr - 1) << 24) | start); + start += nr; + } + + nr = vc >> 8; + while (nr) { + unsigned push = nr > 2047 ? 2047 : nr; + + nr -= push; + + OUT_RING(chan, RING_3D_NI(reg, push)); + while (push--) { + OUT_RING(chan, ((0x100 - 1) << 24) | start); + start += 0x100; + } + } +} + +static void +emit_ib_ranges(void* priv, unsigned start, unsigned vc) +{ + emit_ranges(priv, start, vc, NV34TCL_VB_INDEX_BATCH); +} + +static void +emit_vb_ranges(void* priv, unsigned start, unsigned vc) +{ + emit_ranges(priv, start, vc, NV34TCL_VB_VERTEX_BATCH); +} + +static INLINE void +emit_elt8(void* priv, unsigned start, unsigned vc) +{ + struct push_context* ctx = priv; + struct nouveau_channel *chan = ctx->chan; + uint8_t *elts = (uint8_t *)ctx->idxbuf + start; + int idxbias = ctx->idxbias; + + if (vc & 1) { + OUT_RING(chan, RING_3D(NV34TCL_VB_ELEMENT_U32, 1)); + OUT_RING (chan, elts[0]); + elts++; vc--; + } + + while (vc) { + unsigned i; + unsigned push = MIN2(vc, 2047 * 2); + + OUT_RING(chan, RING_3D_NI(NV34TCL_VB_ELEMENT_U16, push >> 1)); + for (i = 0; i < push; i+=2) + OUT_RING(chan, ((elts[i+1] + idxbias) << 16) | (elts[i] + idxbias)); + + vc -= push; + elts += push; + } +} + +static INLINE void +emit_elt16(void* priv, unsigned start, unsigned vc) +{ + struct push_context* ctx = priv; + struct nouveau_channel *chan = ctx->chan; + uint16_t *elts = (uint16_t *)ctx->idxbuf + start; + int idxbias = ctx->idxbias; + + if (vc & 1) { + OUT_RING(chan, RING_3D(NV34TCL_VB_ELEMENT_U32, 1)); + OUT_RING (chan, elts[0]); + elts++; vc--; + } + + while (vc) { + unsigned i; + unsigned push = MIN2(vc, 2047 * 2); + + OUT_RING(chan, RING_3D_NI(NV34TCL_VB_ELEMENT_U16, push >> 1)); + for (i = 0; i < push; i+=2) + OUT_RING(chan, ((elts[i+1] + idxbias) << 16) | (elts[i] + idxbias)); + + vc -= push; + elts += push; + } +} + +static INLINE void +emit_elt32(void* priv, unsigned start, unsigned vc) +{ + struct push_context* ctx = priv; + struct nouveau_channel *chan = ctx->chan; + uint32_t *elts = (uint32_t *)ctx->idxbuf + start; + int idxbias = ctx->idxbias; + + while (vc) { + unsigned push = MIN2(vc, 2047); + + OUT_RING(chan, RING_3D_NI(NV34TCL_VB_ELEMENT_U32, push)); + assert(AVAIL_RING(chan) >= push); + if(idxbias) + { + for(unsigned i = 0; i < push; ++i) + OUT_RING(chan, elts[i] + idxbias); + } + else + OUT_RINGp(chan, elts, push); + + vc -= push; + elts += push; + } +} + +void +nvfx_push_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + struct nouveau_channel *chan = nvfx->screen->base.channel; + struct push_context ctx; + struct util_split_prim s; + unsigned instances_left = info->instance_count; + int vtx_value; + unsigned hw_mode = nvgl_primitive(info->mode); + int i; + struct + { + uint8_t* map; + unsigned step; + } per_instance[16]; + unsigned p_overhead = 64 /* magic fix */ + + 4 /* begin/end */ + + 4; /* potential edgeflag enable/disable */ + + ctx.chan = nvfx->screen->base.channel; + ctx.translate = nvfx->vtxelt->translate; + ctx.idxbuf = NULL; + ctx.vertex_length = nvfx->vtxelt->vertex_length; + ctx.max_vertices_per_packet = nvfx->vtxelt->max_vertices_per_packet; + ctx.edgeflag = 0.5f; + // TODO: figure out if we really want to handle this, and do so in that case + ctx.edgeflag_attr = 0xff; // nvfx->vertprog->cfg.edgeflag_in; + + if(!nvfx->use_vertex_buffers) + { + for(i = 0; i < nvfx->vtxelt->num_per_vertex_buffer_infos; ++i) + { + struct nvfx_per_vertex_buffer_info* vbi = &nvfx->vtxelt->per_vertex_buffer_info[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[vbi->vertex_buffer_index]; + uint8_t* data = nvfx_buffer(vb->buffer)->data + vb->buffer_offset; + if(info->indexed) + data += info->index_bias * vb->stride; + ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0); + } + + if(ctx.edgeflag_attr < 16) + vtx_value = -(ctx.vertex_length + 3); /* vertex data and edgeflag header and value */ + else + { + p_overhead += 1; /* initial vertex_data header */ + vtx_value = -ctx.vertex_length; /* vertex data and edgeflag header and value */ + } + + if (info->indexed) { + // XXX: this case and is broken and probably need a new VTX_ATTR push path + if (nvfx->idxbuf.index_size == 1) + s.emit = emit_vertices_lookup8; + else if (nvfx->idxbuf.index_size == 2) + s.emit = emit_vertices_lookup16; + else + s.emit = emit_vertices_lookup32; + } else + s.emit = emit_vertices; + } + else + { + if(!info->indexed || nvfx->use_index_buffer) + { + s.emit = info->indexed ? emit_ib_ranges : emit_vb_ranges; + p_overhead += 3; + vtx_value = 0; + } + else if (nvfx->idxbuf.index_size == 4) + { + s.emit = emit_elt32; + p_overhead += 1; + vtx_value = 8; + } + else + { + s.emit = (nvfx->idxbuf.index_size == 2) ? emit_elt16 : emit_elt8; + p_overhead += 3; + vtx_value = 7; + } + } + + ctx.idxbias = info->index_bias; + if(nvfx->use_vertex_buffers) + ctx.idxbias -= nvfx->base_vertex; + + /* map index buffer, if present */ + if (info->indexed && !nvfx->use_index_buffer) + ctx.idxbuf = nvfx_buffer(nvfx->idxbuf.buffer)->data + nvfx->idxbuf.offset; + + s.priv = &ctx; + s.edge = emit_edgeflag; + + for (i = 0; i < nvfx->vtxelt->num_per_instance; ++i) + { + struct nvfx_per_instance_element *ve = &nvfx->vtxelt->per_instance[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->base.vertex_buffer_index]; + float v[4]; + per_instance[i].step = info->start_instance % ve->instance_divisor; + per_instance[i].map = nvfx_buffer(vb->buffer)->data + vb->buffer_offset + ve->base.src_offset; + + nvfx->vtxelt->per_instance[i].base.fetch_rgba_float(v, per_instance[i].map, 0, 0); + + WAIT_RING(chan, 5); + nvfx_emit_vtx_attr(chan, nvfx->vtxelt->per_instance[i].base.idx, v, nvfx->vtxelt->per_instance[i].base.ncomp); + } + + /* per-instance loop */ + while (instances_left--) { + int max_verts; + boolean done; + + util_split_prim_init(&s, info->mode, info->start, info->count); + nvfx_state_emit(nvfx); + for(;;) { + max_verts = AVAIL_RING(chan); + max_verts -= p_overhead; + + /* if vtx_value < 0, each vertex is -vtx_value words long + * otherwise, each vertex is 2^(vtx_value) / 255 words long (this is an approximation) + */ + if(vtx_value < 0) + { + max_verts /= -vtx_value; + max_verts -= (max_verts >> 10); /* vertex data headers */ + } + else + { + if(max_verts >= (1 << 23)) /* avoid overflow here */ + max_verts = (1 << 23); + max_verts = (max_verts * 255) >> vtx_value; + } + + //printf("avail %u max_verts %u\n", AVAIL_RING(chan), max_verts); + + if(max_verts >= 16) + { + /* XXX: any command a lot of times seems to (mostly) fix corruption that would otherwise happen */ + /* this seems to cause issues on nv3x, and also be unneeded there */ + if(nvfx->is_nv4x) + { + int i; + for(i = 0; i < 32; ++i) + { + OUT_RING(chan, RING_3D(0x1dac, 1)); + OUT_RING(chan, 0); + } + } + + OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); + OUT_RING(chan, hw_mode); + done = util_split_prim_next(&s, max_verts); + OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); + OUT_RING(chan, 0); + + if(done) + break; + } + + FIRE_RING(chan); + nvfx_state_emit(nvfx); + } + + /* set data for the next instance, if any changed */ + for (i = 0; i < nvfx->vtxelt->num_per_instance; ++i) + { + struct nvfx_per_instance_element *ve = &nvfx->vtxelt->per_instance[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->base.vertex_buffer_index]; + + if(++per_instance[i].step == ve->instance_divisor) + { + float v[4]; + per_instance[i].map += vb->stride; + per_instance[i].step = 0; + + nvfx->vtxelt->per_instance[i].base.fetch_rgba_float(v, per_instance[i].map, 0, 0); + WAIT_RING(chan, 5); + nvfx_emit_vtx_attr(chan, nvfx->vtxelt->per_instance[i].base.idx, v, nvfx->vtxelt->per_instance[i].base.ncomp); + } + } + } +} diff --git a/src/gallium/drivers/nvfx/nvfx_resource.c b/src/gallium/drivers/nvfx/nvfx_resource.c index 10cdeed2a3..39ae893f1b 100644 --- a/src/gallium/drivers/nvfx/nvfx_resource.c +++ b/src/gallium/drivers/nvfx/nvfx_resource.c @@ -1,23 +1,15 @@ #include "pipe/p_context.h" +#include "util/u_staging.h" #include "nvfx_resource.h" #include "nouveau/nouveau_screen.h" - -/* This doesn't look quite right - this query is supposed to ask - * whether the particular context has references to the resource in - * any unflushed rendering command buffer, and hence requires a - * pipe->flush() for serializing some modification to that resource. - * - * This seems to be answering the question of whether the resource is - * currently on hardware. - */ static unsigned int nvfx_resource_is_referenced(struct pipe_context *pipe, - struct pipe_resource *resource, + struct pipe_resource *pr, unsigned face, unsigned level) { - return nouveau_reference_flags(nvfx_resource(resource)->bo); + return !!nouveau_reference_flags(nvfx_resource(pr)->bo); } static struct pipe_resource * @@ -30,6 +22,15 @@ nvfx_resource_create(struct pipe_screen *screen, return nvfx_miptree_create(screen, template); } +static void +nvfx_resource_destroy(struct pipe_screen *screen, struct pipe_resource *pr) +{ + if (pr->target == PIPE_BUFFER) + return nvfx_buffer_destroy(screen, pr); + else + return nvfx_miptree_destroy(screen, pr); +} + static struct pipe_resource * nvfx_resource_from_handle(struct pipe_screen * screen, const struct pipe_resource *template, @@ -41,15 +42,22 @@ nvfx_resource_from_handle(struct pipe_screen * screen, return nvfx_miptree_from_handle(screen, template, whandle); } +static boolean +nvfx_resource_get_handle(struct pipe_screen *pscreen, + struct pipe_resource *pr, + struct winsys_handle *whandle) +{ + struct nvfx_resource* res = (struct nvfx_resource*)pr; + + if (!res || !res->bo) + return FALSE; + + return nouveau_screen_bo_get_handle(pscreen, res->bo, nvfx_subresource_pitch(pr, 0), whandle); +} + void nvfx_init_resource_functions(struct pipe_context *pipe) { - pipe->get_transfer = u_get_transfer_vtbl; - pipe->transfer_map = u_transfer_map_vtbl; - pipe->transfer_flush_region = u_transfer_flush_region_vtbl; - pipe->transfer_unmap = u_transfer_unmap_vtbl; - pipe->transfer_destroy = u_transfer_destroy_vtbl; - pipe->transfer_inline_write = u_transfer_inline_write_vtbl; pipe->is_resource_referenced = nvfx_resource_is_referenced; } @@ -58,10 +66,10 @@ nvfx_screen_init_resource_functions(struct pipe_screen *pscreen) { pscreen->resource_create = nvfx_resource_create; pscreen->resource_from_handle = nvfx_resource_from_handle; - pscreen->resource_get_handle = u_resource_get_handle_vtbl; - pscreen->resource_destroy = u_resource_destroy_vtbl; + pscreen->resource_get_handle = nvfx_resource_get_handle; + pscreen->resource_destroy = nvfx_resource_destroy; pscreen->user_buffer_create = nvfx_user_buffer_create; - + pscreen->get_tex_surface = nvfx_miptree_surface_new; pscreen->tex_surface_destroy = nvfx_miptree_surface_del; } diff --git a/src/gallium/drivers/nvfx/nvfx_resource.h b/src/gallium/drivers/nvfx/nvfx_resource.h index a68c14cf3f..583be4de2a 100644 --- a/src/gallium/drivers/nvfx/nvfx_resource.h +++ b/src/gallium/drivers/nvfx/nvfx_resource.h @@ -1,44 +1,82 @@ - #ifndef NVFX_RESOURCE_H #define NVFX_RESOURCE_H #include "util/u_transfer.h" +#include "util/u_format.h" +#include "util/u_math.h" +#include "util/u_double_list.h" +#include "util/u_surfaces.h" +#include "util/u_dirty_surfaces.h" +#include <nouveau/nouveau_bo.h> struct pipe_resource; -struct nouveau_bo; - +struct nv04_region; -/* This gets further specialized into either buffer or texture - * structures. In the future we'll want to remove much of that - * distinction, but for now try to keep as close to the existing code - * as possible and use the vtbl struct to choose between the two - * underlying implementations. - */ struct nvfx_resource { struct pipe_resource base; - struct u_resource_vtbl *vtbl; struct nouveau_bo *bo; }; +static INLINE +struct nvfx_resource *nvfx_resource(struct pipe_resource *resource) +{ + return (struct nvfx_resource *)resource; +} + +#define NVFX_RESOURCE_FLAG_LINEAR (PIPE_RESOURCE_FLAG_DRV_PRIV << 0) +#define NVFX_RESOURCE_FLAG_USER (PIPE_RESOURCE_FLAG_DRV_PRIV << 1) + +/* is resource mapped into the GPU's address space (i.e. VRAM or GART) ? */ +static INLINE boolean +nvfx_resource_mapped_by_gpu(struct pipe_resource *resource) +{ + return nvfx_resource(resource)->bo->handle; +} + +/* is resource in VRAM? */ +static inline int +nvfx_resource_on_gpu(struct pipe_resource* pr) +{ +#if 0 + // a compiler error here means you need to apply libdrm-nouveau-add-domain.patch to libdrm + // TODO: return FALSE if not VRAM and on a PCI-E system + return ((struct nvfx_resource*)pr)->bo->domain & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART); +#else + return TRUE; +#endif +} + #define NVFX_MAX_TEXTURE_LEVELS 16 +/* We have the following invariants for render temporaries + * + * 1. Render temporaries are always linear + * 2. Render temporaries are always up to date + * 3. Currently, render temporaries are destroyed when the resource is used for sampling, but kept for any other use + * + * Also, we do NOT flush temporaries on any pipe->flush(). + * This is fine, as long as scanout targets and shared resources never need temps. + * + * TODO: we may want to also support swizzled temporaries to improve performance in some cases. + */ + struct nvfx_miptree { - struct nvfx_resource base; - uint total_size; + struct nvfx_resource base; - struct { - uint pitch; - uint *image_offset; - } level[NVFX_MAX_TEXTURE_LEVELS]; + unsigned linear_pitch; /* for linear textures, 0 for swizzled and compressed textures with level-dependent minimal pitch */ + unsigned face_size; /* 128-byte aligned face/total size */ + unsigned level_offset[NVFX_MAX_TEXTURE_LEVELS]; - unsigned image_nr; + struct util_surfaces surfaces; + struct util_dirty_surfaces dirty_surfaces; }; -static INLINE -struct nvfx_resource *nvfx_resource(struct pipe_resource *resource) -{ - return (struct nvfx_resource *)resource; -} +struct nvfx_surface { + struct util_dirty_surface base; + unsigned pitch; + + struct nvfx_miptree* temp; +}; static INLINE struct nouveau_bo * nvfx_surface_buffer(struct pipe_surface *surf) @@ -48,6 +86,12 @@ nvfx_surface_buffer(struct pipe_surface *surf) return mt->bo; } +static INLINE struct util_dirty_surfaces* +nvfx_surface_get_dirty_surfaces(struct pipe_surface* surf) +{ + struct nvfx_miptree *mt = (struct nvfx_miptree *)surf->texture; + return &mt->dirty_surfaces; +} void nvfx_init_resource_functions(struct pipe_context *pipe); @@ -62,30 +106,118 @@ nvfx_screen_init_resource_functions(struct pipe_screen *pscreen); struct pipe_resource * nvfx_miptree_create(struct pipe_screen *pscreen, const struct pipe_resource *pt); +void +nvfx_miptree_destroy(struct pipe_screen *pscreen, + struct pipe_resource *presource); + struct pipe_resource * nvfx_miptree_from_handle(struct pipe_screen *pscreen, const struct pipe_resource *template, struct winsys_handle *whandle); +void +nvfx_miptree_surface_del(struct pipe_surface *ps); + +struct pipe_surface * +nvfx_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_resource *pt, + unsigned face, unsigned level, unsigned zslice, + unsigned flags); + +/* only for miptrees, don't use for buffers */ + +/* NOTE: for swizzled 3D textures, this just returns the offset of the mipmap level */ +static inline unsigned +nvfx_subresource_offset(struct pipe_resource* pt, unsigned face, unsigned level, unsigned zslice) +{ + if(pt->target == PIPE_BUFFER) + return 0; + else + { + struct nvfx_miptree *mt = (struct nvfx_miptree *)pt; + + unsigned offset = mt->level_offset[level]; + if (pt->target == PIPE_TEXTURE_CUBE) + offset += mt->face_size * face; + else if (pt->target == PIPE_TEXTURE_3D && mt->linear_pitch) + offset += zslice * util_format_get_2d_size(pt->format, (mt->linear_pitch ? mt->linear_pitch : util_format_get_stride(pt->format, u_minify(pt->width0, level))), u_minify(pt->height0, level)); + return offset; + } +} + +static inline unsigned +nvfx_subresource_pitch(struct pipe_resource* pt, unsigned level) +{ + if(pt->target == PIPE_BUFFER) + return ((struct nvfx_resource*)pt)->bo->size; + else + { + struct nvfx_miptree *mt = (struct nvfx_miptree *)pt; + + if(mt->linear_pitch) + return mt->linear_pitch; + else + return util_format_get_stride(pt->format, u_minify(pt->width0, level)); + } +} + +void +nvfx_surface_create_temp(struct pipe_context* pipe, struct pipe_surface* surf); + +void +nvfx_surface_flush(struct pipe_context* pipe, struct pipe_surface* surf); + +struct nvfx_buffer +{ + struct nvfx_resource base; + uint8_t* data; + unsigned size; + + /* the range of data not yet uploaded to the GPU bo */ + unsigned dirty_begin; + unsigned dirty_end; + + /* whether all transfers were unsynchronized */ + boolean dirty_unsynchronized; + + /* whether it would have been profitable to upload + * the latest updated data to the GPU immediately */ + boolean last_update_static; + + /* how many bytes we need to draw before we deem + * the buffer to be static + */ + long long bytes_to_draw_until_static; +}; + +static inline struct nvfx_buffer* nvfx_buffer(struct pipe_resource* pr) +{ + return (struct nvfx_buffer*)pr; +} + +/* this is an heuristic to determine whether we are better off uploading the + * buffer to the GPU, or just continuing pushing it on the FIFO + */ +static inline boolean nvfx_buffer_seems_static(struct nvfx_buffer* buffer) +{ + return buffer->last_update_static + || buffer->bytes_to_draw_until_static < 0; +} + struct pipe_resource * nvfx_buffer_create(struct pipe_screen *pscreen, const struct pipe_resource *template); +void +nvfx_buffer_destroy(struct pipe_screen *pscreen, + struct pipe_resource *presource); + struct pipe_resource * nvfx_user_buffer_create(struct pipe_screen *screen, void *ptr, unsigned bytes, unsigned usage); - - void -nvfx_miptree_surface_del(struct pipe_surface *ps); - -struct pipe_surface * -nvfx_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_resource *pt, - unsigned face, unsigned level, unsigned zslice, - unsigned flags); - +nvfx_buffer_upload(struct nvfx_buffer* buffer); #endif diff --git a/src/gallium/drivers/nvfx/nvfx_screen.c b/src/gallium/drivers/nvfx/nvfx_screen.c index f2525ccb38..65ca265d45 100644 --- a/src/gallium/drivers/nvfx/nvfx_screen.c +++ b/src/gallium/drivers/nvfx/nvfx_screen.c @@ -8,23 +8,12 @@ #include "nvfx_context.h" #include "nvfx_screen.h" #include "nvfx_resource.h" +#include "nvfx_tex.h" #define NV30TCL_CHIPSET_3X_MASK 0x00000003 #define NV34TCL_CHIPSET_3X_MASK 0x00000010 #define NV35TCL_CHIPSET_3X_MASK 0x000001e0 -/* FIXME: It seems I should not include directly ../../winsys/drm/nouveau/drm/nouveau_drm_api.h -* to get the pointer to the context front buffer, so I copied nouveau_winsys here. -* nv30_screen_surface_format_supported() can then use it to enforce creating fbo -* with same number of bits everywhere. -*/ -struct nouveau_winsys { - struct pipe_winsys base; - - struct pipe_screen *pscreen; - - struct pipe_surface *front; -}; #define NV4X_GRCLASS4097_CHIPSETS 0x00000baf #define NV4X_GRCLASS4497_CHIPSETS 0x00005450 #define NV6X_GRCLASS4497_CHIPSETS 0x00000088 @@ -43,7 +32,7 @@ nvfx_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_TWO_SIDED_STENCIL: return 1; case PIPE_CAP_GLSL: - return 0; + return 1; case PIPE_CAP_ANISOTROPIC_FILTER: return 1; case PIPE_CAP_POINT_SPRITE: @@ -162,77 +151,74 @@ nvfx_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_cap param) } static boolean -nvfx_screen_surface_format_supported(struct pipe_screen *pscreen, +nvfx_screen_is_format_supported(struct pipe_screen *pscreen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, - unsigned tex_usage, unsigned geom_flags) + unsigned bind, unsigned geom_flags) { struct nvfx_screen *screen = nvfx_screen(pscreen); - struct pipe_surface *front = ((struct nouveau_winsys *) pscreen->winsys)->front; if (sample_count > 1) return FALSE; - if (tex_usage & PIPE_BIND_RENDER_TARGET) { + if (bind & PIPE_BIND_RENDER_TARGET) { switch (format) { case PIPE_FORMAT_B8G8R8A8_UNORM: case PIPE_FORMAT_B8G8R8X8_UNORM: case PIPE_FORMAT_B5G6R5_UNORM: - return TRUE; - default: break; + default: + return FALSE; } - } else - if (tex_usage & PIPE_BIND_DEPTH_STENCIL) { + } + + if (bind & PIPE_BIND_DEPTH_STENCIL) { switch (format) { case PIPE_FORMAT_S8_USCALED_Z24_UNORM: case PIPE_FORMAT_X8Z24_UNORM: - return TRUE; case PIPE_FORMAT_Z16_UNORM: - /* TODO: this nv30 limitation probably does not exist */ - if (!screen->is_nv4x && front) - return (front->format == PIPE_FORMAT_B5G6R5_UNORM); - return TRUE; - default: break; + default: + return FALSE; } - } else { - switch (format) { - if (tex_usage & PIPE_BIND_SAMPLER_VIEW) { - switch (format) { - case PIPE_FORMAT_DXT1_RGB: - case PIPE_FORMAT_DXT1_RGBA: - case PIPE_FORMAT_DXT3_RGBA: - case PIPE_FORMAT_DXT5_RGBA: - return util_format_s3tc_enabled; - default: - break; - } + } + + if (bind & PIPE_BIND_SAMPLER_VIEW) { + struct nvfx_texture_format* tf = &nvfx_texture_formats[format]; + if(util_format_is_s3tc(format) && !util_format_s3tc_enabled) + return FALSE; + + if(screen->is_nv4x) + { + if(tf->fmt[4] < 0) + return FALSE; } - case PIPE_FORMAT_B8G8R8A8_UNORM: - case PIPE_FORMAT_B8G8R8X8_UNORM: - case PIPE_FORMAT_B5G5R5A1_UNORM: - case PIPE_FORMAT_B4G4R4A4_UNORM: - case PIPE_FORMAT_B5G6R5_UNORM: - case PIPE_FORMAT_L8_UNORM: - case PIPE_FORMAT_A8_UNORM: - case PIPE_FORMAT_I8_UNORM: - case PIPE_FORMAT_L8A8_UNORM: - case PIPE_FORMAT_Z16_UNORM: - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - return TRUE; - /* TODO: does nv30 support this? */ - case PIPE_FORMAT_R16_SNORM: - return !!screen->is_nv4x; - default: - break; + else + { + if(tf->fmt[0] < 0) + return FALSE; } } - return FALSE; -} + // note that we do actually support everything through translate + if (bind & PIPE_BIND_VERTEX_BUFFER) { + unsigned type = nvfx_vertex_formats[format]; + if(!type) + return FALSE; + } + + if (bind & PIPE_BIND_INDEX_BUFFER) { + // 8-bit indices supported, but not in hardware index buffer + if(format != PIPE_FORMAT_R16_USCALED && format != PIPE_FORMAT_R32_USCALED) + return FALSE; + } + + if(bind & PIPE_BIND_STREAM_OUTPUT) + return FALSE; + return TRUE; +} static void nvfx_screen_destroy(struct pipe_screen *pscreen) @@ -245,7 +231,7 @@ nvfx_screen_destroy(struct pipe_screen *pscreen) nouveau_notifier_free(&screen->query); nouveau_notifier_free(&screen->sync); nouveau_grobj_free(&screen->eng3d); - nv04_surface_2d_takedown(&screen->eng2d); + nvfx_screen_surface_takedown(pscreen); nouveau_screen_fini(&screen->base); @@ -374,6 +360,14 @@ nvfx_screen_get_vertex_buffer_flags(struct nvfx_screen* screen) return vram_hack ? NOUVEAU_BO_VRAM : NOUVEAU_BO_GART; } +static void nvfx_channel_flush_notify(struct nouveau_channel* chan) +{ + struct nvfx_screen* screen = chan->user_private; + struct nvfx_context* nvfx = screen->cur_ctx; + if(nvfx) + nvfx->relocs_needed = NVFX_RELOCATE_ALL; +} + struct pipe_screen * nvfx_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) { @@ -395,12 +389,15 @@ nvfx_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) return NULL; } chan = screen->base.channel; + screen->cur_ctx = NULL; + chan->user_private = screen; + chan->flush_notify = nvfx_channel_flush_notify; pscreen->winsys = ws; pscreen->destroy = nvfx_screen_destroy; pscreen->get_param = nvfx_screen_get_param; pscreen->get_paramf = nvfx_screen_get_paramf; - pscreen->is_format_supported = nvfx_screen_surface_format_supported; + pscreen->is_format_supported = nvfx_screen_is_format_supported; pscreen->context_create = nvfx_create; switch (dev->chipset & 0xf0) { @@ -432,6 +429,11 @@ nvfx_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) } screen->force_swtnl = debug_get_bool_option("NOUVEAU_SWTNL", FALSE); + screen->trace_draw = debug_get_bool_option("NVFX_TRACE_DRAW", FALSE); + + screen->buffer_allocation_cost = debug_get_num_option("NVFX_BUFFER_ALLOCATION_COST", 16384); + screen->inline_cost_per_hardware_cost = atof(debug_get_option("NVFX_INLINE_COST_PER_HARDWARE_COST", "1.0")); + screen->static_reuse_threshold = atof(debug_get_option("NVFX_STATIC_REUSE_THRESHOLD", "2.0")); screen->vertex_buffer_reloc_flags = nvfx_screen_get_vertex_buffer_flags(screen); @@ -451,8 +453,7 @@ nvfx_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) } /* 2D engine setup */ - screen->eng2d = nv04_surface_2d_init(&screen->base); - screen->eng2d->buf = nvfx_surface_buffer; + nvfx_screen_surface_init(pscreen); /* Notifier for sync purposes */ ret = nouveau_notifier_alloc(chan, 0xbeef0301, 1, &screen->sync); diff --git a/src/gallium/drivers/nvfx/nvfx_screen.h b/src/gallium/drivers/nvfx/nvfx_screen.h index 5e1c3945ae..1b79235ae0 100644 --- a/src/gallium/drivers/nvfx/nvfx_screen.h +++ b/src/gallium/drivers/nvfx/nvfx_screen.h @@ -1,11 +1,11 @@ #ifndef __NVFX_SCREEN_H__ #define __NVFX_SCREEN_H__ +#include "pipe/p_compiler.h" #include "util/u_double_list.h" #include "nouveau/nouveau_screen.h" -#include "nv04_surface_2d.h" -struct nvfx_context; +struct pipe_screen; struct nvfx_screen { struct nouveau_screen base; @@ -16,11 +16,11 @@ struct nvfx_screen { unsigned is_nv4x; /* either 0 or ~0 */ boolean force_swtnl; + boolean trace_draw; unsigned vertex_buffer_reloc_flags; unsigned index_buffer_reloc_flags; /* HW graphics objects */ - struct nv04_surface_2d *eng2d; struct nouveau_grobj *eng3d; struct nouveau_notifier *sync; @@ -32,6 +32,20 @@ struct nvfx_screen { /* Vtxprog resources */ struct nouveau_resource *vp_exec_heap; struct nouveau_resource *vp_data_heap; + + struct nv04_2d_context* eng2d; + + /* Once the amount of bytes drawn from the buffer reaches the updated size times this value, + * we will assume that the buffer will be drawn an huge number of times before the + * next modification + */ + float static_reuse_threshold; + + /* Cost of allocating a buffer in terms of the cost of copying a byte to an hardware buffer */ + unsigned buffer_allocation_cost; + + /* inline_cost/hardware_cost conversion ration */ + float inline_cost_per_hardware_cost; }; static INLINE struct nvfx_screen * @@ -40,4 +54,7 @@ nvfx_screen(struct pipe_screen *screen) return (struct nvfx_screen *)screen; } +int nvfx_screen_surface_init(struct pipe_screen *pscreen); +void nvfx_screen_surface_takedown(struct pipe_screen *pscreen); + #endif diff --git a/src/gallium/drivers/nvfx/nvfx_shader.h b/src/gallium/drivers/nvfx/nvfx_shader.h index 50830b3916..35006eec3d 100644 --- a/src/gallium/drivers/nvfx/nvfx_shader.h +++ b/src/gallium/drivers/nvfx/nvfx_shader.h @@ -1,6 +1,12 @@ #ifndef __NVFX_SHADER_H__ #define __NVFX_SHADER_H__ +#include <stdint.h> + +#include "pipe/p_compiler.h" + +#define NVFX_SWZ_IDENTITY ((3 << 6) | (2 << 4) | (1 << 2) | (0 << 0)) + /* this will resolve to either the NV30 or the NV40 version * depending on the current hardware */ /* unusual, but very fast and compact method */ @@ -71,11 +77,58 @@ /* * Each fragment program opcode appears to be comprised of 4 32-bit values. * - * 0 - Opcode, output reg/mask, ATTRIB source - * 1 - Source 0 - * 2 - Source 1 - * 3 - Source 2 + * 0: OPDEST + * 0: program end + * 1-6: destination register + * 7: destination register is fp16?? (use for outputs) + * 8: set condition code + * 9: writemask x + * 10: writemask y + * 11: writemask z + * 12: writemask w + * 13-16: source attribute register number (e.g. COL0) + * 17-20: texture unit number + * 21: expand value on texture operation (x -> 2x - 1) + * 22-23: precision 0 = fp32, 1 = fp16, 2 = s1.10 fixed, 3 = s0.8 fixed (nv40-only)) + * 24-29: opcode + * 30: no destination + * 31: saturate + * 1 - SRC0 + * 0-17: see common source fields + * 18: execute if condition code less + * 19: execute if condition code equal + * 20: execute if condition code greater + * 21-22: condition code swizzle x source component + * 23-24: condition code swizzle y source component + * 25-26: condition code swizzle z source component + * 27-28: condition code swizzle w source component + * 29: source 0 absolute + * 30: always 0 in renouveau tests + * 31: always 0 in renouveau tests + * 2 - SRC1 + * 0-17: see common source fields + * 18: source 1 absolute + * 19-20: input precision 0 = fp32, 1 = fp16, 2 = s1.10 fixed, 3 = ??? + * 21-27: always 0 in renouveau tests + * 28-30: scale (0 = 1x, 1 = 2x, 2 = 4x, 3 = 8x, 4 = ???, 5, = 1/2, 6 = 1/4, 7 = 1/8) + * 31: opcode is branch + * 3 - SRC2 + * 0-17: see common source fields + * 18: source 2 absolute + * 19-29: address register displacement + * 30: use index register + * 31: disable perspective-correct interpolation? * +* Common fields of 0, 1, 2 - SRC + * 0-1: source register type (0 = temp, 1 = input, 2 = immediate, 3 = ???) + * 2-7: source temp register index + * 8: source register is fp16?? + * 9-10: source swizzle x source component + * 11-12: source swizzle y source component + * 13-14: source swizzle z source component + * 15-16: source swizzle w source component + * 17: negate + * There appears to be no special difference between result regs and temp regs. * result.color == R0.xyzw * result.depth == R1.z @@ -210,6 +263,7 @@ /* NV40 only fragment program opcodes */ #define NVFX_FP_OP_OPCODE_TXL_NV40 0x2F + /* The use of these instructions appears to be indicated by bit 31 of DWORD 2.*/ #define NV40_FP_OP_BRA_OPCODE_BRK 0x0 #define NV40_FP_OP_BRA_OPCODE_CAL 0x1 @@ -218,10 +272,11 @@ #define NV40_FP_OP_BRA_OPCODE_REP 0x4 #define NV40_FP_OP_BRA_OPCODE_RET 0x5 +#define NV40_FP_OP_OUT_NONE (1 << 30) #define NVFX_FP_OP_OUT_SAT (1 << 31) /* high order bits of SRC0 */ -#define NVFX_FP_OP_OUT_ABS (1 << 29) +#define NVFX_FP_OP_SRC0_ABS (1 << 29) #define NVFX_FP_OP_COND_SWZ_W_SHIFT 27 #define NVFX_FP_OP_COND_SWZ_W_MASK (3 << 27) #define NVFX_FP_OP_COND_SWZ_Z_SHIFT 25 @@ -254,6 +309,7 @@ #define NVFX_FP_OP_DST_SCALE_INV_2X 5 #define NVFX_FP_OP_DST_SCALE_INV_4X 6 #define NVFX_FP_OP_DST_SCALE_INV_8X 7 +#define NVFX_FP_OP_SRC1_ABS (1 << 18) /* SRC1 LOOP */ #define NV40_FP_OP_LOOP_INCR_SHIFT 19 @@ -263,13 +319,13 @@ #define NV40_FP_OP_LOOP_COUNT_SHIFT 2 #define NV40_FP_OP_LOOP_COUNT_MASK (0xFF << 2) -/* SRC1 IF */ -#define NV40_FP_OP_ELSE_ID_SHIFT 2 -#define NV40_FP_OP_ELSE_ID_MASK (0xFF << 2) +/* SRC1 IF: absolute offset in dwords */ +#define NV40_FP_OP_ELSE_OFFSET_SHIFT 0 +#define NV40_FP_OP_ELSE_OFFSET_MASK (0x7FFFFFFF << 0) /* SRC1 CAL */ -#define NV40_FP_OP_IADDR_SHIFT 2 -#define NV40_FP_OP_IADDR_MASK (0xFF << 2) +#define NV40_FP_OP_SUB_OFFSET_SHIFT 0 +#define NV40_FP_OP_SUB_OFFSET_MASK (0x7FFFFFFF << 0) /* SRC1 REP * I have no idea why there are 3 count values here.. but they @@ -283,9 +339,9 @@ #define NV40_FP_OP_REP_COUNT3_SHIFT 19 #define NV40_FP_OP_REP_COUNT3_MASK (0xFF << 19) -/* SRC2 REP/IF */ -#define NV40_FP_OP_END_ID_SHIFT 2 -#define NV40_FP_OP_END_ID_MASK (0xFF << 2) +/* SRC2 REP/IF: absolute offset in dwords */ +#define NV40_FP_OP_END_OFFSET_SHIFT 0 +#define NV40_FP_OP_END_OFFSET_MASK (0x7FFFFFFF << 0) /* high order bits of SRC2 */ #define NVFX_FP_OP_INDEX_INPUT (1 << 30) @@ -323,6 +379,7 @@ #define NVFXSR_INPUT 2 #define NVFXSR_TEMP 3 #define NVFXSR_CONST 4 +#define NVFXSR_RELOCATED 5 #define NVFX_COND_FL 0 #define NVFX_COND_LT 1 @@ -352,51 +409,88 @@ #define NVFX_SWZ_Z 2 #define NVFX_SWZ_W 3 -#define swz(s,x,y,z,w) nvfx_sr_swz((s), NVFX_SWZ_##x, NVFX_SWZ_##y, NVFX_SWZ_##z, NVFX_SWZ_##w) -#define neg(s) nvfx_sr_neg((s)) -#define abs(s) nvfx_sr_abs((s)) -#define scale(s,v) nvfx_sr_scale((s), NVFX_FP_OP_DST_SCALE_##v) +#define swz(s,x,y,z,w) nvfx_src_swz((s), NVFX_SWZ_##x, NVFX_SWZ_##y, NVFX_SWZ_##z, NVFX_SWZ_##w) +#define neg(s) nvfx_src_neg((s)) +#define abs(s) nvfx_src_abs((s)) -struct nvfx_sreg { - int type; - int index; +struct nvfx_reg { + uint8_t type; + uint32_t index; +}; - int dst_scale; +struct nvfx_src { + struct nvfx_reg reg; - int negate; - int abs; - int swz[4]; + /* src only */ + uint8_t negate : 1; + uint8_t abs : 1; + uint8_t swz[4]; +}; - int cc_update; - int cc_update_reg; - int cc_test; - int cc_test_reg; - int cc_swz[4]; +struct nvfx_insn +{ + uint8_t op; + char scale; + int8_t unit; + uint8_t mask; + uint8_t cc_swz[4]; + + uint8_t sat : 1; + uint8_t cc_update : 1; + uint8_t cc_update_reg : 1; + uint8_t cc_test : 3; + uint8_t cc_test_reg : 1; + + struct nvfx_reg dst; + struct nvfx_src src[3]; }; -static INLINE struct nvfx_sreg -nvfx_sr(int type, int index) +static INLINE struct nvfx_insn +nvfx_insn(boolean sat, unsigned op, int unit, struct nvfx_reg dst, unsigned mask, struct nvfx_src s0, struct nvfx_src s1, struct nvfx_src s2) { - struct nvfx_sreg temp = { - .type = type, - .index = index, - .dst_scale = 0, - .abs = 0, - .negate = 0, - .swz = { 0, 1, 2, 3 }, + struct nvfx_insn insn = { + .op = op, + .scale = 0, + .unit = unit, + .sat = sat, + .mask = mask, .cc_update = 0, .cc_update_reg = 0, .cc_test = NVFX_COND_TR, .cc_test_reg = 0, .cc_swz = { 0, 1, 2, 3 }, + .dst = dst, + .src = {s0, s1, s2} + }; + return insn; +} + +static INLINE struct nvfx_reg +nvfx_reg(int type, int index) +{ + struct nvfx_reg temp = { + .type = type, + .index = index, }; return temp; } -static INLINE struct nvfx_sreg -nvfx_sr_swz(struct nvfx_sreg src, int x, int y, int z, int w) +static INLINE struct nvfx_src +nvfx_src(struct nvfx_reg reg) { - struct nvfx_sreg dst = src; + struct nvfx_src temp = { + .reg = reg, + .abs = 0, + .negate = 0, + .swz = { 0, 1, 2, 3 }, + }; + return temp; +} + +static INLINE struct nvfx_src +nvfx_src_swz(struct nvfx_src src, int x, int y, int z, int w) +{ + struct nvfx_src dst = src; dst.swz[NVFX_SWZ_X] = src.swz[x]; dst.swz[NVFX_SWZ_Y] = src.swz[y]; @@ -405,25 +499,23 @@ nvfx_sr_swz(struct nvfx_sreg src, int x, int y, int z, int w) return dst; } -static INLINE struct nvfx_sreg -nvfx_sr_neg(struct nvfx_sreg src) +static INLINE struct nvfx_src +nvfx_src_neg(struct nvfx_src src) { src.negate = !src.negate; return src; } -static INLINE struct nvfx_sreg -nvfx_sr_abs(struct nvfx_sreg src) +static INLINE struct nvfx_src +nvfx_src_abs(struct nvfx_src src) { src.abs = 1; return src; } -static INLINE struct nvfx_sreg -nvfx_sr_scale(struct nvfx_sreg src, int scale) -{ - src.dst_scale = scale; - return src; -} +struct nvfx_relocation { + unsigned location; + unsigned target; +}; #endif diff --git a/src/gallium/drivers/nvfx/nvfx_state.c b/src/gallium/drivers/nvfx/nvfx_state.c index cd58e439d7..5bd7dc07f0 100644 --- a/src/gallium/drivers/nvfx/nvfx_state.c +++ b/src/gallium/drivers/nvfx/nvfx_state.c @@ -1,6 +1,7 @@ #include "pipe/p_state.h" #include "pipe/p_defines.h" #include "util/u_inlines.h" +#include "util/u_framebuffer.h" #include "draw/draw_context.h" @@ -81,111 +82,6 @@ nvfx_blend_state_delete(struct pipe_context *pipe, void *hwcso) } static void * -nvfx_sampler_state_create(struct pipe_context *pipe, - const struct pipe_sampler_state *cso) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - struct nvfx_sampler_state *ps; - - ps = MALLOC(sizeof(struct nvfx_sampler_state)); - - /* on nv30, we use this as an internal flag */ - ps->fmt = cso->normalized_coords ? 0 : NV40TCL_TEX_FORMAT_RECT; - ps->en = 0; - ps->filt = nvfx_tex_filter(cso); - ps->wrap = (nvfx_tex_wrap_mode(cso->wrap_s) << NV34TCL_TX_WRAP_S_SHIFT) | - (nvfx_tex_wrap_mode(cso->wrap_t) << NV34TCL_TX_WRAP_T_SHIFT) | - (nvfx_tex_wrap_mode(cso->wrap_r) << NV34TCL_TX_WRAP_R_SHIFT) | - nvfx_tex_wrap_compare_mode(cso); - ps->bcol = nvfx_tex_border_color(cso->border_color); - - if(nvfx->is_nv4x) - nv40_sampler_state_init(pipe, ps, cso); - else - nv30_sampler_state_init(pipe, ps, cso); - - return (void *)ps; -} - -static void -nvfx_sampler_state_bind(struct pipe_context *pipe, unsigned nr, void **sampler) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - unsigned unit; - - for (unit = 0; unit < nr; unit++) { - nvfx->tex_sampler[unit] = sampler[unit]; - nvfx->dirty_samplers |= (1 << unit); - } - - for (unit = nr; unit < nvfx->nr_samplers; unit++) { - nvfx->tex_sampler[unit] = NULL; - nvfx->dirty_samplers |= (1 << unit); - } - - nvfx->nr_samplers = nr; - nvfx->dirty |= NVFX_NEW_SAMPLER; -} - -static void -nvfx_sampler_state_delete(struct pipe_context *pipe, void *hwcso) -{ - FREE(hwcso); -} - -static void -nvfx_set_fragment_sampler_views(struct pipe_context *pipe, - unsigned nr, - struct pipe_sampler_view **views) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - unsigned unit; - - for (unit = 0; unit < nr; unit++) { - pipe_sampler_view_reference(&nvfx->fragment_sampler_views[unit], - views[unit]); - nvfx->dirty_samplers |= (1 << unit); - } - - for (unit = nr; unit < nvfx->nr_textures; unit++) { - pipe_sampler_view_reference(&nvfx->fragment_sampler_views[unit], - NULL); - nvfx->dirty_samplers |= (1 << unit); - } - - nvfx->nr_textures = nr; - nvfx->dirty |= NVFX_NEW_SAMPLER; -} - - -static struct pipe_sampler_view * -nvfx_create_sampler_view(struct pipe_context *pipe, - struct pipe_resource *texture, - const struct pipe_sampler_view *templ) -{ - struct pipe_sampler_view *view = CALLOC_STRUCT(pipe_sampler_view); - - if (view) { - *view = *templ; - view->reference.count = 1; - view->texture = NULL; - pipe_resource_reference(&view->texture, texture); - view->context = pipe; - } - - return view; -} - - -static void -nvfx_sampler_view_destroy(struct pipe_context *pipe, - struct pipe_sampler_view *view) -{ - pipe_resource_reference(&view->texture, NULL); - FREE(view); -} - -static void * nvfx_rasterizer_state_create(struct pipe_context *pipe, const struct pipe_rasterizer_state *cso) { @@ -195,6 +91,7 @@ nvfx_rasterizer_state_create(struct pipe_context *pipe, /*XXX: ignored: * point_smooth -nohw * multisample + * sprite_coord_origin */ sb_method(sb, NV34TCL_SHADE_MODEL, 1); @@ -254,19 +151,8 @@ nvfx_rasterizer_state_create(struct pipe_context *pipe, sb_data(sb, fui(cso->offset_units * 2)); } - sb_method(sb, NV34TCL_POINT_SPRITE, 1); - if (cso->point_quad_rasterization) { - unsigned psctl = (1 << 0), i; - - for (i = 0; i < 8; i++) { - if ((cso->sprite_coord_enable >> i) & 1) - psctl |= (1 << (8 + i)); - } - - sb_data(sb, psctl); - } else { - sb_data(sb, 0); - } + sb_method(sb, NV34TCL_FLATSHADE_FIRST, 1); + sb_data(sb, cso->flatshade_first); rsso->pipe = *cso; rsso->sb_len = sb_len(sb, rsso->sb); @@ -287,11 +173,11 @@ nvfx_rasterizer_state_bind(struct pipe_context *pipe, void *hwcso) nvfx->draw_dirty |= NVFX_NEW_SCISSOR; } - if(((struct nvfx_rasterizer_state*)hwcso)->pipe.poly_stipple_enable - != nvfx->rasterizer->pipe.poly_stipple_enable) + if(((struct nvfx_rasterizer_state*)hwcso)->pipe.point_quad_rasterization != nvfx->rasterizer->pipe.point_quad_rasterization + || ((struct nvfx_rasterizer_state*)hwcso)->pipe.sprite_coord_enable != nvfx->rasterizer->pipe.sprite_coord_enable + || ((struct nvfx_rasterizer_state*)hwcso)->pipe.sprite_coord_mode != nvfx->rasterizer->pipe.sprite_coord_mode) { - nvfx->dirty |= NVFX_NEW_STIPPLE; - nvfx->draw_dirty |= NVFX_NEW_STIPPLE; + nvfx->dirty |= NVFX_NEW_SPRITE; } } @@ -315,10 +201,8 @@ nvfx_depth_stencil_alpha_state_create(struct pipe_context *pipe, struct nvfx_zsa_state *zsaso = CALLOC(1, sizeof(*zsaso)); struct nouveau_statebuf_builder sb = sb_init(zsaso->sb); - sb_method(sb, NV34TCL_DEPTH_FUNC, 3); + sb_method(sb, NV34TCL_DEPTH_FUNC, 1); sb_data (sb, nvgl_comparison_op(cso->depth.func)); - sb_data (sb, cso->depth.writemask ? 1 : 0); - sb_data (sb, cso->depth.enabled ? 1 : 0); sb_method(sb, NV34TCL_ALPHA_FUNC_ENABLE, 3); sb_data (sb, cso->alpha.enabled ? 1 : 0); @@ -377,76 +261,6 @@ nvfx_depth_stencil_alpha_state_delete(struct pipe_context *pipe, void *hwcso) FREE(zsaso); } -static void * -nvfx_vp_state_create(struct pipe_context *pipe, - const struct pipe_shader_state *cso) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - struct nvfx_vertex_program *vp; - - vp = CALLOC(1, sizeof(struct nvfx_vertex_program)); - vp->pipe.tokens = tgsi_dup_tokens(cso->tokens); - vp->draw = draw_create_vertex_shader(nvfx->draw, &vp->pipe); - - return (void *)vp; -} - -static void -nvfx_vp_state_bind(struct pipe_context *pipe, void *hwcso) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - - nvfx->vertprog = hwcso; - nvfx->dirty |= NVFX_NEW_VERTPROG; - nvfx->draw_dirty |= NVFX_NEW_VERTPROG; -} - -static void -nvfx_vp_state_delete(struct pipe_context *pipe, void *hwcso) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - struct nvfx_vertex_program *vp = hwcso; - - draw_delete_vertex_shader(nvfx->draw, vp->draw); - nvfx_vertprog_destroy(nvfx, vp); - FREE((void*)vp->pipe.tokens); - FREE(vp); -} - -static void * -nvfx_fp_state_create(struct pipe_context *pipe, - const struct pipe_shader_state *cso) -{ - struct nvfx_fragment_program *fp; - - fp = CALLOC(1, sizeof(struct nvfx_fragment_program)); - fp->pipe.tokens = tgsi_dup_tokens(cso->tokens); - - tgsi_scan_shader(fp->pipe.tokens, &fp->info); - - return (void *)fp; -} - -static void -nvfx_fp_state_bind(struct pipe_context *pipe, void *hwcso) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - - nvfx->fragprog = hwcso; - nvfx->dirty |= NVFX_NEW_FRAGPROG; -} - -static void -nvfx_fp_state_delete(struct pipe_context *pipe, void *hwcso) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - struct nvfx_fragment_program *fp = hwcso; - - nvfx_fragprog_destroy(nvfx, fp); - FREE((void*)fp->pipe.tokens); - FREE(fp); -} - static void nvfx_set_blend_color(struct pipe_context *pipe, const struct pipe_blend_color *bcol) @@ -507,7 +321,10 @@ nvfx_set_framebuffer_state(struct pipe_context *pipe, { struct nvfx_context *nvfx = nvfx_context(pipe); - nvfx->framebuffer = *fb; + if(fb) + util_copy_framebuffer_state(&nvfx->framebuffer, fb); + else + util_unreference_framebuffer_state(&nvfx->framebuffer); nvfx->dirty |= NVFX_NEW_FB; } @@ -542,65 +359,6 @@ nvfx_set_viewport_state(struct pipe_context *pipe, nvfx->draw_dirty |= NVFX_NEW_VIEWPORT; } -static void -nvfx_set_vertex_buffers(struct pipe_context *pipe, unsigned count, - const struct pipe_vertex_buffer *vb) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - - memcpy(nvfx->vtxbuf, vb, sizeof(*vb) * count); - nvfx->vtxbuf_nr = count; - - nvfx->dirty |= NVFX_NEW_ARRAYS; - nvfx->draw_dirty |= NVFX_NEW_ARRAYS; -} - -static void -nvfx_set_index_buffer(struct pipe_context *pipe, - const struct pipe_index_buffer *ib) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - - if (ib) - memcpy(&nvfx->idxbuf, ib, sizeof(nvfx->idxbuf)); - else - memset(&nvfx->idxbuf, 0, sizeof(nvfx->idxbuf)); - - /* TODO make this more like a state */ -} - -static void * -nvfx_vtxelts_state_create(struct pipe_context *pipe, - unsigned num_elements, - const struct pipe_vertex_element *elements) -{ - struct nvfx_vtxelt_state *cso = CALLOC_STRUCT(nvfx_vtxelt_state); - - assert(num_elements < 16); /* not doing fallbacks yet */ - cso->num_elements = num_elements; - memcpy(cso->pipe, elements, num_elements * sizeof(*elements)); - -/* nvfx_vtxelt_construct(cso);*/ - - return (void *)cso; -} - -static void -nvfx_vtxelts_state_delete(struct pipe_context *pipe, void *hwcso) -{ - FREE(hwcso); -} - -static void -nvfx_vtxelts_state_bind(struct pipe_context *pipe, void *hwcso) -{ - struct nvfx_context *nvfx = nvfx_context(pipe); - - nvfx->vtxelt = hwcso; - nvfx->dirty |= NVFX_NEW_ARRAYS; - /*nvfx->draw_dirty |= NVFX_NEW_ARRAYS;*/ -} - void nvfx_init_state_functions(struct nvfx_context *nvfx) { @@ -608,13 +366,6 @@ nvfx_init_state_functions(struct nvfx_context *nvfx) nvfx->pipe.bind_blend_state = nvfx_blend_state_bind; nvfx->pipe.delete_blend_state = nvfx_blend_state_delete; - nvfx->pipe.create_sampler_state = nvfx_sampler_state_create; - nvfx->pipe.bind_fragment_sampler_states = nvfx_sampler_state_bind; - nvfx->pipe.delete_sampler_state = nvfx_sampler_state_delete; - nvfx->pipe.set_fragment_sampler_views = nvfx_set_fragment_sampler_views; - nvfx->pipe.create_sampler_view = nvfx_create_sampler_view; - nvfx->pipe.sampler_view_destroy = nvfx_sampler_view_destroy; - nvfx->pipe.create_rasterizer_state = nvfx_rasterizer_state_create; nvfx->pipe.bind_rasterizer_state = nvfx_rasterizer_state_bind; nvfx->pipe.delete_rasterizer_state = nvfx_rasterizer_state_delete; @@ -626,14 +377,6 @@ nvfx_init_state_functions(struct nvfx_context *nvfx) nvfx->pipe.delete_depth_stencil_alpha_state = nvfx_depth_stencil_alpha_state_delete; - nvfx->pipe.create_vs_state = nvfx_vp_state_create; - nvfx->pipe.bind_vs_state = nvfx_vp_state_bind; - nvfx->pipe.delete_vs_state = nvfx_vp_state_delete; - - nvfx->pipe.create_fs_state = nvfx_fp_state_create; - nvfx->pipe.bind_fs_state = nvfx_fp_state_bind; - nvfx->pipe.delete_fs_state = nvfx_fp_state_delete; - nvfx->pipe.set_blend_color = nvfx_set_blend_color; nvfx->pipe.set_stencil_ref = nvfx_set_stencil_ref; nvfx->pipe.set_clip_state = nvfx_set_clip_state; @@ -643,11 +386,4 @@ nvfx_init_state_functions(struct nvfx_context *nvfx) nvfx->pipe.set_polygon_stipple = nvfx_set_polygon_stipple; nvfx->pipe.set_scissor_state = nvfx_set_scissor_state; nvfx->pipe.set_viewport_state = nvfx_set_viewport_state; - - nvfx->pipe.create_vertex_elements_state = nvfx_vtxelts_state_create; - nvfx->pipe.delete_vertex_elements_state = nvfx_vtxelts_state_delete; - nvfx->pipe.bind_vertex_elements_state = nvfx_vtxelts_state_bind; - - nvfx->pipe.set_vertex_buffers = nvfx_set_vertex_buffers; - nvfx->pipe.set_index_buffer = nvfx_set_index_buffer; } diff --git a/src/gallium/drivers/nvfx/nvfx_state.h b/src/gallium/drivers/nvfx/nvfx_state.h index 9ceb2577ec..e9c1f2c26d 100644 --- a/src/gallium/drivers/nvfx/nvfx_state.h +++ b/src/gallium/drivers/nvfx/nvfx_state.h @@ -4,11 +4,11 @@ #include "pipe/p_state.h" #include "tgsi/tgsi_scan.h" #include "nouveau/nouveau_statebuf.h" +#include "util/u_dynarray.h" +#include "util/u_linkage.h" struct nvfx_vertex_program_exec { uint32_t data[4]; - boolean has_branch_offset; - int const_index; }; struct nvfx_vertex_program_data { @@ -18,18 +18,20 @@ struct nvfx_vertex_program_data { struct nvfx_vertex_program { struct pipe_shader_state pipe; + unsigned long long id; struct draw_vertex_shader *draw; boolean translated; - struct pipe_clip_state ucp; - struct nvfx_vertex_program_exec *insns; unsigned nr_insns; struct nvfx_vertex_program_data *consts; unsigned nr_consts; + char generic_to_fp_input[256]; + int sprite_fp_input; + struct nouveau_resource *exec; unsigned exec_start; struct nouveau_resource *data; @@ -38,7 +40,10 @@ struct nvfx_vertex_program { uint32_t ir; uint32_t or; - uint32_t clip_ctrl; + int clip_nr; + + struct util_dynarray branch_relocs; + struct util_dynarray const_relocs; }; struct nvfx_fragment_program_data { @@ -49,15 +54,14 @@ struct nvfx_fragment_program_data { struct nvfx_fragment_program_bo { struct nvfx_fragment_program_bo* next; struct nouveau_bo* bo; + unsigned char* slots; char insn[] __attribute__((aligned(16))); }; struct nvfx_fragment_program { - struct pipe_shader_state pipe; - struct tgsi_shader_info info; - - boolean translated; unsigned samplers; + unsigned point_sprite_control; + unsigned or; uint32_t *insn; int insn_len; @@ -65,13 +69,36 @@ struct nvfx_fragment_program { struct nvfx_fragment_program_data *consts; unsigned nr_consts; + /* the slot at num_slots is for the sprite coordinate, if any */ + unsigned num_slots; /* how many input semantics? */ + unsigned char slot_to_generic[10]; /* semantics */ + unsigned char slot_to_fp_input[11]; /* current assignment of slots for each used semantic */ + struct util_dynarray slot_relocations[11]; + + /* This is reset to progs on any relocation update, and decreases every time we + * move to a new prog due to a constant update + * When this is the same as progs, applying relocations is no longer necessary. + */ + unsigned progs_left_with_obsolete_slot_assignments; + + unsigned long long last_vp_id; + unsigned last_sprite_coord_enable; + uint32_t fp_control; unsigned bo_prog_idx; unsigned prog_size; unsigned progs_per_bo; + unsigned progs; + struct nvfx_fragment_program_bo* fpbo; }; +struct nvfx_pipe_fragment_program { + struct pipe_shader_state pipe; + struct tgsi_shader_info info; + + struct nvfx_fragment_program* fps[2]; +}; #endif diff --git a/src/gallium/drivers/nvfx/nvfx_state_emit.c b/src/gallium/drivers/nvfx/nvfx_state_emit.c index f91ae19ecd..390bca8cdb 100644 --- a/src/gallium/drivers/nvfx/nvfx_state_emit.c +++ b/src/gallium/drivers/nvfx/nvfx_state_emit.c @@ -1,15 +1,54 @@ #include "nvfx_context.h" #include "nvfx_state.h" +#include "nvfx_resource.h" #include "draw/draw_context.h" static boolean nvfx_state_validate_common(struct nvfx_context *nvfx) { struct nouveau_channel* chan = nvfx->screen->base.channel; - unsigned dirty = nvfx->dirty; + unsigned dirty; + unsigned still_dirty = 0; + int all_swizzled = -1; + boolean flush_tex_cache = FALSE; + unsigned render_temps; if(nvfx != nvfx->screen->cur_ctx) - dirty = ~0; + { + nvfx->dirty = ~0; + nvfx->hw_vtxelt_nr = 16; + nvfx->hw_pointsprite_control = -1; + nvfx->hw_vp_output = -1; + nvfx->screen->cur_ctx = nvfx; + nvfx->relocs_needed = NVFX_RELOCATE_ALL; + } + + /* These can trigger use the of 3D engine to copy temporaries. + * That will recurse here and thus dirty all 3D state, so we need to this before anything else, and in a loop.. + * This converges to having clean temps, then binding both fragtexes and framebuffers. + */ + while(nvfx->dirty & (NVFX_NEW_FB | NVFX_NEW_SAMPLER)) + { + if(nvfx->dirty & NVFX_NEW_SAMPLER) + { + nvfx->dirty &=~ NVFX_NEW_SAMPLER; + nvfx_fragtex_validate(nvfx); + + // TODO: only set this if really necessary + flush_tex_cache = TRUE; + } + + if(nvfx->dirty & NVFX_NEW_FB) + { + nvfx->dirty &=~ NVFX_NEW_FB; + all_swizzled = nvfx_framebuffer_prepare(nvfx); + + // TODO: make sure this doesn't happen, i.e. fbs have matching formats + assert(all_swizzled >= 0); + } + } + + dirty = nvfx->dirty; if(nvfx->render_mode == HW) { @@ -19,11 +58,19 @@ nvfx_state_validate_common(struct nvfx_context *nvfx) return FALSE; } - if(dirty & (NVFX_NEW_ARRAYS)) + if(dirty & NVFX_NEW_ARRAYS) { if(!nvfx_vbo_validate(nvfx)) return FALSE; } + + if(dirty & NVFX_NEW_INDEX) + { + if(nvfx->use_index_buffer) + nvfx_idxbuf_validate(nvfx); + else + still_dirty = NVFX_NEW_INDEX; + } } else { @@ -31,13 +78,10 @@ nvfx_state_validate_common(struct nvfx_context *nvfx) if(dirty & (NVFX_NEW_VERTPROG | NVFX_NEW_UCP)) nvfx_vertprog_validate(nvfx); - if(dirty & (NVFX_NEW_ARRAYS | NVFX_NEW_FRAGPROG)) + if(dirty & (NVFX_NEW_ARRAYS | NVFX_NEW_INDEX | NVFX_NEW_FRAGPROG)) nvfx_vtxfmt_validate(nvfx); } - if(dirty & NVFX_NEW_FB) - nvfx_state_framebuffer_validate(nvfx); - if(dirty & NVFX_NEW_RAST) sb_emit(chan, nvfx->rasterizer->sb, nvfx->rasterizer->sb_len); @@ -47,11 +91,97 @@ nvfx_state_validate_common(struct nvfx_context *nvfx) if(dirty & NVFX_NEW_STIPPLE) nvfx_state_stipple_validate(nvfx); - if(dirty & (NVFX_NEW_FRAGPROG | NVFX_NEW_FRAGCONST)) + if(nvfx->dirty & NVFX_NEW_UCP) + { + unsigned enables[7] = + { + 0, + NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0, + NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1, + NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE2, + NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE2 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE3, + NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE2 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE3 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE4, + NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE2 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE3 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE4 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE5, + }; + + if(!nvfx->use_vp_clipping) + { + WAIT_RING(chan, 2); + OUT_RING(chan, RING_3D(NV34TCL_VP_CLIP_PLANES_ENABLE, 1)); + OUT_RING(chan, 0); + + WAIT_RING(chan, 6 * 4 + 1); + OUT_RING(chan, RING_3D(NV34TCL_VP_CLIP_PLANE_A(0), nvfx->clip.nr * 4)); + OUT_RINGp(chan, &nvfx->clip.ucp[0][0], nvfx->clip.nr * 4); + } + + WAIT_RING(chan, 2); + OUT_RING(chan, RING_3D(NV34TCL_VP_CLIP_PLANES_ENABLE, 1)); + OUT_RING(chan, enables[nvfx->clip.nr]); + } + + if(nvfx->use_vp_clipping && (nvfx->dirty & (NVFX_NEW_UCP | NVFX_NEW_VERTPROG))) + { + unsigned i; + struct nvfx_vertex_program* vp = nvfx->vertprog; + if(nvfx->clip.nr != vp->clip_nr) + { + unsigned idx; + WAIT_RING(chan, 14); + + /* remove last instruction bit */ + if(vp->clip_nr >= 0) + { + idx = vp->nr_insns - 7 + vp->clip_nr; + OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_FROM_ID, 1)); + OUT_RING(chan, vp->exec->start + idx); + OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_INST(0), 4)); + OUT_RINGp (chan, vp->insns[idx].data, 4); + } + + /* set last instruction bit */ + idx = vp->nr_insns - 7 + nvfx->clip.nr; + OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_FROM_ID, 1)); + OUT_RING(chan, vp->exec->start + idx); + OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_INST(0), 4)); + OUT_RINGp(chan, vp->insns[idx].data, 3); + OUT_RING(chan, vp->insns[idx].data[3] | 1); + vp->clip_nr = nvfx->clip.nr; + } + + // TODO: only do this for the ones changed + WAIT_RING(chan, 6 * 6); + for(i = 0; i < nvfx->clip.nr; ++i) + { + OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_CONST_ID, 5)); + OUT_RING(chan, vp->data->start + i); + OUT_RINGp (chan, nvfx->clip.ucp[i], 4); + } + } + + if(dirty & (NVFX_NEW_FRAGPROG | NVFX_NEW_FRAGCONST | NVFX_NEW_VERTPROG | NVFX_NEW_SPRITE)) + { nvfx_fragprog_validate(nvfx); + if(dirty & NVFX_NEW_FRAGPROG) + flush_tex_cache = TRUE; // TODO: do we need this? + } - if(dirty & NVFX_NEW_SAMPLER) - nvfx_fragtex_validate(nvfx); + if(nvfx->is_nv4x) + { + unsigned vp_output = nvfx->vertprog->or | nvfx->hw_fragprog->or; + vp_output |= (1 << (nvfx->clip.nr + 6)) - (1 << 6); + + if(vp_output != nvfx->hw_vp_output) + { + WAIT_RING(chan, 2); + OUT_RING(chan, RING_3D(NV40TCL_VP_RESULT_EN, 1)); + OUT_RING(chan, vp_output); + nvfx->hw_vp_output = vp_output; + } + } + + if(all_swizzled >= 0) + nvfx_framebuffer_validate(nvfx, all_swizzled); if(dirty & NVFX_NEW_BLEND) sb_emit(chan, nvfx->blend->sb, nvfx->blend->sb_len); @@ -65,31 +195,62 @@ nvfx_state_validate_common(struct nvfx_context *nvfx) if(dirty & NVFX_NEW_SR) nvfx_state_sr_validate(nvfx); -/* Having this depend on FB looks wrong, but it seems - necessary to make this work on nv3x +/* All these dependencies are wrong, but otherwise + etracer, neverball, foobillard, glest totally misrender TODO: find the right fix */ - if(dirty & (NVFX_NEW_VIEWPORT | NVFX_NEW_FB)) + if(dirty & (NVFX_NEW_VIEWPORT | NVFX_NEW_RAST | NVFX_NEW_ZSA) || (all_swizzled >= 0)) + { nvfx_state_viewport_validate(nvfx); + } + + if(dirty & NVFX_NEW_ZSA || (all_swizzled >= 0)) + { + WAIT_RING(chan, 3); + OUT_RING(chan, RING_3D(NV34TCL_DEPTH_WRITE_ENABLE, 2)); + OUT_RING(chan, nvfx->framebuffer.zsbuf && nvfx->zsa->pipe.depth.writemask); + OUT_RING(chan, nvfx->framebuffer.zsbuf && nvfx->zsa->pipe.depth.enabled); + } - /* TODO: could nv30 need this or something similar too? */ - if((dirty & (NVFX_NEW_FRAGPROG | NVFX_NEW_SAMPLER)) && nvfx->is_nv4x) { - WAIT_RING(chan, 4); - OUT_RING(chan, RING_3D(NV40TCL_TEX_CACHE_CTL, 1)); - OUT_RING(chan, 2); - OUT_RING(chan, RING_3D(NV40TCL_TEX_CACHE_CTL, 1)); - OUT_RING(chan, 1); + if(flush_tex_cache) + { + // TODO: what about nv30? + if(nvfx->is_nv4x) + { + WAIT_RING(chan, 4); + OUT_RING(chan, RING_3D(NV40TCL_TEX_CACHE_CTL, 1)); + OUT_RING(chan, 2); + OUT_RING(chan, RING_3D(NV40TCL_TEX_CACHE_CTL, 1)); + OUT_RING(chan, 1); + } } - nvfx->dirty = 0; + + nvfx->dirty = dirty & still_dirty; + + render_temps = nvfx->state.render_temps; + if(render_temps) + { + for(int i = 0; i < nvfx->framebuffer.nr_cbufs; ++i) + { + if(render_temps & (1 << i)) + util_dirty_surface_set_dirty(nvfx_surface_get_dirty_surfaces(nvfx->framebuffer.cbufs[i]), + (struct util_dirty_surface*)nvfx->framebuffer.cbufs[i]); + } + + if(render_temps & 0x80) + util_dirty_surface_set_dirty(nvfx_surface_get_dirty_surfaces(nvfx->framebuffer.zsbuf), + (struct util_dirty_surface*)nvfx->framebuffer.zsbuf); + } + return TRUE; } -void -nvfx_state_emit(struct nvfx_context *nvfx) +inline void +nvfx_state_relocate(struct nvfx_context *nvfx, unsigned relocs) { struct nouveau_channel* chan = nvfx->screen->base.channel; /* we need to ensure there is enough space to output relocations in one go */ - unsigned max_relocs = 0 + const unsigned max_relocs = 0 + 16 /* vertex buffers, incl. dma flag */ + 2 /* index buffer plus format+dma flag */ + 2 * 5 /* 4 cbufs + zsbuf, plus dma objects */ @@ -97,18 +258,19 @@ nvfx_state_emit(struct nvfx_context *nvfx) + 2 * 4 /* vertex textures plus format+dma flag */ + 1 /* fragprog incl dma flag */ ; + MARK_RING(chan, max_relocs * 2, max_relocs * 2); - nvfx_state_relocate(nvfx); -} -void -nvfx_state_relocate(struct nvfx_context *nvfx) -{ - nvfx_framebuffer_relocate(nvfx); - nvfx_fragtex_relocate(nvfx); - nvfx_fragprog_relocate(nvfx); - if (nvfx->render_mode == HW) + if(relocs & NVFX_RELOCATE_FRAMEBUFFER) + nvfx_framebuffer_relocate(nvfx); + if(relocs & NVFX_RELOCATE_FRAGTEX) + nvfx_fragtex_relocate(nvfx); + if(relocs & NVFX_RELOCATE_FRAGPROG) + nvfx_fragprog_relocate(nvfx); + if(relocs & NVFX_RELOCATE_VTXBUF) nvfx_vbo_relocate(nvfx); + if(relocs & NVFX_RELOCATE_IDXBUF) + nvfx_idxbuf_relocate(nvfx); } boolean @@ -173,6 +335,9 @@ nvfx_state_validate_swtnl(struct nvfx_context *nvfx) draw_set_vertex_elements(draw, nvfx->vtxelt->num_elements, nvfx->vtxelt->pipe); } + if (nvfx->draw_dirty & NVFX_NEW_INDEX) + draw_set_index_buffer(draw, &nvfx->idxbuf); + nvfx_state_validate_common(nvfx); nvfx->draw_dirty = 0; diff --git a/src/gallium/drivers/nvfx/nvfx_state_fb.c b/src/gallium/drivers/nvfx/nvfx_state_fb.c index 360e569f77..3b869d43a1 100644 --- a/src/gallium/drivers/nvfx/nvfx_state_fb.c +++ b/src/gallium/drivers/nvfx/nvfx_state_fb.c @@ -1,21 +1,55 @@ #include "nvfx_context.h" #include "nvfx_resource.h" -#include "nouveau/nouveau_util.h" +#include "util/u_format.h" +static inline boolean +nvfx_surface_linear_renderable(struct pipe_surface* surf) +{ + return (surf->texture->flags & NVFX_RESOURCE_FLAG_LINEAR) + && !(surf->offset & 63) + && !(((struct nvfx_surface*)surf)->pitch & 63); +} +static inline boolean +nvfx_surface_swizzled_renderable(struct pipe_framebuffer_state* fb, struct pipe_surface* surf) +{ + /* TODO: return FALSE if we have a format not supporting swizzled rendering (e.g. r8); currently those are not supported at all */ + return !((struct nvfx_miptree*)surf->texture)->linear_pitch + && (surf->texture->target != PIPE_TEXTURE_3D || u_minify(surf->texture->depth0, surf->level) <= 1) + && !(surf->offset & 127) + && (surf->width == fb->width) + && (surf->height == fb->height) + && !((struct nvfx_surface*)surf)->temp; +} -void -nvfx_state_framebuffer_validate(struct nvfx_context *nvfx) +static boolean +nvfx_surface_get_render_target(struct pipe_surface* surf, int all_swizzled, struct nvfx_render_target* target) +{ + struct nvfx_surface* ns = (struct nvfx_surface*)surf; + if(!ns->temp) + { + target->bo = ((struct nvfx_miptree*)surf->texture)->base.bo; + target->offset = surf->offset; + target->pitch = align(ns->pitch, 64); + assert(target->pitch); + return FALSE; + } + else + { + target->offset = 0; + target->pitch = ns->temp->linear_pitch; + target->bo = ns->temp->base.bo; + assert(target->pitch); + return TRUE; + } +} + +int +nvfx_framebuffer_prepare(struct nvfx_context *nvfx) { struct pipe_framebuffer_state *fb = &nvfx->framebuffer; - struct nouveau_channel *chan = nvfx->screen->base.channel; - uint32_t rt_enable = 0, rt_format = 0; - int i, colour_format = 0, zeta_format = 0; - int depth_only = 0; - unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM; - unsigned w = fb->width; - unsigned h = fb->height; - int colour_bits = 32, zeta_bits = 32; + int i, color_format = 0, zeta_format = 0; + int all_swizzled = 1; if(!nvfx->is_nv4x) assert(fb->nr_cbufs <= 2); @@ -23,113 +57,135 @@ nvfx_state_framebuffer_validate(struct nvfx_context *nvfx) assert(fb->nr_cbufs <= 4); for (i = 0; i < fb->nr_cbufs; i++) { - if (colour_format) - assert(colour_format == fb->cbufs[i]->format); - else - colour_format = fb->cbufs[i]->format; - - rt_enable |= (NV34TCL_RT_ENABLE_COLOR0 << i); - nvfx->hw_rt[i].bo = nvfx_surface_buffer(fb->cbufs[i]); - nvfx->hw_rt[i].offset = fb->cbufs[i]->offset; - nvfx->hw_rt[i].pitch = ((struct nv04_surface *)fb->cbufs[i])->pitch; + if (color_format) { + if(color_format != fb->cbufs[i]->format) + return -1; + } else + color_format = fb->cbufs[i]->format; + + if(!nvfx_surface_swizzled_renderable(fb, fb->cbufs[i])) + all_swizzled = 0; } - for(; i < 4; ++i) - nvfx->hw_rt[i].bo = 0; + if (fb->zsbuf) { + /* TODO: return FALSE if we have a format not supporting a depth buffer (e.g. r8); currently those are not supported at all */ + if(!nvfx_surface_swizzled_renderable(fb, fb->zsbuf)) + all_swizzled = 0; + + if(all_swizzled && util_format_get_blocksize(color_format) != util_format_get_blocksize(zeta_format)) + all_swizzled = 0; + } + + for (i = 0; i < fb->nr_cbufs; i++) { + if(!((struct nvfx_surface*)fb->cbufs[i])->temp && !all_swizzled && !nvfx_surface_linear_renderable(fb->cbufs[i])) + nvfx_surface_create_temp(&nvfx->pipe, fb->cbufs[i]); + } + + if(fb->zsbuf) { + if(!((struct nvfx_surface*)fb->zsbuf)->temp && !all_swizzled && !nvfx_surface_linear_renderable(fb->zsbuf)) + nvfx_surface_create_temp(&nvfx->pipe, fb->zsbuf); + } + + return all_swizzled; +} + +void +nvfx_framebuffer_validate(struct nvfx_context *nvfx, unsigned prepare_result) +{ + struct pipe_framebuffer_state *fb = &nvfx->framebuffer; + struct nouveau_channel *chan = nvfx->screen->base.channel; + uint32_t rt_enable, rt_format; + int i; + unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM; + unsigned w = fb->width; + unsigned h = fb->height; + + rt_enable = (NV34TCL_RT_ENABLE_COLOR0 << fb->nr_cbufs) - 1; if (rt_enable & (NV34TCL_RT_ENABLE_COLOR1 | NV40TCL_RT_ENABLE_COLOR2 | NV40TCL_RT_ENABLE_COLOR3)) rt_enable |= NV34TCL_RT_ENABLE_MRT; + nvfx->state.render_temps = 0; + + for (i = 0; i < fb->nr_cbufs; i++) + nvfx->state.render_temps |= nvfx_surface_get_render_target(fb->cbufs[i], prepare_result, &nvfx->hw_rt[i]) << i; + + for(; i < 4; ++i) + nvfx->hw_rt[i].bo = 0; + if (fb->zsbuf) { - zeta_format = fb->zsbuf->format; - nvfx->hw_zeta.bo = nvfx_surface_buffer(fb->zsbuf); - nvfx->hw_zeta.offset = fb->zsbuf->offset; - nvfx->hw_zeta.pitch = ((struct nv04_surface *)fb->zsbuf)->pitch; - } - else - nvfx->hw_zeta.bo = 0; - - if (rt_enable & (NV34TCL_RT_ENABLE_COLOR0 | NV34TCL_RT_ENABLE_COLOR1 | - NV40TCL_RT_ENABLE_COLOR2 | NV40TCL_RT_ENABLE_COLOR3)) { - /* Render to at least a colour buffer */ - if (!(fb->cbufs[0]->texture->flags & NVFX_RESOURCE_FLAG_LINEAR)) { - assert(!(fb->width & (fb->width - 1)) && !(fb->height & (fb->height - 1))); - for (i = 1; i < fb->nr_cbufs; i++) - assert(!(fb->cbufs[i]->texture->flags & NVFX_RESOURCE_FLAG_LINEAR)); - - rt_format = NV34TCL_RT_FORMAT_TYPE_SWIZZLED | - (log2i(fb->cbufs[0]->width) << NV34TCL_RT_FORMAT_LOG2_WIDTH_SHIFT) | - (log2i(fb->cbufs[0]->height) << NV34TCL_RT_FORMAT_LOG2_HEIGHT_SHIFT); - } - else - rt_format = NV34TCL_RT_FORMAT_TYPE_LINEAR; - } else if (fb->zsbuf) { - depth_only = 1; - - /* Render to depth buffer only */ - if (!(fb->zsbuf->texture->usage & NVFX_RESOURCE_FLAG_LINEAR)) { - assert(!(fb->width & (fb->width - 1)) && !(fb->height & (fb->height - 1))); - - rt_format = NV34TCL_RT_FORMAT_TYPE_SWIZZLED | - (log2i(fb->zsbuf->width) << NV34TCL_RT_FORMAT_LOG2_WIDTH_SHIFT) | - (log2i(fb->zsbuf->height) << NV34TCL_RT_FORMAT_LOG2_HEIGHT_SHIFT); - } - else - rt_format = NV34TCL_RT_FORMAT_TYPE_LINEAR; - } else { - return; + nvfx->state.render_temps |= nvfx_surface_get_render_target(fb->zsbuf, prepare_result, &nvfx->hw_zeta) << 7; + + assert(util_format_get_stride(fb->zsbuf->format, fb->width) <= nvfx->hw_zeta.pitch); + assert(nvfx->hw_zeta.offset + nvfx->hw_zeta.pitch * fb->height <= nvfx->hw_zeta.bo->size); } - switch (colour_format) { - case PIPE_FORMAT_B8G8R8X8_UNORM: - rt_format |= NV34TCL_RT_FORMAT_COLOR_X8R8G8B8; - break; - case PIPE_FORMAT_B8G8R8A8_UNORM: - case 0: - rt_format |= NV34TCL_RT_FORMAT_COLOR_A8R8G8B8; - break; - case PIPE_FORMAT_B5G6R5_UNORM: + if (prepare_result) { + assert(!(fb->width & (fb->width - 1)) && !(fb->height & (fb->height - 1))); + + rt_format = NV34TCL_RT_FORMAT_TYPE_SWIZZLED | + (util_logbase2(fb->width) << NV34TCL_RT_FORMAT_LOG2_WIDTH_SHIFT) | + (util_logbase2(fb->height) << NV34TCL_RT_FORMAT_LOG2_HEIGHT_SHIFT); + } else + rt_format = NV34TCL_RT_FORMAT_TYPE_LINEAR; + + if(fb->nr_cbufs > 0) { + switch (fb->cbufs[0]->format) { + case PIPE_FORMAT_B8G8R8X8_UNORM: + rt_format |= NV34TCL_RT_FORMAT_COLOR_X8R8G8B8; + break; + case PIPE_FORMAT_B8G8R8A8_UNORM: + case 0: + rt_format |= NV34TCL_RT_FORMAT_COLOR_A8R8G8B8; + break; + case PIPE_FORMAT_B5G6R5_UNORM: + rt_format |= NV34TCL_RT_FORMAT_COLOR_R5G6B5; + break; + default: + assert(0); + } + } else if(fb->zsbuf && util_format_get_blocksize(fb->zsbuf->format) == 2) rt_format |= NV34TCL_RT_FORMAT_COLOR_R5G6B5; - colour_bits = 16; - break; - default: - assert(0); - } + else + rt_format |= NV34TCL_RT_FORMAT_COLOR_A8R8G8B8; - switch (zeta_format) { - case PIPE_FORMAT_Z16_UNORM: + if(fb->zsbuf) { + switch (fb->zsbuf->format) { + case PIPE_FORMAT_Z16_UNORM: + rt_format |= NV34TCL_RT_FORMAT_ZETA_Z16; + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + case PIPE_FORMAT_X8Z24_UNORM: + case 0: + rt_format |= NV34TCL_RT_FORMAT_ZETA_Z24S8; + break; + default: + assert(0); + } + } else if(fb->nr_cbufs && util_format_get_blocksize(fb->cbufs[0]->format) == 2) rt_format |= NV34TCL_RT_FORMAT_ZETA_Z16; - zeta_bits = 16; - break; - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - case PIPE_FORMAT_X8Z24_UNORM: - case 0: + else rt_format |= NV34TCL_RT_FORMAT_ZETA_Z24S8; - break; - default: - assert(0); - } - if ((!nvfx->is_nv4x) && colour_bits > zeta_bits) { - /* TODO: does this limitation really exist? - TODO: can it be worked around somehow? */ - assert(0); - } + if ((rt_enable & NV34TCL_RT_ENABLE_COLOR0) || fb->zsbuf) { + struct nvfx_render_target *rt0 = &nvfx->hw_rt[0]; + uint32_t pitch; - if ((rt_enable & NV34TCL_RT_ENABLE_COLOR0) - || ((!nvfx->is_nv4x) && depth_only)) { - struct nvfx_render_target *rt0 = (depth_only ? &nvfx->hw_zeta : &nvfx->hw_rt[0]); - uint32_t pitch = rt0->pitch; + if(!(rt_enable & NV34TCL_RT_ENABLE_COLOR0)) + rt0 = &nvfx->hw_zeta; + + pitch = rt0->pitch; if(!nvfx->is_nv4x) { - if (nvfx->hw_zeta.bo) { + if (nvfx->hw_zeta.bo) pitch |= (nvfx->hw_zeta.pitch << 16); - } else { + else pitch |= (pitch << 16); - } } + //printf("rendering to bo %p [%i] at offset %i with pitch %i\n", rt0->bo, rt0->bo->handle, rt0->offset, pitch); + OUT_RING(chan, RING_3D(NV34TCL_DMA_COLOR0, 1)); OUT_RELOC(chan, rt0->bo, 0, rt_flags | NOUVEAU_BO_OR, @@ -182,7 +238,7 @@ nvfx_state_framebuffer_validate(struct nvfx_context *nvfx) } } - if (zeta_format) { + if (fb->zsbuf) { OUT_RING(chan, RING_3D(NV34TCL_DMA_ZETA, 1)); OUT_RELOC(chan, nvfx->hw_zeta.bo, 0, rt_flags | NOUVEAU_BO_OR, @@ -196,6 +252,10 @@ nvfx_state_framebuffer_validate(struct nvfx_context *nvfx) OUT_RING(chan, nvfx->hw_zeta.pitch); } } + else if(nvfx->is_nv4x) { + OUT_RING(chan, RING_3D(NV40TCL_ZETA_PITCH, 1)); + OUT_RING(chan, 64); + } OUT_RING(chan, RING_3D(NV34TCL_RT_ENABLE, 1)); OUT_RING(chan, rt_enable); @@ -218,6 +278,7 @@ nvfx_state_framebuffer_validate(struct nvfx_context *nvfx) OUT_RING(chan, RING_3D(NV34TCL_VIEWPORT_TX_ORIGIN, 1)); OUT_RING(chan, 0); } + nvfx->relocs_needed &=~ NVFX_RELOCATE_FRAMEBUFFER; } void @@ -247,4 +308,5 @@ nvfx_framebuffer_relocate(struct nvfx_context *nvfx) DO(NV40, 3); DO_(nvfx->hw_zeta, NV34, ZETA); + nvfx->relocs_needed &=~ NVFX_RELOCATE_FRAMEBUFFER; } diff --git a/src/gallium/drivers/nvfx/nvfx_state_stipple.c b/src/gallium/drivers/nvfx/nvfx_state_stipple.c index 4da968f093..b76e9dd382 100644 --- a/src/gallium/drivers/nvfx/nvfx_state_stipple.c +++ b/src/gallium/drivers/nvfx/nvfx_state_stipple.c @@ -4,23 +4,8 @@ void nvfx_state_stipple_validate(struct nvfx_context *nvfx) { struct nouveau_channel *chan = nvfx->screen->base.channel; - struct pipe_rasterizer_state *rast = &nvfx->rasterizer->pipe; - if ((rast->poly_stipple_enable == 0 && nvfx->state.stipple_enabled == 0)) - return; - - if (rast->poly_stipple_enable) { - unsigned i; - - WAIT_RING(chan, 35); - OUT_RING(chan, RING_3D(NV34TCL_POLYGON_STIPPLE_ENABLE, 1)); - OUT_RING(chan, 1); - OUT_RING(chan, RING_3D(NV34TCL_POLYGON_STIPPLE_PATTERN(0), 32)); - for (i = 0; i < 32; i++) - OUT_RING(chan, nvfx->stipple[i]); - } else { - WAIT_RING(chan, 2); - OUT_RING(chan, RING_3D(NV34TCL_POLYGON_STIPPLE_ENABLE, 1)); - OUT_RING(chan, 0); - } + WAIT_RING(chan, 33); + OUT_RING(chan, RING_3D(NV34TCL_POLYGON_STIPPLE_PATTERN(0), 32)); + OUT_RINGp(chan, nvfx->stipple, 32); } diff --git a/src/gallium/drivers/nvfx/nvfx_surface.c b/src/gallium/drivers/nvfx/nvfx_surface.c index a605d2b754..a5931b6e15 100644 --- a/src/gallium/drivers/nvfx/nvfx_surface.c +++ b/src/gallium/drivers/nvfx/nvfx_surface.c @@ -26,33 +26,421 @@ * **************************************************************************/ +#include "pipe/p_context.h" +#include "pipe/p_format.h" +#include "util/u_format.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "util/u_pack_color.h" +#include "util/u_blitter.h" + +#include "nouveau/nouveau_winsys.h" +#include "nouveau/nouveau_screen.h" #include "nvfx_context.h" +#include "nvfx_screen.h" #include "nvfx_resource.h" -#include "pipe/p_defines.h" -#include "util/u_inlines.h" -#include "util/u_pack_color.h" +#include "nv04_2d.h" + +#include <nouveau/nouveau_bo.h> + +static INLINE void +nvfx_region_set_format(struct nv04_region* rgn, enum pipe_format format) +{ + unsigned bits = util_format_get_blocksizebits(format); + switch(bits) + { + case 8: + rgn->bpps = 0; + break; + case 16: + rgn->bpps = 1; + break; + case 32: + rgn->bpps = 2; + break; + default: + { + int shift; + assert(util_is_power_of_two(bits)); + shift = util_logbase2(bits) - 3; + assert(shift >= 2); + rgn->bpps = 2; + shift -= 2; + + rgn->x = util_format_get_nblocksx(format, rgn->x) << shift; + rgn->y = util_format_get_nblocksy(format, rgn->y); + } + } +} + +static INLINE void +nvfx_region_fixup_swizzled(struct nv04_region* rgn, unsigned zslice, unsigned width, unsigned height, unsigned depth) +{ + // TODO: move this code to surface creation? + if((depth <= 1) && (height <= 1 || width <= 2)) + rgn->pitch = width << rgn->bpps; + else if(depth > 1 && height <= 2 && width <= 2) + { + rgn->pitch = width << rgn->bpps; + rgn->offset += (zslice * width * height) << rgn->bpps; + } + else + { + rgn->pitch = 0; + rgn->z = zslice; + rgn->w = width; + rgn->h = height; + rgn->d = depth; + } +} + +static INLINE void +nvfx_region_init_for_surface(struct nv04_region* rgn, struct nvfx_surface* surf, unsigned x, unsigned y, bool for_write) +{ + rgn->x = x; + rgn->y = y; + rgn->z = 0; + nvfx_region_set_format(rgn, surf->base.base.format); + + if(surf->temp) + { + rgn->bo = surf->temp->base.bo; + rgn->offset = 0; + rgn->pitch = surf->temp->linear_pitch; + + if(for_write) + util_dirty_surface_set_dirty(nvfx_surface_get_dirty_surfaces(&surf->base.base), &surf->base); + } else { + rgn->bo = ((struct nvfx_resource*)surf->base.base.texture)->bo; + rgn->offset = surf->base.base.offset; + rgn->pitch = surf->pitch; + + if(!(surf->base.base.texture->flags & NVFX_RESOURCE_FLAG_LINEAR)) + nvfx_region_fixup_swizzled(rgn, surf->base.base.zslice, surf->base.base.width, surf->base.base.height, u_minify(surf->base.base.texture->depth0, surf->base.base.level)); + } +} + +static INLINE void +nvfx_region_init_for_subresource(struct nv04_region* rgn, struct pipe_resource* pt, struct pipe_subresource sub, unsigned x, unsigned y, unsigned z, bool for_write) +{ + if(pt->target != PIPE_BUFFER) + { + struct nvfx_surface* ns = (struct nvfx_surface*)util_surfaces_peek(&((struct nvfx_miptree*)pt)->surfaces, pt, sub.face, sub.level, z); + if(ns && util_dirty_surface_is_dirty(&ns->base)) + { + nvfx_region_init_for_surface(rgn, ns, x, y, for_write); + return; + } + } + + rgn->bo = ((struct nvfx_resource*)pt)->bo; + rgn->offset = nvfx_subresource_offset(pt, sub.face, sub.level, z); + rgn->pitch = nvfx_subresource_pitch(pt, sub.level); + rgn->x = x; + rgn->y = y; + rgn->z = 0; + + nvfx_region_set_format(rgn, pt->format); + if(!(pt->flags & NVFX_RESOURCE_FLAG_LINEAR)) + nvfx_region_fixup_swizzled(rgn, z, u_minify(pt->width0, sub.level), u_minify(pt->height0, sub.level), u_minify(pt->depth0, sub.level)); +} + +// TODO: actually test this for all formats, it's probably wrong for some... + +static INLINE int +nvfx_surface_format(enum pipe_format format) +{ + switch(util_format_get_blocksize(format)) { + case 1: + return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8; + case 2: + //return NV04_CONTEXT_SURFACES_2D_FORMAT_Y16; + return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5; + case 4: + //if(format == PIPE_FORMAT_B8G8R8X8_UNORM || format == PIPE_FORMAT_B8G8R8A8_UNORM) + return NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8; + //else + // return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32; + default: + return -1; + } +} + +static INLINE int +nv04_scaled_image_format(enum pipe_format format) +{ + switch(util_format_get_blocksize(format)) { + case 1: + return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_Y8; + case 2: + //if(format == PIPE_FORMAT_B5G5R5A1_UNORM) + // return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A1R5G5B5; + //else + return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_R5G6B5; + case 4: + if(format == PIPE_FORMAT_B8G8R8X8_UNORM) + return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_X8R8G8B8; + else + return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A8R8G8B8; + default: + return -1; + } +} + +// XXX: must save index buffer too! +static struct blitter_context* +nvfx_get_blitter(struct pipe_context* pipe, int copy) +{ + struct nvfx_context* nvfx = nvfx_context(pipe); + + struct blitter_context* blitter = nvfx->blitter; + if(!blitter) + nvfx->blitter = blitter = util_blitter_create(pipe); + + util_blitter_save_blend(blitter, nvfx->blend); + util_blitter_save_depth_stencil_alpha(blitter, nvfx->zsa); + util_blitter_save_stencil_ref(blitter, &nvfx->stencil_ref); + util_blitter_save_rasterizer(blitter, nvfx->rasterizer); + util_blitter_save_fragment_shader(blitter, nvfx->fragprog); + util_blitter_save_vertex_shader(blitter, nvfx->vertprog); + util_blitter_save_viewport(blitter, &nvfx->viewport); + util_blitter_save_framebuffer(blitter, &nvfx->framebuffer); + util_blitter_save_clip(blitter, &nvfx->clip); + util_blitter_save_vertex_elements(blitter, nvfx->vtxelt); + util_blitter_save_vertex_buffers(blitter, nvfx->vtxbuf_nr, nvfx->vtxbuf); + + if(copy) + { + util_blitter_save_fragment_sampler_states(blitter, nvfx->nr_samplers, (void**)nvfx->tex_sampler); + util_blitter_save_fragment_sampler_views(blitter, nvfx->nr_textures, nvfx->fragment_sampler_views); + } + + return blitter; +} + +static unsigned +nvfx_region_clone(struct nv04_2d_context* ctx, struct nv04_region* rgn, unsigned w, unsigned h, boolean for_read) +{ + unsigned begin = nv04_region_begin(rgn, w, h); + unsigned end = nv04_region_end(rgn, w, h); + unsigned size = end - begin; + struct nouveau_bo* bo = 0; + nouveau_bo_new(rgn->bo->device, NOUVEAU_BO_MAP | NOUVEAU_BO_GART, 256, size, &bo); + + if(for_read || (size > ((w * h) << rgn->bpps))) + nv04_memcpy(ctx, bo, 0, rgn->bo, rgn->offset + begin, size); + + rgn->bo = bo; + rgn->offset = -begin; + return begin; +} static void -nvfx_surface_copy(struct pipe_context *pipe, - struct pipe_resource *dest, struct pipe_subresource subdst, - unsigned destx, unsigned desty, unsigned destz, - struct pipe_resource *src, struct pipe_subresource subsrc, +nvfx_resource_copy_region(struct pipe_context *pipe, + struct pipe_resource *dstr, struct pipe_subresource subdst, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_resource *srcr, struct pipe_subresource subsrc, unsigned srcx, unsigned srcy, unsigned srcz, - unsigned width, unsigned height) + unsigned w, unsigned h) { - struct nvfx_context *nvfx = nvfx_context(pipe); - struct nv04_surface_2d *eng2d = nvfx->screen->eng2d; - struct pipe_surface *ps_dst, *ps_src; + static int copy_threshold = -1; + struct nv04_2d_context *ctx = nvfx_screen(pipe->screen)->eng2d; + struct nv04_region dst, src; + int dst_to_gpu; + int src_on_gpu; + boolean small; + int ret; + + if(!w || !h) + return; + + if(copy_threshold < 0) + copy_threshold = debug_get_num_option("NOUVEAU_COPY_THRESHOLD", 4); + + dst_to_gpu = dstr->usage != PIPE_USAGE_DYNAMIC && dstr->usage != PIPE_USAGE_STAGING; + src_on_gpu = nvfx_resource_on_gpu(srcr); + + nvfx_region_init_for_subresource(&dst, dstr, subdst, dstx, dsty, dstz, TRUE); + nvfx_region_init_for_subresource(&src, srcr, subsrc, srcx, srcy, srcz, FALSE); + w = util_format_get_stride(dstr->format, w) >> dst.bpps; + h = util_format_get_nblocksy(dstr->format, h); - ps_src = nvfx_miptree_surface_new(pipe->screen, src, subsrc.face, - subsrc.level, srcz, 0 /* bind flags */); - ps_dst = nvfx_miptree_surface_new(pipe->screen, dest, subdst.face, - subdst.level, destz, 0 /* bindflags */); + small = (w * h <= copy_threshold); + if((!dst_to_gpu || !src_on_gpu) && small) + ret = -1; /* use the CPU */ + else + ret = nv04_region_copy_2d(ctx, &dst, &src, w, h, + dstr->target == PIPE_BUFFER ? -1 : nvfx_surface_format(dstr->format), + dstr->target == PIPE_BUFFER ? -1 : nv04_scaled_image_format(dstr->format), + dst_to_gpu, src_on_gpu); + if(!ret) + {} + else if(ret > 0 && dstr->bind & PIPE_BIND_RENDER_TARGET && srcr->bind & PIPE_BIND_SAMPLER_VIEW) + { + struct blitter_context* blitter = nvfx_get_blitter(pipe, 1); + util_blitter_copy_region(blitter, dstr, subdst, dstx, dsty, dstz, srcr, subsrc, srcx, srcy, srcz, w, h, TRUE); + } + else + { + struct nv04_region dstt = dst; + struct nv04_region srct = src; + unsigned dstbegin = 0; - eng2d->copy(eng2d, ps_dst, destx, desty, ps_src, srcx, srcy, width, height); + if(!small) + { + if(src_on_gpu) + nvfx_region_clone(ctx, &srct, w, h, TRUE); - nvfx_miptree_surface_del(ps_src); - nvfx_miptree_surface_del(ps_dst); + if(dst_to_gpu) + dstbegin = nvfx_region_clone(ctx, &dstt, w, h, FALSE); + } + + nv04_region_copy_cpu(&dstt, &srct, w, h); + + if(srct.bo != src.bo) + nouveau_screen_bo_release(pipe->screen, srct.bo); + + if(dstt.bo != dst.bo) + { + nv04_memcpy(ctx, dst.bo, dst.offset + dstbegin, dstt.bo, 0, dstt.bo->size); + nouveau_screen_bo_release(pipe->screen, dstt.bo); + } + } +} + +static int +nvfx_surface_fill(struct pipe_context* pipe, struct pipe_surface *dsts, + unsigned dx, unsigned dy, unsigned w, unsigned h, unsigned value) +{ + struct nv04_2d_context *ctx = nvfx_screen(pipe->screen)->eng2d; + struct nv04_region dst; + int ret; + /* Always try to use the GPU right now, if possible + * If the user wanted the surface data on the CPU, he would have cleared with memset (hopefully) */ + + // we don't care about interior pixel order since we set all them to the same value + nvfx_region_init_for_surface(&dst, (struct nvfx_surface*)dsts, dx, dy, TRUE); + + w = util_format_get_stride(dsts->format, w) >> dst.bpps; + h = util_format_get_nblocksy(dsts->format, h); + + ret = nv04_region_fill_2d(ctx, &dst, w, h, value); + if(ret > 0 && dsts->texture->bind & PIPE_BIND_RENDER_TARGET) + return 1; + else if(ret) + { + struct nv04_region dstt = dst; + unsigned dstbegin = 0; + + if(nvfx_resource_on_gpu(dsts->texture)) + dstbegin = nvfx_region_clone(ctx, &dstt, w, h, FALSE); + + nv04_region_fill_cpu(&dstt, w, h, value); + + if(dstt.bo != dst.bo) + { + nv04_memcpy(ctx, dst.bo, dst.offset + dstbegin, dstt.bo, 0, dstt.bo->size); + nouveau_screen_bo_release(pipe->screen, dstt.bo); + } + } + + return 0; +} + + +void +nvfx_screen_surface_takedown(struct pipe_screen *pscreen) +{ + nv04_2d_context_takedown(nvfx_screen(pscreen)->eng2d); + nvfx_screen(pscreen)->eng2d = 0; +} + +int +nvfx_screen_surface_init(struct pipe_screen *pscreen) +{ + struct nv04_2d_context* ctx = nv04_2d_context_init(nouveau_screen(pscreen)->channel); + if(!ctx) + return -1; + nvfx_screen(pscreen)->eng2d = ctx; + return 0; +} + +static void +nvfx_surface_copy_temp(struct pipe_context* pipe, struct pipe_surface* surf, int to_temp) +{ + struct nvfx_surface* ns = (struct nvfx_surface*)surf; + struct pipe_subresource tempsr, surfsr; + struct nvfx_context* nvfx = nvfx_context(pipe); + + // TODO: we really should do this validation before setting these variable in draw calls + unsigned use_vertex_buffers = nvfx->use_vertex_buffers; + boolean use_index_buffer = nvfx->use_index_buffer; + unsigned base_vertex = nvfx->base_vertex; + + tempsr.face = 0; + tempsr.level = 0; + surfsr.face = surf->face; + surfsr.level = surf->level; + + if(to_temp) + nvfx_resource_copy_region(pipe, &ns->temp->base.base, tempsr, 0, 0, 0, surf->texture, surfsr, 0, 0, surf->zslice, surf->width, surf->height); + else + nvfx_resource_copy_region(pipe, surf->texture, surfsr, 0, 0, surf->zslice, &ns->temp->base.base, tempsr, 0, 0, 0, surf->width, surf->height); + + nvfx->use_vertex_buffers = use_vertex_buffers; + nvfx->use_index_buffer = use_index_buffer; + nvfx->base_vertex = base_vertex; + + nvfx->dirty |= NVFX_NEW_ARRAYS; + nvfx->draw_dirty |= NVFX_NEW_ARRAYS; +} + +void +nvfx_surface_create_temp(struct pipe_context* pipe, struct pipe_surface* surf) +{ + struct nvfx_surface* ns = (struct nvfx_surface*)surf; + struct pipe_resource template; + memset(&template, 0, sizeof(struct pipe_resource)); + template.target = PIPE_TEXTURE_2D; + template.format = surf->format; + template.width0 = surf->width; + template.height0 = surf->height; + template.depth0 = 1; + template.nr_samples = surf->texture->nr_samples; + template.flags = NVFX_RESOURCE_FLAG_LINEAR; + + ns->temp = (struct nvfx_miptree*)nvfx_miptree_create(pipe->screen, &template); + nvfx_surface_copy_temp(pipe, surf, 1); +} + +void +nvfx_surface_flush(struct pipe_context* pipe, struct pipe_surface* surf) +{ + struct nvfx_context* nvfx = (struct nvfx_context*)pipe; + struct nvfx_surface* ns = (struct nvfx_surface*)surf; + boolean bound = FALSE; + + /* must be done before the copy, otherwise the copy will use the temp as destination */ + util_dirty_surface_set_clean(nvfx_surface_get_dirty_surfaces(surf), &ns->base); + + nvfx_surface_copy_temp(pipe, surf, 0); + + if(nvfx->framebuffer.zsbuf == surf) + bound = TRUE; + else + { + for(unsigned i = 0; i < nvfx->framebuffer.nr_cbufs; ++i) + { + if(nvfx->framebuffer.cbufs[i] == surf) + { + bound = TRUE; + break; + } + } + } + + if(!bound) + pipe_resource_reference((struct pipe_resource**)&ns->temp, 0); } static void @@ -62,12 +450,16 @@ nvfx_clear_render_target(struct pipe_context *pipe, unsigned dstx, unsigned dsty, unsigned width, unsigned height) { - struct nvfx_context *nvfx = nvfx_context(pipe); - struct nv04_surface_2d *eng2d = nvfx->screen->eng2d; union util_color uc; util_pack_color(rgba, dst->format, &uc); - eng2d->fill(eng2d, dst, dstx, dsty, width, height, uc.ui); + if(util_format_get_blocksizebits(dst->format) > 32 + || nvfx_surface_fill(pipe, dst, dstx, dsty, width, height, uc.ui)) + { + // TODO: probably should use hardware clear here instead if possible + struct blitter_context* blitter = nvfx_get_blitter(pipe, 0); + util_blitter_clear_render_target(blitter, dst, rgba, dstx, dsty, width, height); + } } static void @@ -79,18 +471,20 @@ nvfx_clear_depth_stencil(struct pipe_context *pipe, unsigned dstx, unsigned dsty, unsigned width, unsigned height) { - struct nvfx_context *nvfx = nvfx_context(pipe); - struct nv04_surface_2d *eng2d = nvfx->screen->eng2d; - - eng2d->fill(eng2d, dst, dstx, dsty, width, height, - util_pack_z_stencil(dst->format, depth, stencil)); + if(util_format_get_blocksizebits(dst->format) > 32 + || nvfx_surface_fill(pipe, dst, dstx, dsty, width, height, util_pack_z_stencil(dst->format, depth, stencil))) + { + // TODO: probably should use hardware clear here instead if possible + struct blitter_context* blitter = nvfx_get_blitter(pipe, 0); + util_blitter_clear_depth_stencil(blitter, dst, clear_flags, depth, stencil, dstx, dsty, width, height); + } } void nvfx_init_surface_functions(struct nvfx_context *nvfx) { - nvfx->pipe.resource_copy_region = nvfx_surface_copy; + nvfx->pipe.resource_copy_region = nvfx_resource_copy_region; nvfx->pipe.clear_render_target = nvfx_clear_render_target; nvfx->pipe.clear_depth_stencil = nvfx_clear_depth_stencil; } diff --git a/src/gallium/drivers/nvfx/nvfx_tex.h b/src/gallium/drivers/nvfx/nvfx_tex.h index 69187a79e7..34be936a89 100644 --- a/src/gallium/drivers/nvfx/nvfx_tex.h +++ b/src/gallium/drivers/nvfx/nvfx_tex.h @@ -1,6 +1,11 @@ #ifndef NVFX_TEX_H_ #define NVFX_TEX_H_ +#include "util/u_math.h" +#include "pipe/p_defines.h" +#include "pipe/p_state.h" +#include <nouveau/nouveau_class.h> + static inline unsigned nvfx_tex_wrap_mode(unsigned wrap) { unsigned ret; @@ -31,7 +36,7 @@ nvfx_tex_wrap_mode(unsigned wrap) { ret = NV40TCL_TEX_WRAP_S_MIRROR_CLAMP; break; default: - NOUVEAU_ERR("unknown wrap mode: %d\n", wrap); + assert(0); ret = NV34TCL_TX_WRAP_S_REPEAT; break; } @@ -40,31 +45,29 @@ nvfx_tex_wrap_mode(unsigned wrap) { } static inline unsigned -nvfx_tex_wrap_compare_mode(const struct pipe_sampler_state* cso) +nvfx_tex_wrap_compare_mode(unsigned func) { - if (cso->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { - switch (cso->compare_func) { - case PIPE_FUNC_NEVER: - return NV34TCL_TX_WRAP_RCOMP_NEVER; - case PIPE_FUNC_GREATER: - return NV34TCL_TX_WRAP_RCOMP_GREATER; - case PIPE_FUNC_EQUAL: - return NV34TCL_TX_WRAP_RCOMP_EQUAL; - case PIPE_FUNC_GEQUAL: - return NV34TCL_TX_WRAP_RCOMP_GEQUAL; - case PIPE_FUNC_LESS: - return NV34TCL_TX_WRAP_RCOMP_LESS; - case PIPE_FUNC_NOTEQUAL: - return NV34TCL_TX_WRAP_RCOMP_NOTEQUAL; - case PIPE_FUNC_LEQUAL: - return NV34TCL_TX_WRAP_RCOMP_LEQUAL; - case PIPE_FUNC_ALWAYS: - return NV34TCL_TX_WRAP_RCOMP_ALWAYS; - default: - break; - } + switch (func) { + case PIPE_FUNC_NEVER: + return NV34TCL_TX_WRAP_RCOMP_NEVER; + case PIPE_FUNC_GREATER: + return NV34TCL_TX_WRAP_RCOMP_GREATER; + case PIPE_FUNC_EQUAL: + return NV34TCL_TX_WRAP_RCOMP_EQUAL; + case PIPE_FUNC_GEQUAL: + return NV34TCL_TX_WRAP_RCOMP_GEQUAL; + case PIPE_FUNC_LESS: + return NV34TCL_TX_WRAP_RCOMP_LESS; + case PIPE_FUNC_NOTEQUAL: + return NV34TCL_TX_WRAP_RCOMP_NOTEQUAL; + case PIPE_FUNC_LEQUAL: + return NV34TCL_TX_WRAP_RCOMP_LEQUAL; + case PIPE_FUNC_ALWAYS: + return NV34TCL_TX_WRAP_RCOMP_ALWAYS; + default: + assert(0); + return 0; } - return 0; } static inline unsigned nvfx_tex_filter(const struct pipe_sampler_state* cso) @@ -128,6 +131,45 @@ struct nvfx_sampler_state { uint32_t en; uint32_t filt; uint32_t bcol; + uint32_t min_lod; + uint32_t max_lod; + boolean compare; +}; + +struct nvfx_sampler_view { + struct pipe_sampler_view base; + int offset; + uint32_t swizzle; + uint32_t npot_size; + uint32_t filt; + uint32_t wrap_mask; + uint32_t wrap; + uint32_t lod_offset; + uint32_t max_lod_limit; + union + { + struct + { + uint32_t fmt[4]; /* nv30 has 4 entries, nv40 one */ + int rect; + } nv30; + struct + { + uint32_t fmt[2]; /* nv30 has 4 entries, nv40 one */ + uint32_t npot_size2; /* nv40 only */ + } nv40; + uint32_t init_fmt; + } u; }; +struct nvfx_texture_format { + int fmt[6]; + unsigned sign; + unsigned wrap; + unsigned char src[6]; + unsigned char comp[6]; +}; + +extern struct nvfx_texture_format nvfx_texture_formats[PIPE_FORMAT_COUNT]; + #endif /* NVFX_TEX_H_ */ diff --git a/src/gallium/drivers/nvfx/nvfx_transfer.c b/src/gallium/drivers/nvfx/nvfx_transfer.c index 9ff0a93d30..7cb47a20f6 100644 --- a/src/gallium/drivers/nvfx/nvfx_transfer.c +++ b/src/gallium/drivers/nvfx/nvfx_transfer.c @@ -4,204 +4,218 @@ #include "util/u_format.h" #include "util/u_memory.h" #include "util/u_math.h" -#include "nouveau/nouveau_winsys.h" +#include "util/u_staging.h" #include "nvfx_context.h" #include "nvfx_screen.h" #include "nvfx_state.h" #include "nvfx_resource.h" #include "nvfx_transfer.h" -struct nvfx_transfer { - struct pipe_transfer base; - struct pipe_surface *surface; - boolean direct; -}; - -static void -nvfx_compatible_transfer_tex(struct pipe_resource *pt, unsigned width, unsigned height, - unsigned bind, - struct pipe_resource *template) -{ - memset(template, 0, sizeof(struct pipe_resource)); - template->target = pt->target; - template->format = pt->format; - template->width0 = width; - template->height0 = height; - template->depth0 = 1; - template->last_level = 0; - template->nr_samples = pt->nr_samples; - template->bind = bind; - template->usage = PIPE_USAGE_DYNAMIC; - template->flags = NVFX_RESOURCE_FLAG_LINEAR; -} - - -static unsigned nvfx_transfer_bind_flags( unsigned transfer_usage ) +struct nvfx_staging_transfer { - unsigned bind = 0; + struct util_staging_transfer base; -#if 0 - if (transfer_usage & PIPE_TRANSFER_WRITE) - bind |= PIPE_BIND_BLIT_SOURCE; - - if (transfer_usage & PIPE_TRANSFER_READ) - bind |= PIPE_BIND_BLIT_DESTINATION; -#endif - - return bind; -} + unsigned offset; + unsigned map_count; +}; struct pipe_transfer * -nvfx_miptree_transfer_new(struct pipe_context *pipe, +nvfx_transfer_new(struct pipe_context *pipe, struct pipe_resource *pt, struct pipe_subresource sr, unsigned usage, const struct pipe_box *box) { - struct pipe_screen *pscreen = pipe->screen; - struct nvfx_miptree *mt = (struct nvfx_miptree *)pt; - struct nvfx_transfer *tx; - struct pipe_resource tx_tex_template, *tx_tex; - static int no_transfer = -1; - unsigned bind = nvfx_transfer_bind_flags(usage); - if(no_transfer < 0) - no_transfer = debug_get_bool_option("NOUVEAU_NO_TRANSFER", FALSE); - - - tx = CALLOC_STRUCT(nvfx_transfer); - if (!tx) - return NULL; - - /* Don't handle 3D transfers yet. - */ - assert(box->depth == 1); - - pipe_resource_reference(&tx->base.resource, pt); - tx->base.sr = sr; - tx->base.usage = usage; - tx->base.box = *box; - tx->base.stride = mt->level[sr.level].pitch; - - /* Direct access to texture */ - if ((pt->usage == PIPE_USAGE_DYNAMIC || - no_transfer) && - pt->flags & NVFX_RESOURCE_FLAG_LINEAR) + if((usage & (PIPE_TRANSFER_UNSYNCHRONIZED | PIPE_TRANSFER_DONTBLOCK)) == PIPE_TRANSFER_DONTBLOCK) + { + struct nouveau_bo* bo = ((struct nvfx_resource*)pt)->bo; + if(bo && nouveau_bo_busy(bo, NOUVEAU_BO_WR)) + return NULL; + } + + if(pt->target == PIPE_BUFFER) { - tx->direct = true; - - /* XXX: just call the internal nvfx function. - */ - tx->surface = pscreen->get_tex_surface(pscreen, pt, - sr.face, sr.level, - box->z, - bind); - return &tx->base; - } + // it would be nice if we could avoid all this ridiculous overhead... + struct pipe_transfer* tx; + struct nvfx_buffer* buffer = nvfx_buffer(pt); + + tx = CALLOC_STRUCT(pipe_transfer); + if (!tx) + return NULL; - tx->direct = false; + pipe_resource_reference(&tx->resource, pt); + tx->sr = sr; + tx->usage = usage; + tx->box = *box; - nvfx_compatible_transfer_tex(pt, box->width, box->height, bind, &tx_tex_template); + tx->slice_stride = tx->stride = util_format_get_stride(pt->format, box->width); + tx->data = buffer->data + util_format_get_stride(pt->format, box->x); - tx_tex = pscreen->resource_create(pscreen, &tx_tex_template); - if (!tx_tex) + return tx; + } + else { - FREE(tx); - return NULL; + struct nvfx_staging_transfer* tx; + bool direct = !nvfx_resource_on_gpu(pt) && pt->flags & NVFX_RESOURCE_FLAG_LINEAR; + + tx = CALLOC_STRUCT(nvfx_staging_transfer); + if(!tx) + return NULL; + + util_staging_transfer_init(pipe, pt, sr, usage, box, direct, &tx->base); + + if(direct) + { + tx->base.base.stride = nvfx_subresource_pitch(pt, sr.level); + tx->base.base.slice_stride = tx->base.base.stride * u_minify(pt->height0, sr.level); + tx->offset = nvfx_subresource_offset(pt, sr.face, sr.level, box->z) + + util_format_get_2d_size(pt->format, tx->base.base.stride, box->y) + + util_format_get_stride(pt->format, box->x); + } + else + { + tx->base.base.stride = nvfx_subresource_pitch(tx->base.staging_resource, 0); + tx->base.base.slice_stride = tx->base.base.stride * tx->base.staging_resource->height0; + tx->offset = 0; + } + + assert(tx->base.base.stride); + + return &tx->base.base; } +} - tx->base.stride = ((struct nvfx_miptree*)tx_tex)->level[0].pitch; - - tx->surface = pscreen->get_tex_surface(pscreen, tx_tex, - 0, 0, 0, - bind); - - pipe_resource_reference(&tx_tex, NULL); - - if (!tx->surface) +static void nvfx_buffer_dirty_interval(struct nvfx_buffer* buffer, unsigned begin, unsigned size, boolean unsynchronized) +{ + struct nvfx_screen* screen = nvfx_screen(buffer->base.base.screen); + buffer->last_update_static = buffer->bytes_to_draw_until_static < 0; + if(buffer->dirty_begin == buffer->dirty_end) { - pipe_surface_reference(&tx->surface, NULL); - FREE(tx); - return NULL; + buffer->dirty_begin = begin; + buffer->dirty_end = begin + size; + buffer->dirty_unsynchronized = unsynchronized; + } + else + { + buffer->dirty_begin = MIN2(buffer->dirty_begin, begin); + buffer->dirty_end = MAX2(buffer->dirty_end, begin + size); + buffer->dirty_unsynchronized &= unsynchronized; } - if (usage & PIPE_TRANSFER_READ) { - struct nvfx_screen *nvscreen = nvfx_screen(pscreen); - struct pipe_surface *src; + if(unsynchronized) + { + // TODO: revisit this, it doesn't seem quite right + //printf("UNSYNC UPDATE %p %u %u\n", buffer, begin, size); + buffer->bytes_to_draw_until_static += size * screen->static_reuse_threshold; + } + else + buffer->bytes_to_draw_until_static = buffer->size * screen->static_reuse_threshold; +} - src = pscreen->get_tex_surface(pscreen, pt, - sr.face, sr.level, box->z, - 0 /*PIPE_BIND_BLIT_SOURCE*/); +static void nvfx_transfer_flush_region( struct pipe_context *pipe, + struct pipe_transfer *ptx, + const struct pipe_box *box) +{ + if(ptx->resource->target == PIPE_BUFFER && (ptx->usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) + { + struct nvfx_buffer* buffer = nvfx_buffer(ptx->resource); + nvfx_buffer_dirty_interval(buffer, + (uint8_t*)ptx->data - buffer->data + util_format_get_stride(buffer->base.base.format, box->x), + util_format_get_stride(buffer->base.base.format, box->width), + !!(ptx->usage & PIPE_TRANSFER_UNSYNCHRONIZED)); + } +} - /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */ - /* TODO: Check if SIFM can un-swizzle */ - nvscreen->eng2d->copy(nvscreen->eng2d, - tx->surface, 0, 0, - src, - box->x, box->y, - box->width, box->height); +static void +nvfx_transfer_destroy(struct pipe_context *pipe, struct pipe_transfer *ptx) +{ + if(ptx->resource->target == PIPE_BUFFER) + { + struct nvfx_buffer* buffer = nvfx_buffer(ptx->resource); + if((ptx->usage & (PIPE_TRANSFER_WRITE | PIPE_TRANSFER_FLUSH_EXPLICIT)) == PIPE_TRANSFER_WRITE) + nvfx_buffer_dirty_interval(buffer, + (uint8_t*)ptx->data - buffer->data, + ptx->stride, + !!(ptx->usage & PIPE_TRANSFER_UNSYNCHRONIZED)); + pipe_resource_reference(&ptx->resource, 0); + FREE(ptx); + } + else + { + struct nouveau_channel* chan = nvfx_context(pipe)->screen->base.channel; + util_staging_transfer_destroy(pipe, ptx); - pipe_surface_reference(&src, NULL); + FIRE_RING(chan); } +} - return &tx->base; +void * +nvfx_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx) +{ + if(ptx->resource->target == PIPE_BUFFER) + return ptx->data; + else + { + struct nvfx_staging_transfer *tx = (struct nvfx_staging_transfer *)ptx; + if(!ptx->data) + { + struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->base.staging_resource; + uint8_t *map = nouveau_screen_bo_map(pipe->screen, mt->base.bo, nouveau_screen_transfer_flags(ptx->usage)); + ptx->data = map + tx->offset; + } + + ++tx->map_count; + return ptx->data; + } } void -nvfx_miptree_transfer_del(struct pipe_context *pipe, - struct pipe_transfer *ptx) +nvfx_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *ptx) { - struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx; - - if (!tx->direct && (ptx->usage & PIPE_TRANSFER_WRITE)) { - struct pipe_screen *pscreen = pipe->screen; - struct nvfx_screen *nvscreen = nvfx_screen(pscreen); - struct pipe_surface *dst; - - dst = pscreen->get_tex_surface(pscreen, - ptx->resource, - ptx->sr.face, - ptx->sr.level, - ptx->box.z, - 0 /*PIPE_BIND_BLIT_DESTINATION*/); - - /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */ - nvscreen->eng2d->copy(nvscreen->eng2d, - dst, ptx->box.x, ptx->box.y, - tx->surface, 0, 0, - ptx->box.width, ptx->box.height); - - pipe_surface_reference(&dst, NULL); + if(ptx->resource->target != PIPE_BUFFER) + { + struct nvfx_staging_transfer *tx = (struct nvfx_staging_transfer *)ptx; + struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->base.staging_resource; + + if(!--tx->map_count) + { + nouveau_screen_bo_unmap(pipe->screen, mt->base.bo); + ptx->data = 0; + } } - - pipe_surface_reference(&tx->surface, NULL); - pipe_resource_reference(&ptx->resource, NULL); - FREE(ptx); } -void * -nvfx_miptree_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx) +static void nvfx_transfer_inline_write( struct pipe_context *pipe, + struct pipe_resource *pr, + struct pipe_subresource sr, + unsigned usage, + const struct pipe_box *box, + const void *data, + unsigned stride, + unsigned slice_stride) { - struct pipe_screen *pscreen = pipe->screen; - struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx; - struct nv04_surface *ns = (struct nv04_surface *)tx->surface; - struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture; - uint8_t *map = nouveau_screen_bo_map(pscreen, mt->base.bo, - nouveau_screen_transfer_flags(ptx->usage)); - - if(!tx->direct) - return map + ns->base.offset; + if(pr->target != PIPE_BUFFER) + { + u_default_transfer_inline_write(pipe, pr, sr, usage, box, data, stride, slice_stride); + } else - return (map + ns->base.offset + - ptx->box.y * ns->pitch + - ptx->box.x * util_format_get_blocksize(ptx->resource->format)); + { + struct nvfx_buffer* buffer = nvfx_buffer(pr); + unsigned begin = util_format_get_stride(pr->format, box->x); + unsigned size = util_format_get_stride(pr->format, box->width); + memcpy(buffer->data + begin, data, size); + nvfx_buffer_dirty_interval(buffer, begin, size, + !!(pr->flags & PIPE_TRANSFER_UNSYNCHRONIZED)); + } } void -nvfx_miptree_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *ptx) +nvfx_init_transfer_functions(struct pipe_context *pipe) { - struct pipe_screen *pscreen = pipe->screen; - struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx; - struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture; - - nouveau_screen_bo_unmap(pscreen, mt->base.bo); + pipe->get_transfer = nvfx_transfer_new; + pipe->transfer_map = nvfx_transfer_map; + pipe->transfer_flush_region = nvfx_transfer_flush_region; + pipe->transfer_unmap = nvfx_transfer_unmap; + pipe->transfer_destroy = nvfx_transfer_destroy; + pipe->transfer_inline_write = nvfx_transfer_inline_write; } diff --git a/src/gallium/drivers/nvfx/nvfx_transfer.h b/src/gallium/drivers/nvfx/nvfx_transfer.h index 3e3317b2c7..20f20d5b0b 100644 --- a/src/gallium/drivers/nvfx/nvfx_transfer.h +++ b/src/gallium/drivers/nvfx/nvfx_transfer.h @@ -7,19 +7,17 @@ struct pipe_transfer * -nvfx_miptree_transfer_new(struct pipe_context *pcontext, +nvfx_transfer_new(struct pipe_context *pcontext, struct pipe_resource *pt, struct pipe_subresource sr, unsigned usage, const struct pipe_box *box); -void -nvfx_miptree_transfer_del(struct pipe_context *pcontext, - struct pipe_transfer *ptx); + void * -nvfx_miptree_transfer_map(struct pipe_context *pcontext, +nvfx_transfer_map(struct pipe_context *pcontext, struct pipe_transfer *ptx); void -nvfx_miptree_transfer_unmap(struct pipe_context *pcontext, +nvfx_transfer_unmap(struct pipe_context *pcontext, struct pipe_transfer *ptx); diff --git a/src/gallium/drivers/nvfx/nvfx_vbo.c b/src/gallium/drivers/nvfx/nvfx_vbo.c index 4aa3793842..e6e9a8f2e4 100644 --- a/src/gallium/drivers/nvfx/nvfx_vbo.c +++ b/src/gallium/drivers/nvfx/nvfx_vbo.c @@ -2,6 +2,7 @@ #include "pipe/p_state.h" #include "util/u_inlines.h" #include "util/u_format.h" +#include "translate/translate.h" #include "nvfx_context.h" #include "nvfx_state.h" @@ -10,646 +11,595 @@ #include "nouveau/nouveau_channel.h" #include "nouveau/nouveau_class.h" #include "nouveau/nouveau_pushbuf.h" -#include "nouveau/nouveau_util.h" -static INLINE int -nvfx_vbo_format_to_hw(enum pipe_format pipe, unsigned *fmt, unsigned *ncomp) +static inline unsigned +util_guess_unique_indices_count(unsigned mode, unsigned indices) { - switch (pipe) { - case PIPE_FORMAT_R32_FLOAT: - case PIPE_FORMAT_R32G32_FLOAT: - case PIPE_FORMAT_R32G32B32_FLOAT: - case PIPE_FORMAT_R32G32B32A32_FLOAT: - *fmt = NV34TCL_VTXFMT_TYPE_FLOAT; - break; - case PIPE_FORMAT_R16_FLOAT: - case PIPE_FORMAT_R16G16_FLOAT: - case PIPE_FORMAT_R16G16B16_FLOAT: - case PIPE_FORMAT_R16G16B16A16_FLOAT: - *fmt = NV34TCL_VTXFMT_TYPE_HALF; - break; - case PIPE_FORMAT_R8_UNORM: - case PIPE_FORMAT_R8G8_UNORM: - case PIPE_FORMAT_R8G8B8_UNORM: - case PIPE_FORMAT_R8G8B8A8_UNORM: - *fmt = NV34TCL_VTXFMT_TYPE_UBYTE; - break; - case PIPE_FORMAT_R16_SSCALED: - case PIPE_FORMAT_R16G16_SSCALED: - case PIPE_FORMAT_R16G16B16_SSCALED: - case PIPE_FORMAT_R16G16B16A16_SSCALED: - *fmt = NV34TCL_VTXFMT_TYPE_USHORT; - break; - default: - NOUVEAU_ERR("Unknown format %s\n", util_format_name(pipe)); - return 1; + /* Euler's formula gives V = + * = E - F + 2 = + * = F * (polygon_edges / 2 - 1) + 2 = + * = F * (polygon_edges - 2) / 2 + 2 = + * = indices * (polygon_edges - 2) / (2 * indices_per_face) + 2 + * = indices * (1 / 2 - 1 / polygon_edges) + 2 + */ + switch(mode) + { + case PIPE_PRIM_LINES: + return indices >> 1; + case PIPE_PRIM_TRIANGLES: + { + // avoid an expensive division by 3 using the multiplicative inverse mod 2^32 + unsigned q; + unsigned inv3 = 2863311531; + indices >>= 1; + q = indices * inv3; + if(unlikely(q >= indices)) + { + q += inv3; + if(q >= indices) + q += inv3; + } + return indices + 2; + //return indices / 6 + 2; } - - switch (pipe) { - case PIPE_FORMAT_R8_UNORM: - case PIPE_FORMAT_R32_FLOAT: - case PIPE_FORMAT_R16_FLOAT: - case PIPE_FORMAT_R16_SSCALED: - *ncomp = 1; - break; - case PIPE_FORMAT_R8G8_UNORM: - case PIPE_FORMAT_R32G32_FLOAT: - case PIPE_FORMAT_R16G16_FLOAT: - case PIPE_FORMAT_R16G16_SSCALED: - *ncomp = 2; - break; - case PIPE_FORMAT_R8G8B8_UNORM: - case PIPE_FORMAT_R32G32B32_FLOAT: - case PIPE_FORMAT_R16G16B16_FLOAT: - case PIPE_FORMAT_R16G16B16_SSCALED: - *ncomp = 3; - break; - case PIPE_FORMAT_R8G8B8A8_UNORM: - case PIPE_FORMAT_R32G32B32A32_FLOAT: - case PIPE_FORMAT_R16G16B16A16_FLOAT: - case PIPE_FORMAT_R16G16B16A16_SSCALED: - *ncomp = 4; - break; + // guess that indexed quads are created by successive connections, since a closed mesh seems unlikely + case PIPE_PRIM_QUADS: + return (indices >> 1) + 2; + // return (indices >> 2) + 2; // if it is a closed mesh default: - NOUVEAU_ERR("Unknown format %s\n", util_format_name(pipe)); - return 1; + return indices; } - - return 0; } -static boolean -nvfx_vbo_set_idxbuf(struct nvfx_context *nvfx, struct pipe_resource *ib, - unsigned ib_size) +static unsigned nvfx_decide_upload_mode(struct pipe_context *pipe, const struct pipe_draw_info *info) { - unsigned type; - - if (!ib) { - nvfx->idxbuf_buffer = NULL; - nvfx->idxbuf_format = 0xdeadbeef; - return FALSE; + struct nvfx_context* nvfx = nvfx_context(pipe); + unsigned hardware_cost = 0; + unsigned inline_cost = 0; + unsigned unique_vertices; + unsigned upload_mode; + float best_index_cost_for_hardware_vertices_as_inline_cost; + boolean prefer_hardware_indices; + unsigned index_inline_cost; + unsigned index_hardware_cost; + if (info->indexed) + unique_vertices = util_guess_unique_indices_count(info->mode, info->count); + else + unique_vertices = info->count; + + /* Here we try to figure out if we are better off writing vertex data directly on the FIFO, + * or create hardware buffer objects and pointing the hardware to them. + * + * This is done by computing the total memcpy cost of each option, ignoring uploads + * if we think that the buffer is static and thus the upload cost will be amortized over + * future draw calls. + * + * For instance, if everything looks static, we will always create buffer objects, while if + * everything is a user buffer and we are not doing indexed drawing, we never do. + * + * Other interesting cases are where a small user vertex buffer, but a huge user index buffer, + * where we will upload the vertex buffer, so that we can use hardware index lookup, and + * the opposite case, where we instead do index lookup in software to avoid uploading + * a huge amount of vertex data that is not going to be used. + * + * Otherwise, we generally move to the GPU the after it has been pushed + * NVFX_STATIC_BUFFER_MIN_REUSE_TIMES times to the GPU without having + * been updated with a transfer (or just the buffer having been destroyed). + * + * There is no special handling for user buffers, since applications can use + * OpenGL VBOs in a one-shot fashion. OpenGL 3/4 core profile forces this + * by the way. + * + * Note that currently we don't support only putting some data on the FIFO, and + * some on vertex buffers (constant and instanced data is independent from this). + * + * nVidia doesn't seem to do this either, even though it should be at least + * doable with VTX_ATTR and possibly with VERTEX_DATA too if not indexed. + */ + + for (unsigned i = 0; i < nvfx->vtxelt->num_per_vertex_buffer_infos; i++) + { + struct nvfx_per_vertex_buffer_info* vbi = &nvfx->vtxelt->per_vertex_buffer_info[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[vbi->vertex_buffer_index]; + struct nvfx_buffer* buffer = nvfx_buffer(vb->buffer); + buffer->bytes_to_draw_until_static -= vbi->per_vertex_size * unique_vertices; + if (!nvfx_buffer_seems_static(buffer)) + { + hardware_cost += buffer->dirty_end - buffer->dirty_begin; + if (!buffer->base.bo) + hardware_cost += nvfx->screen->buffer_allocation_cost; + } + inline_cost += vbi->per_vertex_size * info->count; } - if (!nvfx->screen->index_buffer_reloc_flags || ib_size == 1) - return FALSE; + best_index_cost_for_hardware_vertices_as_inline_cost = 0.0f; + prefer_hardware_indices = FALSE; + index_inline_cost = 0; + index_hardware_cost = 0; - switch (ib_size) { - case 2: - type = NV34TCL_IDXBUF_FORMAT_TYPE_U16; - break; - case 4: - type = NV34TCL_IDXBUF_FORMAT_TYPE_U32; - break; - default: - return FALSE; - } + if (info->indexed) + { + index_inline_cost = nvfx->idxbuf.index_size * info->count; + if (nvfx->screen->index_buffer_reloc_flags + && (nvfx->idxbuf.index_size == 2 || nvfx->idxbuf.index_size == 4) + && !(nvfx->idxbuf.offset & (nvfx->idxbuf.index_size - 1))) + { + struct nvfx_buffer* buffer = nvfx_buffer(nvfx->idxbuf.buffer); + buffer->bytes_to_draw_until_static -= index_inline_cost; - if (ib != nvfx->idxbuf_buffer || - type != nvfx->idxbuf_format) { - nvfx->dirty |= NVFX_NEW_ARRAYS; - nvfx->idxbuf_buffer = ib; - nvfx->idxbuf_format = type; - } + prefer_hardware_indices = TRUE; - return TRUE; -} + if (!nvfx_buffer_seems_static(buffer)) + { + index_hardware_cost = buffer->dirty_end - buffer->dirty_begin; + if (!buffer->base.bo) + index_hardware_cost += nvfx->screen->buffer_allocation_cost; + } -// type must be floating point -static inline void -nvfx_vbo_static_attrib(struct nvfx_context *nvfx, - int attrib, struct pipe_vertex_element *ve, - struct pipe_vertex_buffer *vb, unsigned ncomp) -{ - struct pipe_transfer *transfer; - struct nouveau_channel* chan = nvfx->screen->base.channel; - void *map; - float *v; - - map = pipe_buffer_map(&nvfx->pipe, vb->buffer, PIPE_TRANSFER_READ, &transfer); - map = (uint8_t *) map + vb->buffer_offset + ve->src_offset; - - v = map; - - switch (ncomp) { - case 4: - OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_4F_X(attrib), 4)); - OUT_RING(chan, fui(v[0])); - OUT_RING(chan, fui(v[1])); - OUT_RING(chan, fui(v[2])); - OUT_RING(chan, fui(v[3])); - break; - case 3: - OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_3F_X(attrib), 3)); - OUT_RING(chan, fui(v[0])); - OUT_RING(chan, fui(v[1])); - OUT_RING(chan, fui(v[2])); - break; - case 2: - OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_2F_X(attrib), 2)); - OUT_RING(chan, fui(v[0])); - OUT_RING(chan, fui(v[1])); - break; - case 1: - OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_1F(attrib), 1)); - OUT_RING(chan, fui(v[0])); - break; + if ((float) index_inline_cost < (float) index_hardware_cost * nvfx->screen->inline_cost_per_hardware_cost) + { + best_index_cost_for_hardware_vertices_as_inline_cost = (float) index_inline_cost; + } + else + { + best_index_cost_for_hardware_vertices_as_inline_cost = (float) index_hardware_cost * nvfx->screen->inline_cost_per_hardware_cost; + prefer_hardware_indices = TRUE; + } + } } - pipe_buffer_unmap(&nvfx->pipe, vb->buffer, transfer); + /* let's finally figure out which of the 3 paths we want to take */ + if ((float) (inline_cost + index_inline_cost) > ((float) hardware_cost * nvfx->screen->inline_cost_per_hardware_cost + best_index_cost_for_hardware_vertices_as_inline_cost)) + upload_mode = 1 + prefer_hardware_indices; + else + upload_mode = 0; + +#ifdef DEBUG + if (unlikely(nvfx->screen->trace_draw)) + { + fprintf(stderr, "DRAW"); + if (info->indexed) + { + fprintf(stderr, "_IDX%u", nvfx->idxbuf.index_size); + if (info->index_bias) + fprintf(stderr, " biased %u", info->index_bias); + fprintf(stderr, " idxrange %u -> %u", info->min_index, info->max_index); + } + if (info->instance_count > 1) + fprintf(stderr, " %u instances from %u", info->instance_count, info->indexed); + fprintf(stderr, " start %u count %u prim %u", info->start, info->count, info->mode); + if (!upload_mode) + fprintf(stderr, " -> inline vertex data"); + else if (upload_mode == 2 || !info->indexed) + fprintf(stderr, " -> buffer range"); + else + fprintf(stderr, " -> inline indices"); + fprintf(stderr, " [ivtx %u hvtx %u iidx %u hidx %u bidx %f] <", inline_cost, hardware_cost, index_inline_cost, index_hardware_cost, best_index_cost_for_hardware_vertices_as_inline_cost); + for (unsigned i = 0; i < nvfx->vtxelt->num_per_vertex_buffer_infos; ++i) + { + struct nvfx_per_vertex_buffer_info* vbi = &nvfx->vtxelt->per_vertex_buffer_info[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[vbi->vertex_buffer_index]; + struct nvfx_buffer* buffer = nvfx_buffer(vb->buffer); + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "%p%s left %Li", buffer, buffer->last_update_static ? " static" : "", buffer->bytes_to_draw_until_static); + } + fprintf(stderr, ">\n"); + } +#endif + + return upload_mode; } -static void -nvfx_draw_arrays(struct pipe_context *pipe, - unsigned mode, unsigned start, unsigned count) +void nvfx_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct nvfx_context *nvfx = nvfx_context(pipe); - struct nvfx_screen *screen = nvfx->screen; - struct nouveau_channel *chan = screen->base.channel; - unsigned restart = 0; - - nvfx_vbo_set_idxbuf(nvfx, NULL, 0); - if (nvfx->screen->force_swtnl || !nvfx_state_validate(nvfx)) { - nvfx_draw_elements_swtnl(pipe, NULL, 0, 0, - mode, start, count); - return; - } + unsigned upload_mode = 0; - while (count) { - unsigned vc, nr, avail; + if (!nvfx->vtxelt->needs_translate) + upload_mode = nvfx_decide_upload_mode(pipe, info); - nvfx_state_emit(nvfx); + nvfx->use_index_buffer = upload_mode > 1; - avail = AVAIL_RING(chan); - avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */ + if ((upload_mode > 0) != nvfx->use_vertex_buffers) + { + nvfx->use_vertex_buffers = (upload_mode > 0); + nvfx->dirty |= NVFX_NEW_ARRAYS; + nvfx->draw_dirty |= NVFX_NEW_ARRAYS; + } - vc = nouveau_vbuf_split(avail, 6, 256, - mode, start, count, &restart); - if (!vc) { - FIRE_RING(chan); - continue; + if (upload_mode > 0) + { + for (unsigned i = 0; i < nvfx->vtxelt->num_per_vertex_buffer_infos; i++) + { + struct nvfx_per_vertex_buffer_info* vbi = &nvfx->vtxelt->per_vertex_buffer_info[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[vbi->vertex_buffer_index]; + nvfx_buffer_upload(nvfx_buffer(vb->buffer)); } - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, nvgl_primitive(mode)); + if (upload_mode > 1) + { + nvfx_buffer_upload(nvfx_buffer(nvfx->idxbuf.buffer)); - nr = (vc & 0xff); - if (nr) { - OUT_RING(chan, RING_3D(NV34TCL_VB_VERTEX_BATCH, 1)); - OUT_RING (chan, ((nr - 1) << 24) | start); - start += nr; + if (unlikely(info->index_bias != nvfx->base_vertex)) + { + nvfx->base_vertex = info->index_bias; + nvfx->dirty |= NVFX_NEW_ARRAYS; + } } - - nr = vc >> 8; - while (nr) { - unsigned push = nr > 2047 ? 2047 : nr; - - nr -= push; - - OUT_RING(chan, RING_3D_NI(NV34TCL_VB_VERTEX_BATCH, push)); - while (push--) { - OUT_RING(chan, ((0x100 - 1) << 24) | start); - start += 0x100; + else + { + if (unlikely(info->start < nvfx->base_vertex && nvfx->base_vertex)) + { + nvfx->base_vertex = 0; + nvfx->dirty |= NVFX_NEW_ARRAYS; } } - - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, 0); - - count -= vc; - start = restart; } - pipe->flush(pipe, 0, NULL); + if (nvfx->screen->force_swtnl || !nvfx_state_validate(nvfx)) + nvfx_draw_vbo_swtnl(pipe, info); + else + nvfx_push_vbo(pipe, info); } -static INLINE void -nvfx_draw_elements_u08(struct nvfx_context *nvfx, void *ib, - unsigned mode, unsigned start, unsigned count) +boolean +nvfx_vbo_validate(struct nvfx_context *nvfx) { - struct nvfx_screen *screen = nvfx->screen; - struct nouveau_channel *chan = screen->base.channel; + struct nouveau_channel* chan = nvfx->screen->base.channel; + int i; + int elements = MAX2(nvfx->vtxelt->num_elements, nvfx->hw_vtxelt_nr); + unsigned vb_flags = nvfx->screen->vertex_buffer_reloc_flags | NOUVEAU_BO_RD; - while (count) { - uint8_t *elts = (uint8_t *)ib + start; - unsigned vc, push, restart = 0, avail; + if (!elements) + return TRUE; - nvfx_state_emit(nvfx); + MARK_RING(chan, (5 + 2) * 16 + 2 + 11, 16 + 2); + for(unsigned i = 0; i < nvfx->vtxelt->num_constant; ++i) + { + struct nvfx_low_frequency_element *ve = &nvfx->vtxelt->constant[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; + struct nvfx_buffer* buffer = nvfx_buffer(vb->buffer); + float v[4]; + ve->fetch_rgba_float(v, buffer->data + vb->buffer_offset + ve->src_offset, 0, 0); + nvfx_emit_vtx_attr(chan, ve->idx, v, ve->ncomp); + } - avail = AVAIL_RING(chan); - avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */ - vc = nouveau_vbuf_split(avail, 6, 2, - mode, start, count, &restart); - if (vc == 0) { - FIRE_RING(chan); - continue; - } - count -= vc; + OUT_RING(chan, RING_3D(NV34TCL_VTXFMT(0), elements)); + if(nvfx->use_vertex_buffers) + { + unsigned idx = 0; + for (i = 0; i < nvfx->vtxelt->num_per_vertex; i++) { + struct nvfx_per_vertex_element *ve = &nvfx->vtxelt->per_vertex[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, nvgl_primitive(mode)); + if(idx != ve->idx) + { + assert(idx < ve->idx); + OUT_RINGp(chan, &nvfx->vtxelt->vtxfmt[idx], ve->idx - idx); + idx = ve->idx; + } - if (vc & 1) { - OUT_RING(chan, RING_3D(NV34TCL_VB_ELEMENT_U32, 1)); - OUT_RING (chan, elts[0]); - elts++; vc--; + OUT_RING(chan, nvfx->vtxelt->vtxfmt[idx] | (vb->stride << NV34TCL_VTXFMT_STRIDE_SHIFT)); + ++idx; } + if(idx != nvfx->vtxelt->num_elements) + OUT_RINGp(chan, &nvfx->vtxelt->vtxfmt[idx], nvfx->vtxelt->num_elements - idx); + } + else + OUT_RINGp(chan, nvfx->vtxelt->vtxfmt, nvfx->vtxelt->num_elements); - while (vc) { - unsigned i; - - push = MIN2(vc, 2047 * 2); - - OUT_RING(chan, RING_3D_NI(NV34TCL_VB_ELEMENT_U16, push >> 1)); - for (i = 0; i < push; i+=2) - OUT_RING(chan, (elts[i+1] << 16) | elts[i]); + for(i = nvfx->vtxelt->num_elements; i < elements; ++i) + OUT_RING(chan, NV34TCL_VTXFMT_TYPE_32_FLOAT); - vc -= push; - elts += push; + if(nvfx->is_nv4x) { + unsigned i; + /* seems to be some kind of cache flushing */ + for(i = 0; i < 3; ++i) { + OUT_RING(chan, RING_3D(0x1718, 1)); + OUT_RING(chan, 0); } - - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, 0); - - start = restart; } -} - -static INLINE void -nvfx_draw_elements_u16(struct nvfx_context *nvfx, void *ib, - unsigned mode, unsigned start, unsigned count) -{ - struct nvfx_screen *screen = nvfx->screen; - struct nouveau_channel *chan = screen->base.channel; - - while (count) { - uint16_t *elts = (uint16_t *)ib + start; - unsigned vc, push, restart = 0, avail; - - nvfx_state_emit(nvfx); - - avail = AVAIL_RING(chan); - avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */ - vc = nouveau_vbuf_split(avail, 6, 2, - mode, start, count, &restart); - if (vc == 0) { - FIRE_RING(chan); - continue; - } - count -= vc; + OUT_RING(chan, RING_3D(NV34TCL_VTXBUF_ADDRESS(0), elements)); + if(nvfx->use_vertex_buffers) + { + unsigned idx = 0; + for (i = 0; i < nvfx->vtxelt->num_per_vertex; i++) { + struct nvfx_per_vertex_element *ve = &nvfx->vtxelt->per_vertex[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; + struct nouveau_bo* bo = nvfx_resource(vb->buffer)->bo; - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, nvgl_primitive(mode)); + for(; idx < ve->idx; ++idx) + OUT_RING(chan, 0); - if (vc & 1) { - OUT_RING(chan, RING_3D(NV34TCL_VB_ELEMENT_U32, 1)); - OUT_RING (chan, elts[0]); - elts++; vc--; + OUT_RELOC(chan, bo, + vb->buffer_offset + ve->src_offset + nvfx->base_vertex * vb->stride, + vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR, + 0, NV34TCL_VTXBUF_ADDRESS_DMA1); + ++idx; } - while (vc) { - unsigned i; - - push = MIN2(vc, 2047 * 2); - - OUT_RING(chan, RING_3D_NI(NV34TCL_VB_ELEMENT_U16, push >> 1)); - for (i = 0; i < push; i+=2) - OUT_RING(chan, (elts[i+1] << 16) | elts[i]); - - vc -= push; - elts += push; - } + for(; idx < elements; ++idx) + OUT_RING(chan, 0); + } + else + { + for (i = 0; i < elements; i++) + OUT_RING(chan, 0); + } - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, 0); + OUT_RING(chan, RING_3D(0x1710, 1)); + OUT_RING(chan, 0); - start = restart; - } + nvfx->hw_vtxelt_nr = nvfx->vtxelt->num_elements; + nvfx->relocs_needed &=~ NVFX_RELOCATE_VTXBUF; + return TRUE; } -static INLINE void -nvfx_draw_elements_u32(struct nvfx_context *nvfx, void *ib, - unsigned mode, unsigned start, unsigned count) +void +nvfx_vbo_relocate(struct nvfx_context *nvfx) { - struct nvfx_screen *screen = nvfx->screen; - struct nouveau_channel *chan = screen->base.channel; - - while (count) { - uint32_t *elts = (uint32_t *)ib + start; - unsigned vc, push, restart = 0, avail; - - nvfx_state_emit(nvfx); - - avail = AVAIL_RING(chan); - avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */ - - vc = nouveau_vbuf_split(avail, 5, 1, - mode, start, count, &restart); - if (vc == 0) { - FIRE_RING(chan); - continue; - } - count -= vc; - - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, nvgl_primitive(mode)); - - while (vc) { - push = MIN2(vc, 2047); - - OUT_RING(chan, RING_3D_NI(NV34TCL_VB_ELEMENT_U32, push)); - OUT_RINGp (chan, elts, push); + struct nouveau_channel* chan; + unsigned vb_flags; + int i; - vc -= push; - elts += push; - } + if(!nvfx->use_vertex_buffers) + return; - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, 0); + chan = nvfx->screen->base.channel; + vb_flags = nvfx->screen->vertex_buffer_reloc_flags | NOUVEAU_BO_RD | NOUVEAU_BO_DUMMY; - start = restart; + MARK_RING(chan, 2 * 16 + 3, 2 * 16 + 3); + for (i = 0; i < nvfx->vtxelt->num_per_vertex; i++) { + struct nvfx_per_vertex_element *ve = &nvfx->vtxelt->per_vertex[i]; + struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; + struct nouveau_bo* bo = nvfx_resource(vb->buffer)->bo; + + OUT_RELOC(chan, bo, RING_3D(NV34TCL_VTXBUF_ADDRESS(ve->idx), 1), + vb_flags, 0, 0); + OUT_RELOC(chan, bo, vb->buffer_offset + ve->src_offset + nvfx->base_vertex * vb->stride, + vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR, + 0, NV34TCL_VTXBUF_ADDRESS_DMA1); } + nvfx->relocs_needed &=~ NVFX_RELOCATE_VTXBUF; } static void -nvfx_draw_elements_inline(struct pipe_context *pipe, - struct pipe_resource *ib, - unsigned ib_size, int ib_bias, - unsigned mode, unsigned start, unsigned count) +nvfx_idxbuf_emit(struct nvfx_context* nvfx, unsigned ib_flags) { - struct nvfx_context *nvfx = nvfx_context(pipe); - struct pipe_transfer *transfer; - void *map; - - map = pipe_buffer_map(pipe, ib, PIPE_TRANSFER_READ, &transfer); - if (!ib) { - NOUVEAU_ERR("failed mapping ib\n"); - return; - } + struct nouveau_channel* chan = nvfx->screen->base.channel; + unsigned ib_format = (nvfx->idxbuf.index_size == 2) ? NV34TCL_IDXBUF_FORMAT_TYPE_U16 : NV34TCL_IDXBUF_FORMAT_TYPE_U32; + struct nouveau_bo* bo = nvfx_resource(nvfx->idxbuf.buffer)->bo; + ib_flags |= nvfx->screen->index_buffer_reloc_flags | NOUVEAU_BO_RD; - assert(ib_bias == 0); - - switch (ib_size) { - case 1: - nvfx_draw_elements_u08(nvfx, map, mode, start, count); - break; - case 2: - nvfx_draw_elements_u16(nvfx, map, mode, start, count); - break; - case 4: - nvfx_draw_elements_u32(nvfx, map, mode, start, count); - break; - default: - NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size); - break; - } + assert(nvfx->screen->index_buffer_reloc_flags); - pipe_buffer_unmap(pipe, ib, transfer); + MARK_RING(chan, 3, 3); + if(ib_flags & NOUVEAU_BO_DUMMY) + OUT_RELOC(chan, bo, RING_3D(NV34TCL_IDXBUF_ADDRESS, 2), ib_flags, 0, 0); + else + OUT_RING(chan, RING_3D(NV34TCL_IDXBUF_ADDRESS, 2)); + OUT_RELOC(chan, bo, nvfx->idxbuf.offset + 1, ib_flags | NOUVEAU_BO_LOW, 0, 0); + OUT_RELOC(chan, bo, ib_format, ib_flags | NOUVEAU_BO_OR, + 0, NV34TCL_IDXBUF_FORMAT_DMA1); + nvfx->relocs_needed &=~ NVFX_RELOCATE_IDXBUF; } -static void -nvfx_draw_elements_vbo(struct pipe_context *pipe, - unsigned mode, unsigned start, unsigned count) +void +nvfx_idxbuf_validate(struct nvfx_context* nvfx) { - struct nvfx_context *nvfx = nvfx_context(pipe); - struct nvfx_screen *screen = nvfx->screen; - struct nouveau_channel *chan = screen->base.channel; - unsigned restart = 0; + nvfx_idxbuf_emit(nvfx, 0); +} - while (count) { - unsigned nr, vc, avail; +void +nvfx_idxbuf_relocate(struct nvfx_context* nvfx) +{ + nvfx_idxbuf_emit(nvfx, NOUVEAU_BO_DUMMY); +} - nvfx_state_emit(nvfx); +unsigned nvfx_vertex_formats[PIPE_FORMAT_COUNT] = +{ + [PIPE_FORMAT_R32_FLOAT] = NV34TCL_VTXFMT_TYPE_32_FLOAT, + [PIPE_FORMAT_R32G32_FLOAT] = NV34TCL_VTXFMT_TYPE_32_FLOAT, + [PIPE_FORMAT_R32G32B32A32_FLOAT] = NV34TCL_VTXFMT_TYPE_32_FLOAT, + [PIPE_FORMAT_R32G32B32_FLOAT] = NV34TCL_VTXFMT_TYPE_32_FLOAT, + [PIPE_FORMAT_R16_FLOAT] = NV34TCL_VTXFMT_TYPE_16_FLOAT, + [PIPE_FORMAT_R16G16_FLOAT] = NV34TCL_VTXFMT_TYPE_16_FLOAT, + [PIPE_FORMAT_R16G16B16_FLOAT] = NV34TCL_VTXFMT_TYPE_16_FLOAT, + [PIPE_FORMAT_R16G16B16A16_FLOAT] = NV34TCL_VTXFMT_TYPE_16_FLOAT, + [PIPE_FORMAT_R8_UNORM] = NV34TCL_VTXFMT_TYPE_8_UNORM, + [PIPE_FORMAT_R8G8_UNORM] = NV34TCL_VTXFMT_TYPE_8_UNORM, + [PIPE_FORMAT_R8G8B8_UNORM] = NV34TCL_VTXFMT_TYPE_8_UNORM, + [PIPE_FORMAT_R8G8B8A8_UNORM] = NV34TCL_VTXFMT_TYPE_8_UNORM, + [PIPE_FORMAT_R8G8B8A8_USCALED] = NV34TCL_VTXFMT_TYPE_8_USCALED, + [PIPE_FORMAT_R16_SNORM] = NV34TCL_VTXFMT_TYPE_16_SNORM, + [PIPE_FORMAT_R16G16_SNORM] = NV34TCL_VTXFMT_TYPE_16_SNORM, + [PIPE_FORMAT_R16G16B16_SNORM] = NV34TCL_VTXFMT_TYPE_16_SNORM, + [PIPE_FORMAT_R16G16B16A16_SNORM] = NV34TCL_VTXFMT_TYPE_16_SNORM, + [PIPE_FORMAT_R16_SSCALED] = NV34TCL_VTXFMT_TYPE_16_SSCALED, + [PIPE_FORMAT_R16G16_SSCALED] = NV34TCL_VTXFMT_TYPE_16_SSCALED, + [PIPE_FORMAT_R16G16B16_SSCALED] = NV34TCL_VTXFMT_TYPE_16_SSCALED, + [PIPE_FORMAT_R16G16B16A16_SSCALED] = NV34TCL_VTXFMT_TYPE_16_SSCALED, +}; + +static void * +nvfx_vtxelts_state_create(struct pipe_context *pipe, + unsigned num_elements, + const struct pipe_vertex_element *elements) +{ + struct nvfx_vtxelt_state *cso = CALLOC_STRUCT(nvfx_vtxelt_state); + struct translate_key transkey; + unsigned per_vertex_size[16]; + unsigned vb_compacted_index[16]; - avail = AVAIL_RING(chan); - avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */ + if(num_elements > 16) + { + _debug_printf("Error: application attempted to use %u vertex elements, but only 16 are supported: ignoring the rest\n", num_elements); + num_elements = 16; + } - vc = nouveau_vbuf_split(avail, 6, 256, - mode, start, count, &restart); - if (!vc) { - FIRE_RING(chan); - continue; - } + memset(per_vertex_size, 0, sizeof(per_vertex_size)); + memcpy(cso->pipe, elements, num_elements * sizeof(elements[0])); + cso->num_elements = num_elements; + cso->needs_translate = FALSE; + + transkey.nr_elements = 0; + transkey.output_stride = 0; + + for(unsigned i = 0; i < num_elements; ++i) + { + const struct pipe_vertex_element* ve = &elements[i]; + if(!ve->instance_divisor) + per_vertex_size[ve->vertex_buffer_index] += util_format_get_stride(ve->src_format, 1); + } + + for(unsigned i = 0; i < 16; ++i) + { + if(per_vertex_size[i]) + { + unsigned idx = cso->num_per_vertex_buffer_infos++; + cso->per_vertex_buffer_info[idx].vertex_buffer_index = i; + cso->per_vertex_buffer_info[idx].per_vertex_size = per_vertex_size[i]; + vb_compacted_index[i] = idx; + } + } + + for(unsigned i = 0; i < num_elements; ++i) + { + const struct pipe_vertex_element* ve = &elements[i]; + unsigned type = nvfx_vertex_formats[ve->src_format]; + unsigned ncomp = util_format_get_nr_components(ve->src_format); - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, nvgl_primitive(mode)); + //if(ve->frequency != PIPE_ELEMENT_FREQUENCY_PER_VERTEX) + if(ve->instance_divisor) + { + struct nvfx_low_frequency_element* lfve; + cso->vtxfmt[i] = NV34TCL_VTXFMT_TYPE_32_FLOAT; + + //if(ve->frequency == PIPE_ELEMENT_FREQUENCY_CONSTANT) + if(0) + lfve = &cso->constant[cso->num_constant++]; + else + { + lfve = &cso->per_instance[cso->num_per_instance++].base; + ((struct nvfx_per_instance_element*)lfve)->instance_divisor = ve->instance_divisor; + } - nr = (vc & 0xff); - if (nr) { - OUT_RING(chan, RING_3D(NV34TCL_VB_INDEX_BATCH, 1)); - OUT_RING (chan, ((nr - 1) << 24) | start); - start += nr; + lfve->idx = i; + lfve->vertex_buffer_index = ve->vertex_buffer_index; + lfve->src_offset = ve->src_offset; + lfve->fetch_rgba_float = util_format_description(ve->src_format)->fetch_rgba_float; + lfve->ncomp = ncomp; } - - nr = vc >> 8; - while (nr) { - unsigned push = nr > 2047 ? 2047 : nr; - - nr -= push; - - OUT_RING(chan, RING_3D_NI(NV34TCL_VB_INDEX_BATCH, push)); - while (push--) { - OUT_RING(chan, ((0x100 - 1) << 24) | start); - start += 0x100; + else + { + unsigned idx; + + idx = cso->num_per_vertex++; + cso->per_vertex[idx].idx = i; + cso->per_vertex[idx].vertex_buffer_index = ve->vertex_buffer_index; + cso->per_vertex[idx].src_offset = ve->src_offset; + + idx = transkey.nr_elements++; + transkey.element[idx].input_format = ve->src_format; + transkey.element[idx].input_buffer = vb_compacted_index[ve->vertex_buffer_index]; + transkey.element[idx].input_offset = ve->src_offset; + transkey.element[idx].instance_divisor = 0; + transkey.element[idx].type = TRANSLATE_ELEMENT_NORMAL; + if(type) + { + transkey.element[idx].output_format = ve->src_format; + cso->vtxfmt[i] = (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type; + } + else + { + unsigned float32[4] = {PIPE_FORMAT_R32_FLOAT, PIPE_FORMAT_R32G32_FLOAT, PIPE_FORMAT_R32G32B32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT}; + transkey.element[idx].output_format = float32[ncomp - 1]; + cso->needs_translate = TRUE; + cso->vtxfmt[i] = (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | NV34TCL_VTXFMT_TYPE_32_FLOAT; } + transkey.element[idx].output_offset = transkey.output_stride; + transkey.output_stride += (util_format_get_stride(transkey.element[idx].output_format, 1) + 3) & ~3; } + } - OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1)); - OUT_RING (chan, 0); + cso->translate = translate_create(&transkey); + cso->vertex_length = transkey.output_stride >> 2; + cso->max_vertices_per_packet = 2047 / cso->vertex_length; - count -= vc; - start = restart; - } + return (void *)cso; } static void -nvfx_draw_elements(struct pipe_context *pipe, - struct pipe_resource *indexBuffer, - unsigned indexSize, int indexBias, - unsigned mode, unsigned start, unsigned count) +nvfx_vtxelts_state_delete(struct pipe_context *pipe, void *hwcso) { - struct nvfx_context *nvfx = nvfx_context(pipe); - boolean idxbuf; - - idxbuf = nvfx_vbo_set_idxbuf(nvfx, indexBuffer, indexSize); - if (nvfx->screen->force_swtnl || !nvfx_state_validate(nvfx)) { - nvfx_draw_elements_swtnl(pipe, - indexBuffer, indexSize, indexBias, - mode, start, count); - return; - } - - if (idxbuf) { - nvfx_draw_elements_vbo(pipe, mode, start, count); - } else { - nvfx_draw_elements_inline(pipe, - indexBuffer, indexSize, indexBias, - mode, start, count); - } - - pipe->flush(pipe, 0, NULL); + FREE(hwcso); } -void -nvfx_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) +static void +nvfx_vtxelts_state_bind(struct pipe_context *pipe, void *hwcso) { struct nvfx_context *nvfx = nvfx_context(pipe); - if (info->indexed && nvfx->idxbuf.buffer) { - unsigned offset; - - assert(nvfx->idxbuf.offset % nvfx->idxbuf.index_size == 0); - offset = nvfx->idxbuf.offset / nvfx->idxbuf.index_size; - - nvfx_draw_elements(pipe, - nvfx->idxbuf.buffer, - nvfx->idxbuf.index_size, - info->index_bias, - info->mode, - info->start + offset, - info->count); - } - else { - nvfx_draw_arrays(pipe, - info->mode, - info->start, - info->count); - } + nvfx->vtxelt = hwcso; + nvfx->use_vertex_buffers = -1; + nvfx->draw_dirty |= NVFX_NEW_ARRAYS; } -boolean -nvfx_vbo_validate(struct nvfx_context *nvfx) +static void +nvfx_set_vertex_buffers(struct pipe_context *pipe, unsigned count, + const struct pipe_vertex_buffer *vb) { - struct nouveau_channel* chan = nvfx->screen->base.channel; - struct pipe_resource *ib = nvfx->idxbuf_buffer; - unsigned ib_format = nvfx->idxbuf_format; - int i; - int elements = MAX2(nvfx->vtxelt->num_elements, nvfx->hw_vtxelt_nr); - uint32_t vtxfmt[16]; - unsigned vb_flags = nvfx->screen->vertex_buffer_reloc_flags | NOUVEAU_BO_RD; - - if (!elements) - return TRUE; - - nvfx->vbo_bo = 0; - - MARK_RING(chan, (5 + 2) * 16 + 2 + 11, 16 + 2); - for (i = 0; i < nvfx->vtxelt->num_elements; i++) { - struct pipe_vertex_element *ve; - struct pipe_vertex_buffer *vb; - unsigned type, ncomp; - - ve = &nvfx->vtxelt->pipe[i]; - vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; - - if (nvfx_vbo_format_to_hw(ve->src_format, &type, &ncomp)) { - MARK_UNDO(chan); - nvfx->fallback_swtnl |= NVFX_NEW_ARRAYS; - return FALSE; - } + struct nvfx_context *nvfx = nvfx_context(pipe); - if (!vb->stride && type == NV34TCL_VTXFMT_TYPE_FLOAT) { - nvfx_vbo_static_attrib(nvfx, i, ve, vb, ncomp); - vtxfmt[i] = type; - } else { - vtxfmt[i] = ((vb->stride << NV34TCL_VTXFMT_STRIDE_SHIFT) | - (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type); - nvfx->vbo_bo |= (1 << i); - } + for(unsigned i = 0; i < count; ++i) + { + pipe_resource_reference(&nvfx->vtxbuf[i].buffer, vb[i].buffer); + nvfx->vtxbuf[i].buffer_offset = vb[i].buffer_offset; + nvfx->vtxbuf[i].max_index = vb[i].max_index; + nvfx->vtxbuf[i].stride = vb[i].stride; } - for(; i < elements; ++i) - vtxfmt[i] = NV34TCL_VTXFMT_TYPE_FLOAT; + for(unsigned i = count; i < nvfx->vtxbuf_nr; ++i) + pipe_resource_reference(&nvfx->vtxbuf[i].buffer, 0); - OUT_RING(chan, RING_3D(NV34TCL_VTXFMT(0), elements)); - OUT_RINGp(chan, vtxfmt, elements); - - if(nvfx->is_nv4x) { - unsigned i; - /* seems to be some kind of cache flushing */ - for(i = 0; i < 3; ++i) { - OUT_RING(chan, RING_3D(0x1718, 1)); - OUT_RING(chan, 0); - } - } - - OUT_RING(chan, RING_3D(NV34TCL_VTXBUF_ADDRESS(0), elements)); - for (i = 0; i < nvfx->vtxelt->num_elements; i++) { - struct pipe_vertex_element *ve; - struct pipe_vertex_buffer *vb; + nvfx->vtxbuf_nr = count; + nvfx->use_vertex_buffers = -1; + nvfx->draw_dirty |= NVFX_NEW_ARRAYS; +} - ve = &nvfx->vtxelt->pipe[i]; - vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; +static void +nvfx_set_index_buffer(struct pipe_context *pipe, + const struct pipe_index_buffer *ib) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); - if (!(nvfx->vbo_bo & (1 << i))) - OUT_RING(chan, 0); - else - { - struct nouveau_bo* bo = nvfx_resource(vb->buffer)->bo; - OUT_RELOC(chan, bo, - vb->buffer_offset + ve->src_offset, - vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR, - 0, NV34TCL_VTXBUF_ADDRESS_DMA1); - } + if(ib) + { + pipe_resource_reference(&nvfx->idxbuf.buffer, ib->buffer); + nvfx->idxbuf.index_size = ib->index_size; + nvfx->idxbuf.offset = ib->offset; } - - for (; i < elements; i++) - OUT_RING(chan, 0); - - OUT_RING(chan, RING_3D(0x1710, 1)); - OUT_RING(chan, 0); - - if (ib) { - unsigned ib_flags = nvfx->screen->index_buffer_reloc_flags | NOUVEAU_BO_RD; - struct nouveau_bo* bo = nvfx_resource(ib)->bo; - - assert(nvfx->screen->index_buffer_reloc_flags); - - OUT_RING(chan, RING_3D(NV34TCL_IDXBUF_ADDRESS, 2)); - OUT_RELOC(chan, bo, 0, ib_flags | NOUVEAU_BO_LOW, 0, 0); - OUT_RELOC(chan, bo, ib_format, ib_flags | NOUVEAU_BO_OR, - 0, NV34TCL_IDXBUF_FORMAT_DMA1); + else + { + pipe_resource_reference(&nvfx->idxbuf.buffer, 0); + nvfx->idxbuf.index_size = 0; + nvfx->idxbuf.offset = 0; } - nvfx->hw_vtxelt_nr = nvfx->vtxelt->num_elements; - return TRUE; + nvfx->dirty |= NVFX_NEW_INDEX; + nvfx->draw_dirty |= NVFX_NEW_INDEX; } void -nvfx_vbo_relocate(struct nvfx_context *nvfx) +nvfx_init_vbo_functions(struct nvfx_context *nvfx) { - struct nouveau_channel* chan = nvfx->screen->base.channel; - unsigned vb_flags = nvfx->screen->vertex_buffer_reloc_flags | NOUVEAU_BO_RD | NOUVEAU_BO_DUMMY; - int i; + nvfx->pipe.set_vertex_buffers = nvfx_set_vertex_buffers; + nvfx->pipe.set_index_buffer = nvfx_set_index_buffer; - MARK_RING(chan, 2 * 16 + 3, 2 * 16 + 3); - for(i = 0; i < nvfx->vtxelt->num_elements; ++i) { - if(nvfx->vbo_bo & (1 << i)) { - struct pipe_vertex_element *ve = &nvfx->vtxelt->pipe[i]; - struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->vertex_buffer_index]; - struct nouveau_bo* bo = nvfx_resource(vb->buffer)->bo; - OUT_RELOC(chan, bo, RING_3D(NV34TCL_VTXBUF_ADDRESS(i), 1), - vb_flags, 0, 0); - OUT_RELOC(chan, bo, vb->buffer_offset + ve->src_offset, - vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR, - 0, NV34TCL_VTXBUF_ADDRESS_DMA1); - } - } - - if(nvfx->idxbuf_buffer) - { - unsigned ib_flags = nvfx->screen->index_buffer_reloc_flags | NOUVEAU_BO_RD | NOUVEAU_BO_DUMMY; - struct nouveau_bo* bo = nvfx_resource(nvfx->idxbuf_buffer)->bo; - - assert(nvfx->screen->index_buffer_reloc_flags); - - OUT_RELOC(chan, bo, RING_3D(NV34TCL_IDXBUF_ADDRESS, 2), - ib_flags, 0, 0); - OUT_RELOC(chan, bo, 0, - ib_flags | NOUVEAU_BO_LOW, 0, 0); - OUT_RELOC(chan, bo, nvfx->idxbuf_format, - ib_flags | NOUVEAU_BO_OR, - 0, NV34TCL_IDXBUF_FORMAT_DMA1); - } + nvfx->pipe.create_vertex_elements_state = nvfx_vtxelts_state_create; + nvfx->pipe.delete_vertex_elements_state = nvfx_vtxelts_state_delete; + nvfx->pipe.bind_vertex_elements_state = nvfx_vtxelts_state_bind; } diff --git a/src/gallium/drivers/nvfx/nvfx_vertprog.c b/src/gallium/drivers/nvfx/nvfx_vertprog.c index 24d9846310..ea7e88c561 100644 --- a/src/gallium/drivers/nvfx/nvfx_vertprog.c +++ b/src/gallium/drivers/nvfx/nvfx_vertprog.c @@ -1,15 +1,19 @@ #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "pipe/p_state.h" -#include "util/u_inlines.h" +#include "util/u_linkage.h" +#include "util/u_debug.h" #include "pipe/p_shader_tokens.h" #include "tgsi/tgsi_parse.h" #include "tgsi/tgsi_dump.h" #include "tgsi/tgsi_util.h" +#include "draw/draw_context.h" + #include "nvfx_context.h" #include "nvfx_state.h" +#include "nvfx_resource.h" /* TODO (at least...): * 1. Indexed consts + ARL @@ -25,26 +29,34 @@ #include "nv30_vertprog.h" #include "nv40_vertprog.h" -#define NVFX_VP_INST_DEST_CLIP(n) ((~0 - 6) + (n)) +struct nvfx_loop_entry +{ + unsigned brk_target; + unsigned cont_target; +}; struct nvfx_vpc { + struct nvfx_context* nvfx; struct nvfx_vertex_program *vp; struct nvfx_vertex_program_exec *vpi; unsigned r_temps; unsigned r_temps_discard; - struct nvfx_sreg r_result[PIPE_MAX_SHADER_OUTPUTS]; - struct nvfx_sreg *r_address; - struct nvfx_sreg *r_temp; + struct nvfx_reg r_result[PIPE_MAX_SHADER_OUTPUTS]; + struct nvfx_reg *r_address; + struct nvfx_reg *r_temp; - struct nvfx_sreg *imm; + struct nvfx_reg *imm; unsigned nr_imm; unsigned hpos_idx; + + struct util_dynarray label_relocs; + struct util_dynarray loop_stack; }; -static struct nvfx_sreg +static struct nvfx_reg temp(struct nvfx_vpc *vpc) { int idx = ffs(~vpc->r_temps) - 1; @@ -52,22 +64,22 @@ temp(struct nvfx_vpc *vpc) if (idx < 0) { NOUVEAU_ERR("out of temps!!\n"); assert(0); - return nvfx_sr(NVFXSR_TEMP, 0); + return nvfx_reg(NVFXSR_TEMP, 0); } vpc->r_temps |= (1 << idx); vpc->r_temps_discard |= (1 << idx); - return nvfx_sr(NVFXSR_TEMP, idx); + return nvfx_reg(NVFXSR_TEMP, idx); } -static INLINE void +static inline void release_temps(struct nvfx_vpc *vpc) { vpc->r_temps &= ~vpc->r_temps_discard; vpc->r_temps_discard = 0; } -static struct nvfx_sreg +static struct nvfx_reg constant(struct nvfx_vpc *vpc, int pipe, float x, float y, float z, float w) { struct nvfx_vertex_program *vp = vpc->vp; @@ -77,7 +89,7 @@ constant(struct nvfx_vpc *vpc, int pipe, float x, float y, float z, float w) if (pipe >= 0) { for (idx = 0; idx < vp->nr_consts; idx++) { if (vp->consts[idx].index == pipe) - return nvfx_sr(NVFXSR_CONST, idx); + return nvfx_reg(NVFXSR_CONST, idx); } } @@ -90,35 +102,36 @@ constant(struct nvfx_vpc *vpc, int pipe, float x, float y, float z, float w) vpd->value[1] = y; vpd->value[2] = z; vpd->value[3] = w; - return nvfx_sr(NVFXSR_CONST, idx); + return nvfx_reg(NVFXSR_CONST, idx); } -#define arith(cc,s,o,d,m,s0,s1,s2) \ - nvfx_vp_arith(nvfx, (cc), NVFX_VP_INST_SLOT_##s, NVFX_VP_INST_##s##_OP_##o, (d), (m), (s0), (s1), (s2)) +#define arith(s,o,d,m,s0,s1,s2) \ + nvfx_insn(0, (NVFX_VP_INST_SLOT_##s << 7) | NVFX_VP_INST_##s##_OP_##o, -1, (d), (m), (s0), (s1), (s2)) static void -emit_src(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, uint32_t *hw, int pos, struct nvfx_sreg src) +emit_src(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, uint32_t *hw, int pos, struct nvfx_src src) { struct nvfx_vertex_program *vp = vpc->vp; uint32_t sr = 0; + struct nvfx_relocation reloc; - switch (src.type) { + switch (src.reg.type) { case NVFXSR_TEMP: sr |= (NVFX_VP(SRC_REG_TYPE_TEMP) << NVFX_VP(SRC_REG_TYPE_SHIFT)); - sr |= (src.index << NVFX_VP(SRC_TEMP_SRC_SHIFT)); + sr |= (src.reg.index << NVFX_VP(SRC_TEMP_SRC_SHIFT)); break; case NVFXSR_INPUT: sr |= (NVFX_VP(SRC_REG_TYPE_INPUT) << NVFX_VP(SRC_REG_TYPE_SHIFT)); - vp->ir |= (1 << src.index); - hw[1] |= (src.index << NVFX_VP(INST_INPUT_SRC_SHIFT)); + vp->ir |= (1 << src.reg.index); + hw[1] |= (src.reg.index << NVFX_VP(INST_INPUT_SRC_SHIFT)); break; case NVFXSR_CONST: sr |= (NVFX_VP(SRC_REG_TYPE_CONST) << NVFX_VP(SRC_REG_TYPE_SHIFT)); - assert(vpc->vpi->const_index == -1 || - vpc->vpi->const_index == src.index); - vpc->vpi->const_index = src.index; + reloc.location = vp->nr_insns - 1; + reloc.target = src.reg.index; + util_dynarray_append(&vp->const_relocs, struct nvfx_relocation, reloc); break; case NVFXSR_NONE: sr |= (NVFX_VP(SRC_REG_TYPE_INPUT) << @@ -161,100 +174,67 @@ emit_src(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, uint32_t *hw, int pos, } static void -emit_dst(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, uint32_t *hw, int slot, struct nvfx_sreg dst) +emit_dst(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, uint32_t *hw, int slot, struct nvfx_reg dst) { struct nvfx_vertex_program *vp = vpc->vp; switch (dst.type) { + case NVFXSR_NONE: + if(!nvfx->is_nv4x) + hw[0] |= NV30_VP_INST_DEST_TEMP_ID_MASK; + else { + hw[3] |= NV40_VP_INST_DEST_MASK; + if (slot == 0) + hw[0] |= NV40_VP_INST_VEC_DEST_TEMP_MASK; + else + hw[3] |= NV40_VP_INST_SCA_DEST_TEMP_MASK; + } + break; case NVFXSR_TEMP: if(!nvfx->is_nv4x) hw[0] |= (dst.index << NV30_VP_INST_DEST_TEMP_ID_SHIFT); else { hw[3] |= NV40_VP_INST_DEST_MASK; - if (slot == 0) { - hw[0] |= (dst.index << - NV40_VP_INST_VEC_DEST_TEMP_SHIFT); - } else { - hw[3] |= (dst.index << - NV40_VP_INST_SCA_DEST_TEMP_SHIFT); - } + if (slot == 0) + hw[0] |= (dst.index << NV40_VP_INST_VEC_DEST_TEMP_SHIFT); + else + hw[3] |= (dst.index << NV40_VP_INST_SCA_DEST_TEMP_SHIFT); } break; case NVFXSR_OUTPUT: /* TODO: this may be wrong because on nv30 COL0 and BFC0 are swapped */ - switch (dst.index) { - case NVFX_VP_INST_DEST_CLIP(0): - vp->or |= (1 << 6); - vp->clip_ctrl |= NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0; - dst.index = NVFX_VP(INST_DEST_FOGC); - break; - case NVFX_VP_INST_DEST_CLIP(1): - vp->or |= (1 << 7); - vp->clip_ctrl |= NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1; - dst.index = NVFX_VP(INST_DEST_FOGC); - break; - case NVFX_VP_INST_DEST_CLIP(2): - vp->or |= (1 << 8); - vp->clip_ctrl |= NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE2; - dst.index = NVFX_VP(INST_DEST_FOGC); - break; - case NVFX_VP_INST_DEST_CLIP(3): - vp->or |= (1 << 9); - vp->clip_ctrl |= NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE3; - dst.index = NVFX_VP(INST_DEST_PSZ); - break; - case NVFX_VP_INST_DEST_CLIP(4): - vp->or |= (1 << 10); - vp->clip_ctrl |= NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE4; - dst.index = NVFX_VP(INST_DEST_PSZ); - break; - case NVFX_VP_INST_DEST_CLIP(5): - vp->or |= (1 << 11); - vp->clip_ctrl |= NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE5; - dst.index = NVFX_VP(INST_DEST_PSZ); - break; - default: - if(!nvfx->is_nv4x) { - switch (dst.index) { - case NV30_VP_INST_DEST_COL0 : vp->or |= (1 << 0); break; - case NV30_VP_INST_DEST_COL1 : vp->or |= (1 << 1); break; - case NV30_VP_INST_DEST_BFC0 : vp->or |= (1 << 2); break; - case NV30_VP_INST_DEST_BFC1 : vp->or |= (1 << 3); break; - case NV30_VP_INST_DEST_FOGC: vp->or |= (1 << 4); break; - case NV30_VP_INST_DEST_PSZ : vp->or |= (1 << 5); break; - case NV30_VP_INST_DEST_TC(0): vp->or |= (1 << 14); break; - case NV30_VP_INST_DEST_TC(1): vp->or |= (1 << 15); break; - case NV30_VP_INST_DEST_TC(2): vp->or |= (1 << 16); break; - case NV30_VP_INST_DEST_TC(3): vp->or |= (1 << 17); break; - case NV30_VP_INST_DEST_TC(4): vp->or |= (1 << 18); break; - case NV30_VP_INST_DEST_TC(5): vp->or |= (1 << 19); break; - case NV30_VP_INST_DEST_TC(6): vp->or |= (1 << 20); break; - case NV30_VP_INST_DEST_TC(7): vp->or |= (1 << 21); break; - } - } else { - switch (dst.index) { - case NV40_VP_INST_DEST_COL0 : vp->or |= (1 << 0); break; - case NV40_VP_INST_DEST_COL1 : vp->or |= (1 << 1); break; - case NV40_VP_INST_DEST_BFC0 : vp->or |= (1 << 2); break; - case NV40_VP_INST_DEST_BFC1 : vp->or |= (1 << 3); break; - case NV40_VP_INST_DEST_FOGC: vp->or |= (1 << 4); break; - case NV40_VP_INST_DEST_PSZ : vp->or |= (1 << 5); break; - case NV40_VP_INST_DEST_TC(0): vp->or |= (1 << 14); break; - case NV40_VP_INST_DEST_TC(1): vp->or |= (1 << 15); break; - case NV40_VP_INST_DEST_TC(2): vp->or |= (1 << 16); break; - case NV40_VP_INST_DEST_TC(3): vp->or |= (1 << 17); break; - case NV40_VP_INST_DEST_TC(4): vp->or |= (1 << 18); break; - case NV40_VP_INST_DEST_TC(5): vp->or |= (1 << 19); break; - case NV40_VP_INST_DEST_TC(6): vp->or |= (1 << 20); break; - case NV40_VP_INST_DEST_TC(7): vp->or |= (1 << 21); break; - } + if(nvfx->is_nv4x) { + switch (dst.index) { + case NV30_VP_INST_DEST_CLP(0): + dst.index = NVFX_VP(INST_DEST_FOGC); + break; + case NV30_VP_INST_DEST_CLP(1): + dst.index = NVFX_VP(INST_DEST_FOGC); + break; + case NV30_VP_INST_DEST_CLP(2): + dst.index = NVFX_VP(INST_DEST_FOGC); + break; + case NV30_VP_INST_DEST_CLP(3): + dst.index = NVFX_VP(INST_DEST_PSZ); + break; + case NV30_VP_INST_DEST_CLP(4): + dst.index = NVFX_VP(INST_DEST_PSZ); + break; + case NV30_VP_INST_DEST_CLP(5): + dst.index = NVFX_VP(INST_DEST_PSZ); + break; + case NV40_VP_INST_DEST_COL0 : vp->or |= (1 << 0); break; + case NV40_VP_INST_DEST_COL1 : vp->or |= (1 << 1); break; + case NV40_VP_INST_DEST_BFC0 : vp->or |= (1 << 2); break; + case NV40_VP_INST_DEST_BFC1 : vp->or |= (1 << 3); break; + case NV40_VP_INST_DEST_FOGC: vp->or |= (1 << 4); break; + case NV40_VP_INST_DEST_PSZ : vp->or |= (1 << 5); break; } - break; } if(!nvfx->is_nv4x) { hw[3] |= (dst.index << NV30_VP_INST_DEST_SHIFT); - hw[0] |= NV30_VP_INST_VEC_DEST_TEMP_MASK | (1<<20); + hw[0] |= NV30_VP_INST_VEC_DEST_TEMP_MASK; /*XXX: no way this is entirely correct, someone needs to * figure out what exactly it is. @@ -264,7 +244,7 @@ emit_dst(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, uint32_t *hw, int slot hw[3] |= (dst.index << NV40_VP_INST_DEST_SHIFT); if (slot == 0) { hw[0] |= NV40_VP_INST_VEC_RESULT; - hw[0] |= NV40_VP_INST_VEC_DEST_TEMP_MASK | (1<<20); + hw[0] |= NV40_VP_INST_VEC_DEST_TEMP_MASK; } else { hw[3] |= NV40_VP_INST_SCA_RESULT; hw[3] |= NV40_VP_INST_SCA_DEST_TEMP_MASK; @@ -277,26 +257,27 @@ emit_dst(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, uint32_t *hw, int slot } static void -nvfx_vp_arith(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, int slot, int op, - struct nvfx_sreg dst, int mask, - struct nvfx_sreg s0, struct nvfx_sreg s1, - struct nvfx_sreg s2) +nvfx_vp_emit(struct nvfx_vpc *vpc, struct nvfx_insn insn) { + struct nvfx_context* nvfx = vpc->nvfx; struct nvfx_vertex_program *vp = vpc->vp; + unsigned slot = insn.op >> 7; + unsigned op = insn.op & 0x7f; uint32_t *hw; vp->insns = realloc(vp->insns, ++vp->nr_insns * sizeof(*vpc->vpi)); vpc->vpi = &vp->insns[vp->nr_insns - 1]; memset(vpc->vpi, 0, sizeof(*vpc->vpi)); - vpc->vpi->const_index = -1; hw = vpc->vpi->data; - hw[0] |= (NVFX_COND_TR << NVFX_VP(INST_COND_SHIFT)); - hw[0] |= ((0 << NVFX_VP(INST_COND_SWZ_X_SHIFT)) | - (1 << NVFX_VP(INST_COND_SWZ_Y_SHIFT)) | - (2 << NVFX_VP(INST_COND_SWZ_Z_SHIFT)) | - (3 << NVFX_VP(INST_COND_SWZ_W_SHIFT))); + hw[0] |= (insn.cc_test << NVFX_VP(INST_COND_SHIFT)); + hw[0] |= ((insn.cc_swz[0] << NVFX_VP(INST_COND_SWZ_X_SHIFT)) | + (insn.cc_swz[1] << NVFX_VP(INST_COND_SWZ_Y_SHIFT)) | + (insn.cc_swz[2] << NVFX_VP(INST_COND_SWZ_Z_SHIFT)) | + (insn.cc_swz[3] << NVFX_VP(INST_COND_SWZ_W_SHIFT))); + if(insn.cc_update) + hw[0] |= NVFX_VP(INST_COND_UPDATE_ENABLE); if(!nvfx->is_nv4x) { if(slot == 0) @@ -309,54 +290,56 @@ nvfx_vp_arith(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, int slot, int op, // hw[3] |= NVFX_VP(INST_SCA_DEST_TEMP_MASK); // hw[3] |= (mask << NVFX_VP(INST_VEC_WRITEMASK_SHIFT)); - if (dst.type == NVFXSR_OUTPUT) { + if (insn.dst.type == NVFXSR_OUTPUT) { if (slot) - hw[3] |= (mask << NV30_VP_INST_SDEST_WRITEMASK_SHIFT); + hw[3] |= (insn.mask << NV30_VP_INST_SDEST_WRITEMASK_SHIFT); else - hw[3] |= (mask << NV30_VP_INST_VDEST_WRITEMASK_SHIFT); + hw[3] |= (insn.mask << NV30_VP_INST_VDEST_WRITEMASK_SHIFT); } else { if (slot) - hw[3] |= (mask << NV30_VP_INST_STEMP_WRITEMASK_SHIFT); + hw[3] |= (insn.mask << NV30_VP_INST_STEMP_WRITEMASK_SHIFT); else - hw[3] |= (mask << NV30_VP_INST_VTEMP_WRITEMASK_SHIFT); + hw[3] |= (insn.mask << NV30_VP_INST_VTEMP_WRITEMASK_SHIFT); } } else { if (slot == 0) { hw[1] |= (op << NV40_VP_INST_VEC_OPCODE_SHIFT); hw[3] |= NV40_VP_INST_SCA_DEST_TEMP_MASK; - hw[3] |= (mask << NV40_VP_INST_VEC_WRITEMASK_SHIFT); + hw[3] |= (insn.mask << NV40_VP_INST_VEC_WRITEMASK_SHIFT); } else { hw[1] |= (op << NV40_VP_INST_SCA_OPCODE_SHIFT); - hw[0] |= (NV40_VP_INST_VEC_DEST_TEMP_MASK | (1 << 20)); - hw[3] |= (mask << NV40_VP_INST_SCA_WRITEMASK_SHIFT); + hw[0] |= NV40_VP_INST_VEC_DEST_TEMP_MASK ; + hw[3] |= (insn.mask << NV40_VP_INST_SCA_WRITEMASK_SHIFT); } } - emit_dst(nvfx, vpc, hw, slot, dst); - emit_src(nvfx, vpc, hw, 0, s0); - emit_src(nvfx, vpc, hw, 1, s1); - emit_src(nvfx, vpc, hw, 2, s2); + emit_dst(nvfx, vpc, hw, slot, insn.dst); + emit_src(nvfx, vpc, hw, 0, insn.src[0]); + emit_src(nvfx, vpc, hw, 1, insn.src[1]); + emit_src(nvfx, vpc, hw, 2, insn.src[2]); } -static INLINE struct nvfx_sreg +static inline struct nvfx_src tgsi_src(struct nvfx_vpc *vpc, const struct tgsi_full_src_register *fsrc) { - struct nvfx_sreg src = { 0 }; + struct nvfx_src src; switch (fsrc->Register.File) { case TGSI_FILE_INPUT: - src = nvfx_sr(NVFXSR_INPUT, fsrc->Register.Index); + src.reg = nvfx_reg(NVFXSR_INPUT, fsrc->Register.Index); break; case TGSI_FILE_CONSTANT: - src = constant(vpc, fsrc->Register.Index, 0, 0, 0, 0); + src.reg = constant(vpc, fsrc->Register.Index, 0, 0, 0, 0); break; case TGSI_FILE_IMMEDIATE: - src = vpc->imm[fsrc->Register.Index]; + src.reg = vpc->imm[fsrc->Register.Index]; break; case TGSI_FILE_TEMPORARY: - src = vpc->r_temp[fsrc->Register.Index]; + src.reg = vpc->r_temp[fsrc->Register.Index]; break; default: NOUVEAU_ERR("bad src file\n"); + src.reg.index = 0; + src.reg.type = 0; break; } @@ -369,11 +352,14 @@ tgsi_src(struct nvfx_vpc *vpc, const struct tgsi_full_src_register *fsrc) { return src; } -static INLINE struct nvfx_sreg +static INLINE struct nvfx_reg tgsi_dst(struct nvfx_vpc *vpc, const struct tgsi_full_dst_register *fdst) { - struct nvfx_sreg dst = { 0 }; + struct nvfx_reg dst; switch (fdst->Register.File) { + case TGSI_FILE_NULL: + dst = nvfx_reg(NVFXSR_NONE, 0); + break; case TGSI_FILE_OUTPUT: dst = vpc->r_result[fdst->Register.Index]; break; @@ -384,14 +370,16 @@ tgsi_dst(struct nvfx_vpc *vpc, const struct tgsi_full_dst_register *fdst) { dst = vpc->r_address[fdst->Register.Index]; break; default: - NOUVEAU_ERR("bad dst file\n"); + NOUVEAU_ERR("bad dst file %i\n", fdst->Register.File); + dst.index = 0; + dst.type = 0; break; } return dst; } -static INLINE int +static inline int tgsi_mask(uint tgsi) { int mask = 0; @@ -405,10 +393,14 @@ tgsi_mask(uint tgsi) static boolean nvfx_vertprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, - const struct tgsi_full_instruction *finst) + unsigned idx, const struct tgsi_full_instruction *finst) { - struct nvfx_sreg src[3], dst, tmp; - struct nvfx_sreg none = nvfx_sr(NVFXSR_NONE, 0); + struct nvfx_src src[3], tmp; + struct nvfx_reg dst; + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE, 0)); + struct nvfx_insn insn; + struct nvfx_relocation reloc; + struct nvfx_loop_entry loop; int mask; int ai = -1, ci = -1, ii = -1; int i; @@ -436,9 +428,8 @@ nvfx_vertprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, ai = fsrc->Register.Index; src[i] = tgsi_src(vpc, fsrc); } else { - src[i] = temp(vpc); - arith(vpc, VEC, MOV, src[i], NVFX_VP_MASK_ALL, - tgsi_src(vpc, fsrc), none, none); + src[i] = nvfx_src(temp(vpc)); + nvfx_vp_emit(vpc, arith(VEC, MOV, src[i].reg, NVFX_VP_MASK_ALL, tgsi_src(vpc, fsrc), none, none)); } break; case TGSI_FILE_CONSTANT: @@ -447,9 +438,8 @@ nvfx_vertprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, ci = fsrc->Register.Index; src[i] = tgsi_src(vpc, fsrc); } else { - src[i] = temp(vpc); - arith(vpc, VEC, MOV, src[i], NVFX_VP_MASK_ALL, - tgsi_src(vpc, fsrc), none, none); + src[i] = nvfx_src(temp(vpc)); + nvfx_vp_emit(vpc, arith(VEC, MOV, src[i].reg, NVFX_VP_MASK_ALL, tgsi_src(vpc, fsrc), none, none)); } break; case TGSI_FILE_IMMEDIATE: @@ -458,9 +448,8 @@ nvfx_vertprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, ii = fsrc->Register.Index; src[i] = tgsi_src(vpc, fsrc); } else { - src[i] = temp(vpc); - arith(vpc, VEC, MOV, src[i], NVFX_VP_MASK_ALL, - tgsi_src(vpc, fsrc), none, none); + src[i] = nvfx_src(temp(vpc)); + nvfx_vp_emit(vpc, arith(VEC, MOV, src[i].reg, NVFX_VP_MASK_ALL, tgsi_src(vpc, fsrc), none, none)); } break; case TGSI_FILE_TEMPORARY: @@ -477,128 +466,231 @@ nvfx_vertprog_parse_instruction(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, switch (finst->Instruction.Opcode) { case TGSI_OPCODE_ABS: - arith(vpc, VEC, MOV, dst, mask, abs(src[0]), none, none); + nvfx_vp_emit(vpc, arith(VEC, MOV, dst, mask, abs(src[0]), none, none)); break; case TGSI_OPCODE_ADD: - arith(vpc, VEC, ADD, dst, mask, src[0], none, src[1]); + nvfx_vp_emit(vpc, arith(VEC, ADD, dst, mask, src[0], none, src[1])); break; case TGSI_OPCODE_ARL: - arith(vpc, VEC, ARL, dst, mask, src[0], none, none); + nvfx_vp_emit(vpc, arith(VEC, ARL, dst, mask, src[0], none, none)); + break; + case TGSI_OPCODE_CMP: + insn = arith(VEC, MOV, none.reg, mask, src[0], none, none); + insn.cc_update = 1; + nvfx_vp_emit(vpc, insn); + + insn = arith(VEC, MOV, dst, mask, src[2], none, none); + insn.cc_test = NVFX_COND_GE; + nvfx_vp_emit(vpc, insn); + + insn = arith(VEC, MOV, dst, mask, src[1], none, none); + insn.cc_test = NVFX_COND_LT; + nvfx_vp_emit(vpc, insn); break; case TGSI_OPCODE_COS: - arith(vpc, SCA, COS, dst, mask, none, none, src[0]); + nvfx_vp_emit(vpc, arith(SCA, COS, dst, mask, none, none, src[0])); break; + case TGSI_OPCODE_DP2: + tmp = nvfx_src(temp(vpc)); + nvfx_vp_emit(vpc, arith(VEC, MUL, tmp.reg, NVFX_VP_MASK_X | NVFX_VP_MASK_Y, src[0], src[1], none)); + nvfx_vp_emit(vpc, arith(VEC, ADD, dst, mask, swz(tmp, X, X, X, X), swz(tmp, Y, Y, Y, Y), none)); + break; case TGSI_OPCODE_DP3: - arith(vpc, VEC, DP3, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, DP3, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_DP4: - arith(vpc, VEC, DP4, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, DP4, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_DPH: - arith(vpc, VEC, DPH, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, DPH, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_DST: - arith(vpc, VEC, DST, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, DST, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_EX2: - arith(vpc, SCA, EX2, dst, mask, none, none, src[0]); + nvfx_vp_emit(vpc, arith(SCA, EX2, dst, mask, none, none, src[0])); break; case TGSI_OPCODE_EXP: - arith(vpc, SCA, EXP, dst, mask, none, none, src[0]); + nvfx_vp_emit(vpc, arith(SCA, EXP, dst, mask, none, none, src[0])); break; case TGSI_OPCODE_FLR: - arith(vpc, VEC, FLR, dst, mask, src[0], none, none); + nvfx_vp_emit(vpc, arith(VEC, FLR, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_FRC: - arith(vpc, VEC, FRC, dst, mask, src[0], none, none); + nvfx_vp_emit(vpc, arith(VEC, FRC, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_LG2: - arith(vpc, SCA, LG2, dst, mask, none, none, src[0]); + nvfx_vp_emit(vpc, arith(SCA, LG2, dst, mask, none, none, src[0])); break; case TGSI_OPCODE_LIT: - arith(vpc, SCA, LIT, dst, mask, none, none, src[0]); + nvfx_vp_emit(vpc, arith(SCA, LIT, dst, mask, none, none, src[0])); break; case TGSI_OPCODE_LOG: - arith(vpc, SCA, LOG, dst, mask, none, none, src[0]); + nvfx_vp_emit(vpc, arith(SCA, LOG, dst, mask, none, none, src[0])); break; case TGSI_OPCODE_LRP: - tmp = temp(vpc); - arith(vpc, VEC, MAD, tmp, mask, neg(src[0]), src[2], src[2]); - arith(vpc, VEC, MAD, dst, mask, src[0], src[1], tmp); + tmp = nvfx_src(temp(vpc)); + nvfx_vp_emit(vpc, arith(VEC, MAD, tmp.reg, mask, neg(src[0]), src[2], src[2])); + nvfx_vp_emit(vpc, arith(VEC, MAD, dst, mask, src[0], src[1], tmp)); break; case TGSI_OPCODE_MAD: - arith(vpc, VEC, MAD, dst, mask, src[0], src[1], src[2]); + nvfx_vp_emit(vpc, arith(VEC, MAD, dst, mask, src[0], src[1], src[2])); break; case TGSI_OPCODE_MAX: - arith(vpc, VEC, MAX, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, MAX, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_MIN: - arith(vpc, VEC, MIN, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, MIN, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_MOV: - arith(vpc, VEC, MOV, dst, mask, src[0], none, none); + nvfx_vp_emit(vpc, arith(VEC, MOV, dst, mask, src[0], none, none)); break; case TGSI_OPCODE_MUL: - arith(vpc, VEC, MUL, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, MUL, dst, mask, src[0], src[1], none)); + break; + case TGSI_OPCODE_NOP: break; case TGSI_OPCODE_POW: - tmp = temp(vpc); - arith(vpc, SCA, LG2, tmp, NVFX_VP_MASK_X, none, none, - swz(src[0], X, X, X, X)); - arith(vpc, VEC, MUL, tmp, NVFX_VP_MASK_X, swz(tmp, X, X, X, X), - swz(src[1], X, X, X, X), none); - arith(vpc, SCA, EX2, dst, mask, none, none, - swz(tmp, X, X, X, X)); + tmp = nvfx_src(temp(vpc)); + nvfx_vp_emit(vpc, arith(SCA, LG2, tmp.reg, NVFX_VP_MASK_X, none, none, swz(src[0], X, X, X, X))); + nvfx_vp_emit(vpc, arith(VEC, MUL, tmp.reg, NVFX_VP_MASK_X, swz(tmp, X, X, X, X), swz(src[1], X, X, X, X), none)); + nvfx_vp_emit(vpc, arith(SCA, EX2, dst, mask, none, none, swz(tmp, X, X, X, X))); break; case TGSI_OPCODE_RCP: - arith(vpc, SCA, RCP, dst, mask, none, none, src[0]); - break; - case TGSI_OPCODE_RET: + nvfx_vp_emit(vpc, arith(SCA, RCP, dst, mask, none, none, src[0])); break; case TGSI_OPCODE_RSQ: - arith(vpc, SCA, RSQ, dst, mask, none, none, abs(src[0])); + nvfx_vp_emit(vpc, arith(SCA, RSQ, dst, mask, none, none, abs(src[0]))); break; case TGSI_OPCODE_SEQ: - arith(vpc, VEC, SEQ, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, SEQ, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SFL: - arith(vpc, VEC, SFL, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, SFL, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SGE: - arith(vpc, VEC, SGE, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, SGE, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SGT: - arith(vpc, VEC, SGT, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, SGT, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SIN: - arith(vpc, SCA, SIN, dst, mask, none, none, src[0]); + nvfx_vp_emit(vpc, arith(SCA, SIN, dst, mask, none, none, src[0])); break; case TGSI_OPCODE_SLE: - arith(vpc, VEC, SLE, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, SLE, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SLT: - arith(vpc, VEC, SLT, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, SLT, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SNE: - arith(vpc, VEC, SNE, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, SNE, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SSG: - arith(vpc, VEC, SSG, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, SSG, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_STR: - arith(vpc, VEC, STR, dst, mask, src[0], src[1], none); + nvfx_vp_emit(vpc, arith(VEC, STR, dst, mask, src[0], src[1], none)); break; case TGSI_OPCODE_SUB: - arith(vpc, VEC, ADD, dst, mask, src[0], none, neg(src[1])); + nvfx_vp_emit(vpc, arith(VEC, ADD, dst, mask, src[0], none, neg(src[1]))); break; + case TGSI_OPCODE_TRUNC: + tmp = nvfx_src(temp(vpc)); + insn = arith(VEC, MOV, none.reg, mask, src[0], none, none); + insn.cc_update = 1; + nvfx_vp_emit(vpc, insn); + + nvfx_vp_emit(vpc, arith(VEC, FLR, tmp.reg, mask, abs(src[0]), none, none)); + nvfx_vp_emit(vpc, arith(VEC, MOV, dst, mask, tmp, none, none)); + + insn = arith(VEC, MOV, dst, mask, neg(tmp), none, none); + insn.cc_test = NVFX_COND_LT; + nvfx_vp_emit(vpc, insn); + break; case TGSI_OPCODE_XPD: - tmp = temp(vpc); - arith(vpc, VEC, MUL, tmp, mask, - swz(src[0], Z, X, Y, Y), swz(src[1], Y, Z, X, X), none); - arith(vpc, VEC, MAD, dst, (mask & ~NVFX_VP_MASK_W), - swz(src[0], Y, Z, X, X), swz(src[1], Z, X, Y, Y), - neg(tmp)); + tmp = nvfx_src(temp(vpc)); + nvfx_vp_emit(vpc, arith(VEC, MUL, tmp.reg, mask, swz(src[0], Z, X, Y, Y), swz(src[1], Y, Z, X, X), none)); + nvfx_vp_emit(vpc, arith(VEC, MAD, dst, (mask & ~NVFX_VP_MASK_W), swz(src[0], Y, Z, X, X), swz(src[1], Z, X, Y, Y), neg(tmp))); + break; + + case TGSI_OPCODE_IF: + insn = arith(VEC, MOV, none.reg, NVFX_VP_MASK_X, src[0], none, none); + insn.cc_update = 1; + nvfx_vp_emit(vpc, insn); + + reloc.location = vpc->vp->nr_insns; + reloc.target = finst->Label.Label + 1; + util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc); + + insn = arith(SCA, BRA, none.reg, 0, none, none, none); + insn.cc_test = NVFX_COND_EQ; + insn.cc_swz[0] = insn.cc_swz[1] = insn.cc_swz[2] = insn.cc_swz[3] = 0; + nvfx_vp_emit(vpc, insn); break; + + case TGSI_OPCODE_ELSE: + case TGSI_OPCODE_BRA: + case TGSI_OPCODE_CAL: + reloc.location = vpc->vp->nr_insns; + reloc.target = finst->Label.Label; + util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc); + + if(finst->Instruction.Opcode == TGSI_OPCODE_CAL) + insn = arith(SCA, CAL, none.reg, 0, none, none, none); + else + insn = arith(SCA, BRA, none.reg, 0, none, none, none); + nvfx_vp_emit(vpc, insn); + break; + + case TGSI_OPCODE_RET: + tmp = none; + tmp.swz[0] = tmp.swz[1] = tmp.swz[2] = tmp.swz[3] = 0; + nvfx_vp_emit(vpc, arith(SCA, RET, none.reg, 0, none, none, tmp)); + break; + + case TGSI_OPCODE_BGNSUB: + case TGSI_OPCODE_ENDSUB: + case TGSI_OPCODE_ENDIF: + /* nothing to do here */ + break; + + case TGSI_OPCODE_BGNLOOP: + loop.cont_target = idx; + loop.brk_target = finst->Label.Label + 1; + util_dynarray_append(&vpc->loop_stack, struct nvfx_loop_entry, loop); + break; + + case TGSI_OPCODE_ENDLOOP: + loop = util_dynarray_pop(&vpc->loop_stack, struct nvfx_loop_entry); + + reloc.location = vpc->vp->nr_insns; + reloc.target = loop.cont_target; + util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc); + + nvfx_vp_emit(vpc, arith(SCA, BRA, none.reg, 0, none, none, none)); + break; + + case TGSI_OPCODE_CONT: + loop = util_dynarray_top(&vpc->loop_stack, struct nvfx_loop_entry); + + reloc.location = vpc->vp->nr_insns; + reloc.target = loop.cont_target; + util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc); + + nvfx_vp_emit(vpc, arith(SCA, BRA, none.reg, 0, none, none, none)); + break; + + case TGSI_OPCODE_BRK: + loop = util_dynarray_top(&vpc->loop_stack, struct nvfx_loop_entry); + + reloc.location = vpc->vp->nr_insns; + reloc.target = loop.brk_target; + util_dynarray_append(&vpc->label_relocs, struct nvfx_relocation, reloc); + + nvfx_vp_emit(vpc, arith(SCA, BRA, none.reg, 0, none, none, none)); + break; + default: NOUVEAU_ERR("invalid opcode %d\n", finst->Instruction.Opcode); return FALSE; @@ -649,12 +741,8 @@ nvfx_vertprog_parse_decl_output(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, hw = NVFX_VP(INST_DEST_PSZ); break; case TGSI_SEMANTIC_GENERIC: - if (fdec->Semantic.Index <= 7) { - hw = NVFX_VP(INST_DEST_TC(fdec->Semantic.Index)); - } else { - NOUVEAU_ERR("bad generic semantic index\n"); - return FALSE; - } + hw = (vpc->vp->generic_to_fp_input[fdec->Semantic.Index] & 0xf) + + NVFX_VP(INST_DEST_TC(0)) - NVFX_FP_OP_INPUT_SRC_TC(0); break; case TGSI_SEMANTIC_EDGEFLAG: /* not really an error just a fallback */ @@ -665,7 +753,7 @@ nvfx_vertprog_parse_decl_output(struct nvfx_context* nvfx, struct nvfx_vpc *vpc, return FALSE; } - vpc->r_result[idx] = nvfx_sr(NVFXSR_OUTPUT, hw); + vpc->r_result[idx] = nvfx_reg(NVFXSR_OUTPUT, hw); return TRUE; } @@ -674,6 +762,36 @@ nvfx_vertprog_prepare(struct nvfx_context* nvfx, struct nvfx_vpc *vpc) { struct tgsi_parse_context p; int high_temp = -1, high_addr = -1, nr_imm = 0, i; + struct util_semantic_set set; + unsigned char sem_layout[8]; + unsigned num_outputs; + + num_outputs = util_semantic_set_from_program_file(&set, vpc->vp->pipe.tokens, TGSI_FILE_OUTPUT); + + if(num_outputs > 8) { + NOUVEAU_ERR("too many vertex program outputs: %i\n", num_outputs); + return FALSE; + } + util_semantic_layout_from_set(sem_layout, &set, 8, 8); + + /* hope 0xf is (0, 0, 0, 1) initialized; otherwise, we are _probably_ not required to do this */ + memset(vpc->vp->generic_to_fp_input, 0x0f, sizeof(vpc->vp->generic_to_fp_input)); + for(int i = 0; i < 8; ++i) { + if(sem_layout[i] == 0xff) + continue; + //printf("vp: GENERIC[%i] to fpreg %i\n", sem_layout[i], NVFX_FP_OP_INPUT_SRC_TC(0) + i); + vpc->vp->generic_to_fp_input[sem_layout[i]] = 0xf0 | NVFX_FP_OP_INPUT_SRC_TC(i); + } + + vpc->vp->sprite_fp_input = -1; + for(int i = 0; i < 8; ++i) + { + if(sem_layout[i] == 0xff) + { + vpc->vp->sprite_fp_input = NVFX_FP_OP_INPUT_SRC_TC(i); + break; + } + } tgsi_parse_init(&p, vpc->vp->pipe.tokens); while (!tgsi_parse_end_of_tokens(&p)) { @@ -737,18 +855,18 @@ nvfx_vertprog_prepare(struct nvfx_context* nvfx, struct nvfx_vpc *vpc) tgsi_parse_free(&p); if (nr_imm) { - vpc->imm = CALLOC(nr_imm, sizeof(struct nvfx_sreg)); + vpc->imm = CALLOC(nr_imm, sizeof(struct nvfx_reg)); assert(vpc->imm); } if (++high_temp) { - vpc->r_temp = CALLOC(high_temp, sizeof(struct nvfx_sreg)); + vpc->r_temp = CALLOC(high_temp, sizeof(struct nvfx_reg)); for (i = 0; i < high_temp; i++) vpc->r_temp[i] = temp(vpc); } if (++high_addr) { - vpc->r_address = CALLOC(high_addr, sizeof(struct nvfx_sreg)); + vpc->r_address = CALLOC(high_addr, sizeof(struct nvfx_reg)); for (i = 0; i < high_addr; i++) vpc->r_address[i] = temp(vpc); } @@ -757,20 +875,31 @@ nvfx_vertprog_prepare(struct nvfx_context* nvfx, struct nvfx_vpc *vpc) return TRUE; } +DEBUG_GET_ONCE_BOOL_OPTION(nvfx_dump_vp, "NVFX_DUMP_VP", FALSE) + static void nvfx_vertprog_translate(struct nvfx_context *nvfx, struct nvfx_vertex_program *vp) { struct tgsi_parse_context parse; struct nvfx_vpc *vpc = NULL; - struct nvfx_sreg none = nvfx_sr(NVFXSR_NONE, 0); + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE, 0)); + struct util_dynarray insns; int i; vpc = CALLOC(1, sizeof(struct nvfx_vpc)); if (!vpc) return; + vpc->nvfx = nvfx; vpc->vp = vp; + /* reserve space for ucps */ + if(nvfx->use_vp_clipping) + { + for(i = 0; i < 6; ++i) + constant(vpc, -1, 0, 0, 0, 0); + } + if (!nvfx_vertprog_prepare(nvfx, vpc)) { FREE(vpc); return; @@ -780,13 +909,15 @@ nvfx_vertprog_translate(struct nvfx_context *nvfx, * planes are enabled. We need to append code to the vtxprog * to handle clip planes later. */ - if (vp->ucp.nr) { + /* TODO: maybe support patching this depending on whether there are ucps: not sure if it is really matters much */ + if (nvfx->use_vp_clipping) { vpc->r_result[vpc->hpos_idx] = temp(vpc); vpc->r_temps_discard = 0; } tgsi_parse_init(&parse, vp->pipe.tokens); + util_dynarray_init(&insns); while (!tgsi_parse_end_of_tokens(&parse)) { tgsi_parse_token(&parse); @@ -809,8 +940,10 @@ nvfx_vertprog_translate(struct nvfx_context *nvfx, case TGSI_TOKEN_TYPE_INSTRUCTION: { const struct tgsi_full_instruction *finst; + unsigned idx = insns.size >> 2; + util_dynarray_append(&insns, unsigned, vp->nr_insns); finst = &parse.FullToken.FullInstruction; - if (!nvfx_vertprog_parse_instruction(nvfx, vpc, finst)) + if (!nvfx_vertprog_parse_instruction(nvfx, vpc, idx, finst)) goto out_err; } break; @@ -819,43 +952,87 @@ nvfx_vertprog_translate(struct nvfx_context *nvfx, } } + util_dynarray_append(&insns, unsigned, vp->nr_insns); + + for(unsigned i = 0; i < vpc->label_relocs.size; i += sizeof(struct nvfx_relocation)) + { + struct nvfx_relocation* label_reloc = (struct nvfx_relocation*)((char*)vpc->label_relocs.data + i); + struct nvfx_relocation hw_reloc; + + hw_reloc.location = label_reloc->location; + hw_reloc.target = ((unsigned*)insns.data)[label_reloc->target]; + + //debug_printf("hw %u -> tgsi %u = hw %u\n", hw_reloc.location, label_reloc->target, hw_reloc.target); + + util_dynarray_append(&vp->branch_relocs, struct nvfx_relocation, hw_reloc); + } + util_dynarray_fini(&insns); + util_dynarray_trim(&vp->branch_relocs); + + /* XXX: what if we add a RET before?! make sure we jump here...*/ + /* Write out HPOS if it was redirected to a temp earlier */ if (vpc->r_result[vpc->hpos_idx].type != NVFXSR_OUTPUT) { - struct nvfx_sreg hpos = nvfx_sr(NVFXSR_OUTPUT, + struct nvfx_reg hpos = nvfx_reg(NVFXSR_OUTPUT, NVFX_VP(INST_DEST_POS)); - struct nvfx_sreg htmp = vpc->r_result[vpc->hpos_idx]; + struct nvfx_src htmp = nvfx_src(vpc->r_result[vpc->hpos_idx]); - arith(vpc, VEC, MOV, hpos, NVFX_VP_MASK_ALL, htmp, none, none); + nvfx_vp_emit(vpc, arith(VEC, MOV, hpos, NVFX_VP_MASK_ALL, htmp, none, none)); } /* Insert code to handle user clip planes */ - for (i = 0; i < vp->ucp.nr; i++) { - struct nvfx_sreg cdst = nvfx_sr(NVFXSR_OUTPUT, - NVFX_VP_INST_DEST_CLIP(i)); - struct nvfx_sreg ceqn = constant(vpc, -1, - nvfx->clip.ucp[i][0], - nvfx->clip.ucp[i][1], - nvfx->clip.ucp[i][2], - nvfx->clip.ucp[i][3]); - struct nvfx_sreg htmp = vpc->r_result[vpc->hpos_idx]; - unsigned mask; - - switch (i) { - case 0: case 3: mask = NVFX_VP_MASK_Y; break; - case 1: case 4: mask = NVFX_VP_MASK_Z; break; - case 2: case 5: mask = NVFX_VP_MASK_W; break; - default: - NOUVEAU_ERR("invalid clip dist #%d\n", i); - goto out_err; + if(nvfx->use_vp_clipping) + { + for (i = 0; i < 6; i++) { + struct nvfx_reg cdst = nvfx_reg(NVFXSR_OUTPUT, NV30_VP_INST_DEST_CLP(i)); + struct nvfx_src ceqn = nvfx_src(nvfx_reg(NVFXSR_CONST, i)); + struct nvfx_src htmp = nvfx_src(vpc->r_result[vpc->hpos_idx]); + unsigned mask; + + if(nvfx->is_nv4x) + { + switch (i) { + case 0: case 3: mask = NVFX_VP_MASK_Y; break; + case 1: case 4: mask = NVFX_VP_MASK_Z; break; + case 2: case 5: mask = NVFX_VP_MASK_W; break; + default: + NOUVEAU_ERR("invalid clip dist #%d\n", i); + goto out_err; + } + } + else + mask = NVFX_VP_MASK_X; + + nvfx_vp_emit(vpc, arith(VEC, DP4, cdst, mask, htmp, ceqn, none)); } + } + else + { + if(vp->nr_insns) + vp->insns[vp->nr_insns - 1].data[3] |= NVFX_VP_INST_LAST; - arith(vpc, VEC, DP4, cdst, mask, htmp, ceqn, none); + nvfx_vp_emit(vpc, arith(VEC, NOP, none.reg, 0, none, none, none)); + vp->insns[vp->nr_insns - 1].data[3] |= NVFX_VP_INST_LAST; } - vp->insns[vp->nr_insns - 1].data[3] |= NVFX_VP_INST_LAST; + if(debug_get_option_nvfx_dump_vp()) + { + debug_printf("\n"); + tgsi_dump(vp->pipe.tokens, 0); + + debug_printf("\n%s vertex program:\n", nvfx->is_nv4x ? "nv4x" : "nv3x"); + for (i = 0; i < vp->nr_insns; i++) + debug_printf("%3u: %08x %08x %08x %08x\n", i, vp->insns[i].data[0], vp->insns[i].data[1], vp->insns[i].data[2], vp->insns[i].data[3]); + debug_printf("\n"); + } + + vp->clip_nr = -1; + vp->exec_start = -1; vp->translated = TRUE; out_err: tgsi_parse_free(&parse); + util_dynarray_fini(&vpc->label_relocs); + util_dynarray_fini(&vpc->loop_stack); if (vpc->r_temp) FREE(vpc->r_temp); if (vpc->r_address) @@ -868,26 +1045,17 @@ out_err: boolean nvfx_vertprog_validate(struct nvfx_context *nvfx) { - struct pipe_context *pipe = &nvfx->pipe; struct nvfx_screen *screen = nvfx->screen; struct nouveau_channel *chan = screen->base.channel; struct nouveau_grobj *eng3d = screen->eng3d; struct nvfx_vertex_program *vp; struct pipe_resource *constbuf; - struct pipe_transfer *transfer = NULL; boolean upload_code = FALSE, upload_data = FALSE; int i; if (nvfx->render_mode == HW) { vp = nvfx->vertprog; constbuf = nvfx->constbuf[PIPE_SHADER_VERTEX]; - - // TODO: ouch! can't we just use constant slots for these?! - if ((nvfx->dirty & NVFX_NEW_UCP) || - memcmp(&nvfx->clip, &vp->ucp, sizeof(vp->ucp))) { - nvfx_vertprog_destroy(nvfx, vp); - memcpy(&vp->ucp, &nvfx->clip, sizeof(vp->ucp)); - } } else { vp = nvfx->swtnl.vertprog; constbuf = NULL; @@ -918,7 +1086,11 @@ nvfx_vertprog_validate(struct nvfx_context *nvfx) } if (nouveau_resource_alloc(heap, vplen, vp, &vp->exec)) - assert(0); + { + debug_printf("Vertex shader too long: %u instructions\n", vplen); + nvfx->fallback_swtnl |= NVFX_NEW_VERTPROG; + return FALSE; + } } upload_code = TRUE; @@ -937,7 +1109,11 @@ nvfx_vertprog_validate(struct nvfx_context *nvfx) } if (nouveau_resource_alloc(heap, vp->nr_consts, vp, &vp->data)) - assert(0); + { + debug_printf("Vertex shader uses too many constants: %u constants\n", vp->nr_consts); + nvfx->fallback_swtnl |= NVFX_NEW_VERTPROG; + return FALSE; + } } /*XXX: handle this some day */ @@ -952,44 +1128,57 @@ nvfx_vertprog_validate(struct nvfx_context *nvfx) * fixup offsets and register IDs. */ if (vp->exec_start != vp->exec->start) { - for (i = 0; i < vp->nr_insns; i++) { - struct nvfx_vertex_program_exec *vpi = &vp->insns[i]; + //printf("vp_relocs %u -> %u\n", vp->exec_start, vp->exec->start); + for(unsigned i = 0; i < vp->branch_relocs.size; i += sizeof(struct nvfx_relocation)) + { + struct nvfx_relocation* reloc = (struct nvfx_relocation*)((char*)vp->branch_relocs.data + i); + uint32_t* hw = vp->insns[reloc->location].data; + unsigned target = vp->exec->start + reloc->target; + + //debug_printf("vp_reloc hw %u -> hw %u\n", reloc->location, target); - if (vpi->has_branch_offset) { - assert(0); + if(!nvfx->is_nv4x) + { + hw[2] &=~ NV30_VP_INST_IADDR_MASK; + hw[2] |= (target & 0x1ff) << NV30_VP_INST_IADDR_SHIFT; + } + else + { + hw[3] &=~ NV40_VP_INST_IADDRL_MASK; + hw[3] |= (target & 7) << NV40_VP_INST_IADDRL_SHIFT; + + hw[2] &=~ NV40_VP_INST_IADDRH_MASK; + hw[2] |= ((target >> 3) & 0x3f) << NV40_VP_INST_IADDRH_SHIFT; } } vp->exec_start = vp->exec->start; } - if (vp->nr_consts && vp->data_start != vp->data->start) { - for (i = 0; i < vp->nr_insns; i++) { - struct nvfx_vertex_program_exec *vpi = &vp->insns[i]; + if (vp->data_start != vp->data->start) { + for(unsigned i = 0; i < vp->const_relocs.size; i += sizeof(struct nvfx_relocation)) + { + struct nvfx_relocation* reloc = (struct nvfx_relocation*)((char*)vp->const_relocs.data + i); + struct nvfx_vertex_program_exec *vpi = &vp->insns[reloc->location]; - if (vpi->const_index >= 0) { - vpi->data[1] &= ~NVFX_VP(INST_CONST_SRC_MASK); - vpi->data[1] |= - (vpi->const_index + vp->data->start) << + vpi->data[1] &= ~NVFX_VP(INST_CONST_SRC_MASK); + vpi->data[1] |= + (reloc->target + vp->data->start) << NVFX_VP(INST_CONST_SRC_SHIFT); - - } } vp->data_start = vp->data->start; + upload_code = TRUE; } /* Update + Upload constant values */ if (vp->nr_consts) { float *map = NULL; - if (constbuf) { - map = pipe_buffer_map(pipe, constbuf, - PIPE_TRANSFER_READ, - &transfer); - } + if (constbuf) + map = (float*)nvfx_buffer(constbuf)->data; - for (i = 0; i < vp->nr_consts; i++) { + for (i = nvfx->use_vp_clipping ? 6 : 0; i < vp->nr_consts; i++) { struct nvfx_vertex_program_data *vpd = &vp->consts[i]; if (vpd->index >= 0) { @@ -1005,41 +1194,28 @@ nvfx_vertprog_validate(struct nvfx_context *nvfx) OUT_RING (chan, i + vp->data->start); OUT_RINGp (chan, (uint32_t *)vpd->value, 4); } - - if (constbuf) - pipe_buffer_unmap(pipe, constbuf, transfer); } /* Upload vtxprog */ if (upload_code) { -#if 0 - for (i = 0; i < vp->nr_insns; i++) { - NOUVEAU_MSG("VP %d: 0x%08x\n", i, vp->insns[i].data[0]); - NOUVEAU_MSG("VP %d: 0x%08x\n", i, vp->insns[i].data[1]); - NOUVEAU_MSG("VP %d: 0x%08x\n", i, vp->insns[i].data[2]); - NOUVEAU_MSG("VP %d: 0x%08x\n", i, vp->insns[i].data[3]); - } -#endif BEGIN_RING(chan, eng3d, NV34TCL_VP_UPLOAD_FROM_ID, 1); OUT_RING (chan, vp->exec->start); for (i = 0; i < vp->nr_insns; i++) { BEGIN_RING(chan, eng3d, NV34TCL_VP_UPLOAD_INST(0), 4); OUT_RINGp (chan, vp->insns[i].data, 4); } + vp->clip_nr = -1; } - if(nvfx->dirty & (NVFX_NEW_VERTPROG | NVFX_NEW_UCP)) + if(nvfx->dirty & (NVFX_NEW_VERTPROG)) { - WAIT_RING(chan, 7); + WAIT_RING(chan, 6); OUT_RING(chan, RING_3D(NV34TCL_VP_START_FROM_ID, 1)); OUT_RING(chan, vp->exec->start); if(nvfx->is_nv4x) { - OUT_RING(chan, RING_3D(NV40TCL_VP_ATTRIB_EN, 2)); + OUT_RING(chan, RING_3D(NV40TCL_VP_ATTRIB_EN, 1)); OUT_RING(chan, vp->ir); - OUT_RING(chan, vp->or); } - OUT_RING(chan, RING_3D(NV34TCL_VP_CLIP_PLANES_ENABLE, 1)); - OUT_RING(chan, vp->clip_ctrl); } return TRUE; @@ -1048,25 +1224,63 @@ nvfx_vertprog_validate(struct nvfx_context *nvfx) void nvfx_vertprog_destroy(struct nvfx_context *nvfx, struct nvfx_vertex_program *vp) { - vp->translated = FALSE; - - if (vp->nr_insns) { + if (vp->nr_insns) FREE(vp->insns); - vp->insns = NULL; - vp->nr_insns = 0; - } - if (vp->nr_consts) { + if (vp->nr_consts) FREE(vp->consts); - vp->consts = NULL; - vp->nr_consts = 0; - } nouveau_resource_free(&vp->exec); - vp->exec_start = 0; nouveau_resource_free(&vp->data); - vp->data_start = 0; - vp->data_start_min = 0; - vp->ir = vp->or = vp->clip_ctrl = 0; + util_dynarray_fini(&vp->branch_relocs); + util_dynarray_fini(&vp->const_relocs); +} + +static void * +nvfx_vp_state_create(struct pipe_context *pipe, + const struct pipe_shader_state *cso) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + struct nvfx_vertex_program *vp; + + // TODO: use a 64-bit atomic here! + static unsigned long long id = 0; + + vp = CALLOC(1, sizeof(struct nvfx_vertex_program)); + vp->pipe.tokens = tgsi_dup_tokens(cso->tokens); + vp->draw = draw_create_vertex_shader(nvfx->draw, &vp->pipe); + vp->id = ++id; + + return (void *)vp; +} + +static void +nvfx_vp_state_bind(struct pipe_context *pipe, void *hwcso) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + + nvfx->vertprog = hwcso; + nvfx->dirty |= NVFX_NEW_VERTPROG; + nvfx->draw_dirty |= NVFX_NEW_VERTPROG; +} + +static void +nvfx_vp_state_delete(struct pipe_context *pipe, void *hwcso) +{ + struct nvfx_context *nvfx = nvfx_context(pipe); + struct nvfx_vertex_program *vp = hwcso; + + draw_delete_vertex_shader(nvfx->draw, vp->draw); + nvfx_vertprog_destroy(nvfx, vp); + FREE((void*)vp->pipe.tokens); + FREE(vp); +} + +void +nvfx_init_vertprog_functions(struct nvfx_context *nvfx) +{ + nvfx->pipe.create_vs_state = nvfx_vp_state_create; + nvfx->pipe.bind_vs_state = nvfx_vp_state_bind; + nvfx->pipe.delete_vs_state = nvfx_vp_state_delete; } diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c index e8b6c4f7af..624dadd07d 100644 --- a/src/gallium/drivers/r300/r300_context.c +++ b/src/gallium/drivers/r300/r300_context.c @@ -65,7 +65,7 @@ static void r300_release_referenced_objects(struct r300_context *r300) unsigned i; /* Framebuffer state. */ - util_assign_framebuffer_state(fb, NULL); + util_unreference_framebuffer_state(fb); /* Textures. */ for (i = 0; i < textures->sampler_view_count; i++) @@ -99,8 +99,10 @@ static void r300_destroy_context(struct pipe_context* context) struct r300_context* r300 = r300_context(context); struct r300_atom *atom; - util_blitter_destroy(r300->blitter); - draw_destroy(r300->draw); + if (r300->blitter) + util_blitter_destroy(r300->blitter); + if (r300->draw) + draw_destroy(r300->draw); /* Print stats, if enabled. */ if (SCREEN_DBG_ON(r300->screen, DBG_STATS)) { @@ -112,40 +114,48 @@ static void r300_destroy_context(struct pipe_context* context) } } - u_upload_destroy(r300->upload_vb); - u_upload_destroy(r300->upload_ib); + if (r300->upload_vb) + u_upload_destroy(r300->upload_vb); + if (r300->upload_ib) + u_upload_destroy(r300->upload_ib); - /* setup hyper-z mm */ - if (r300->rws->get_value(r300->rws, R300_CAN_HYPERZ)) - r300_hyperz_destroy_mm(r300); - - translate_cache_destroy(r300->tran.translate_cache); + if (r300->tran.translate_cache) + translate_cache_destroy(r300->tran.translate_cache); + /* XXX: This function assumes r300->query_list was initialized */ r300_release_referenced_objects(r300); - r300->rws->cs_destroy(r300->cs); + if (r300->zmask_mm) + r300_hyperz_destroy_mm(r300); + + if (r300->cs) + r300->rws->cs_destroy(r300->cs); + /* XXX: No way to tell if this was initialized or not? */ util_mempool_destroy(&r300->pool_transfers); r300_update_num_contexts(r300->screen, -1); - FREE(r300->aa_state.state); - FREE(r300->blend_color_state.state); - FREE(r300->clip_state.state); - FREE(r300->fb_state.state); - FREE(r300->gpu_flush.state); - FREE(r300->hyperz_state.state); - FREE(r300->invariant_state.state); - FREE(r300->rs_block_state.state); - FREE(r300->scissor_state.state); - FREE(r300->textures_state.state); - FREE(r300->vap_invariant_state.state); - FREE(r300->viewport_state.state); - FREE(r300->ztop_state.state); - FREE(r300->fs_constants.state); - FREE(r300->vs_constants.state); - if (!r300->screen->caps.has_tcl) { - FREE(r300->vertex_stream_state.state); + /* Free the structs allocated in r300_setup_atoms() */ + if (r300->aa_state.state) { + FREE(r300->aa_state.state); + FREE(r300->blend_color_state.state); + FREE(r300->clip_state.state); + FREE(r300->fb_state.state); + FREE(r300->gpu_flush.state); + FREE(r300->hyperz_state.state); + FREE(r300->invariant_state.state); + FREE(r300->rs_block_state.state); + FREE(r300->scissor_state.state); + FREE(r300->textures_state.state); + FREE(r300->vap_invariant_state.state); + FREE(r300->viewport_state.state); + FREE(r300->ztop_state.state); + FREE(r300->fs_constants.state); + FREE(r300->vs_constants.state); + if (!r300->screen->caps.has_tcl) { + FREE(r300->vertex_stream_state.state); + } } FREE(r300); } @@ -158,12 +168,14 @@ void r300_flush_cb(void *data) } #define R300_INIT_ATOM(atomname, atomsize) \ + do { \ r300->atomname.name = #atomname; \ r300->atomname.state = NULL; \ r300->atomname.size = atomsize; \ r300->atomname.emit = r300_emit_##atomname; \ r300->atomname.dirty = FALSE; \ - insert_at_tail(&r300->atom_list, &r300->atomname); + insert_at_tail(&r300->atom_list, &r300->atomname); \ + } while (0) static void r300_setup_atoms(struct r300_context* r300) { @@ -404,19 +416,21 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, r300->context.destroy = r300_destroy_context; - r300->cs = rws->cs_create(rws); + make_empty_list(&r300->query_list); util_mempool_create(&r300->pool_transfers, sizeof(struct pipe_transfer), 64, UTIL_MEMPOOL_SINGLETHREADED); + r300->cs = rws->cs_create(rws); + if (r300->cs == NULL) + goto fail; + if (!r300screen->caps.has_tcl) { /* Create a Draw. This is used for SW TCL. */ r300->draw = draw_create(&r300->context); /* Enable our renderer. */ draw_set_rasterize_stage(r300->draw, r300_draw_stage(r300)); - /* Enable Draw's clipping. */ - draw_set_driver_clipping(r300->draw, FALSE); /* Disable converting points/lines to triangles. */ draw_wide_line_threshold(r300->draw, 10000000.f); draw_wide_point_threshold(r300->draw, 10000000.f); @@ -424,8 +438,6 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, r300_setup_atoms(r300); - make_empty_list(&r300->query_list); - r300_init_blit_functions(r300); r300_init_flush_functions(r300); r300_init_query_functions(r300); @@ -433,6 +445,8 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, r300_init_resource_functions(r300); r300->blitter = util_blitter_create(&r300->context); + if (r300->blitter == NULL) + goto fail; /* Render functions must be initialized after blitter. */ r300_init_render_functions(r300); @@ -441,22 +455,25 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, /* setup hyper-z mm */ if (r300->rws->get_value(r300->rws, R300_CAN_HYPERZ)) - r300_hyperz_init_mm(r300); + if (!r300_hyperz_init_mm(r300)) + goto fail; r300->upload_ib = u_upload_create(&r300->context, 32 * 1024, 16, PIPE_BIND_INDEX_BUFFER); if (r300->upload_ib == NULL) - goto no_upload_ib; + goto fail; r300->upload_vb = u_upload_create(&r300->context, 128 * 1024, 16, PIPE_BIND_VERTEX_BUFFER); if (r300->upload_vb == NULL) - goto no_upload_vb; + goto fail; r300->tran.translate_cache = translate_cache_create(); + if (r300->tran.translate_cache == NULL) + goto fail; r300_init_states(&r300->context); @@ -486,10 +503,8 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, return &r300->context; - no_upload_ib: - u_upload_destroy(r300->upload_ib); - no_upload_vb: - FREE(r300); + fail: + r300_destroy_context(&r300->context); return NULL; } diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h index 6fa7f470f9..8f0e86fd37 100644 --- a/src/gallium/drivers/r300/r300_context.h +++ b/src/gallium/drivers/r300/r300_context.h @@ -254,8 +254,8 @@ struct r300_ztop_state { struct r300_constant_buffer { /* Buffer of constants */ uint32_t *ptr; - /* Total number of vec4s */ - unsigned count; + /* Remapping table. */ + unsigned *remap_table; }; /* Query object. @@ -449,6 +449,7 @@ struct r300_context { struct r300_screen *screen; /* Draw module. Used mostly for SW TCL. */ struct draw_context* draw; + size_t draw_vbo_size; /* Accelerated blit support. */ struct blitter_context* blitter; /* Stencil two-sided reference value fallback. */ @@ -649,6 +650,11 @@ void r300_translate_index_buffer(struct r300_context *r300, /* r300_render_stencilref.c */ void r300_plug_in_stencil_ref_fallback(struct r300_context *r300); +/* r300_render.c */ +void r300_draw_flush_vbuf(struct r300_context *r300); +boolean r500_index_bias_supported(struct r300_context *r300); +void r500_emit_index_bias(struct r300_context *r300, int index_bias); + /* r300_state.c */ enum r300_fb_state_change { R300_CHANGED_FB_STATE = 0, diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c index d0fd45349e..232259e21d 100644 --- a/src/gallium/drivers/r300/r300_emit.c +++ b/src/gallium/drivers/r300/r300_emit.c @@ -180,9 +180,18 @@ void r300_emit_fs_constants(struct r300_context* r300, unsigned size, void *stat BEGIN_CS(size); OUT_CS_REG_SEQ(R300_PFS_PARAM_0_X, count * 4); - for (i = 0; i < count; i++) - for (j = 0; j < 4; j++) - OUT_CS(pack_float24(*(float*)&buf->ptr[i*4+j])); + if (buf->remap_table){ + for (i = 0; i < count; i++) { + float *data = (float*)&buf->ptr[buf->remap_table[i]*4]; + for (j = 0; j < 4; j++) + OUT_CS(pack_float24(data[j])); + } + } else { + for (i = 0; i < count; i++) + for (j = 0; j < 4; j++) + OUT_CS(pack_float24(*(float*)&buf->ptr[i*4+j])); + } + END_CS; } @@ -226,7 +235,7 @@ void r500_emit_fs_constants(struct r300_context* r300, unsigned size, void *stat { struct r300_fragment_shader *fs = r300_fs(r300); struct r300_constant_buffer *buf = (struct r300_constant_buffer*)state; - unsigned count = fs->shader->externals_count * 4; + unsigned count = fs->shader->externals_count; CS_LOCALS(r300); if (count == 0) @@ -234,8 +243,15 @@ void r500_emit_fs_constants(struct r300_context* r300, unsigned size, void *stat BEGIN_CS(size); OUT_CS_REG(R500_GA_US_VECTOR_INDEX, R500_GA_US_VECTOR_INDEX_TYPE_CONST); - OUT_CS_ONE_REG(R500_GA_US_VECTOR_DATA, count); - OUT_CS_TABLE(buf->ptr, count); + OUT_CS_ONE_REG(R500_GA_US_VECTOR_DATA, count * 4); + if (buf->remap_table){ + for (unsigned i = 0; i < count; i++) { + uint32_t *data = &buf->ptr[buf->remap_table[i]*4]; + OUT_CS_TABLE(data, 4); + } + } else { + OUT_CS_TABLE(buf->ptr, count * 4); + } END_CS; } @@ -893,7 +909,7 @@ void r300_emit_vs_state(struct r300_context* r300, unsigned size, void* state) unsigned pvs_num_slots = MIN3(vtx_mem_size / input_count, vtx_mem_size / output_count, 10); - unsigned pvs_num_controllers = MIN2(vtx_mem_size / temp_count, 6); + unsigned pvs_num_controllers = MIN2(vtx_mem_size / temp_count, 5); unsigned imm_first = vs->externals_count; unsigned imm_end = vs->code.constants.Count; @@ -961,6 +977,7 @@ void r300_emit_vs_constants(struct r300_context* r300, unsigned count = ((struct r300_vertex_shader*)r300->vs_state.state)->externals_count; struct r300_constant_buffer *buf = (struct r300_constant_buffer*)state; + unsigned i; CS_LOCALS(r300); if (!count) @@ -971,7 +988,14 @@ void r300_emit_vs_constants(struct r300_context* r300, (r300->screen->caps.is_r500 ? R500_PVS_CONST_START : R300_PVS_CONST_START)); OUT_CS_ONE_REG(R300_VAP_PVS_UPLOAD_DATA, count * 4); - OUT_CS_TABLE(buf->ptr, count * 4); + if (buf->remap_table){ + for (i = 0; i < count; i++) { + uint32_t *data = &buf->ptr[buf->remap_table[i]*4]; + OUT_CS_TABLE(data, 4); + } + } else { + OUT_CS_TABLE(buf->ptr, count * 4); + } END_CS; } @@ -1219,6 +1243,8 @@ unsigned r300_get_num_cs_end_dwords(struct r300_context *r300) /* Emitted in flush. */ dwords += 26; /* emit_query_end */ dwords += r300->hyperz_state.size + 2; /* emit_hyperz_end + zcache flush */ + if (r500_index_bias_supported(r300)) + dwords += 2; return dwords; } diff --git a/src/gallium/drivers/r300/r300_flush.c b/src/gallium/drivers/r300/r300_flush.c index fe182b6615..2b5d2e42ba 100644 --- a/src/gallium/drivers/r300/r300_flush.c +++ b/src/gallium/drivers/r300/r300_flush.c @@ -43,9 +43,14 @@ static void r300_flush(struct pipe_context* pipe, u_upload_flush(r300->upload_vb); u_upload_flush(r300->upload_ib); + if (r300->draw) + r300_draw_flush_vbuf(r300); + if (r300->dirty_hw) { r300_emit_hyperz_end(r300); r300_emit_query_end(r300); + if (r500_index_bias_supported(r300)) + r500_emit_index_bias(r300, 0); r300->flush_counter++; r300->rws->cs_flush(r300->cs); diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c index 2a0c30620a..9845e54610 100644 --- a/src/gallium/drivers/r300/r300_fs.c +++ b/src/gallium/drivers/r300/r300_fs.c @@ -257,17 +257,17 @@ static void r300_emit_fs_code_to_buffer( shader->cb_code_size = 19 + ((code->inst_end + 1) * 6) + imm_count * 7 + - code->int_constant_count * 2; + code->int_constant_count * 2; NEW_CB(shader->cb_code, shader->cb_code_size); OUT_CB_REG(R500_US_CONFIG, R500_ZERO_TIMES_ANYTHING_EQUALS_ZERO); OUT_CB_REG(R500_US_PIXSIZE, code->max_temp_idx); OUT_CB_REG(R500_US_FC_CTRL, code->us_fc_ctrl); for(i = 0; i < code->int_constant_count; i++){ - OUT_CB_REG(R500_US_FC_INT_CONST_0 + (i * 4), - code->int_constants[i]); - } - OUT_CB_REG(R500_US_CODE_RANGE, + OUT_CB_REG(R500_US_FC_INT_CONST_0 + (i * 4), + code->int_constants[i]); + } + OUT_CB_REG(R500_US_CODE_RANGE, R500_US_CODE_RANGE_ADDR(0) | R500_US_CODE_RANGE_SIZE(code->inst_end)); OUT_CB_REG(R500_US_CODE_OFFSET, 0); OUT_CB_REG(R500_US_CODE_ADDR, @@ -386,6 +386,7 @@ static void r300_translate_fragment_shader( compiler.state = shader->compare_state; compiler.Base.is_r500 = r300->screen->caps.is_r500; compiler.Base.max_temp_regs = compiler.Base.is_r500 ? 128 : 32; + compiler.Base.remove_unused_constants = TRUE; compiler.AllocateHwInputs = &allocate_hardware_inputs; compiler.UserData = &shader->inputs; @@ -431,9 +432,8 @@ static void r300_translate_fragment_shader( } if (compiler.Base.Error) { - DBG(r300, DBG_FP, "r300 FP: Compiler Error:\n%sUsing a dummy shader" - " instead.\nIf there's an 'unknown opcode' message, please" - " file a bug report and attach this log.\n", compiler.Base.ErrorMsg); + fprintf(stderr, "r300 FP: Compiler Error:\n%sUsing a dummy shader" + " instead.\n", compiler.Base.ErrorMsg); if (shader->dummy) { fprintf(stderr, "r300 FP: Cannot compile the dummy shader! " @@ -447,7 +447,12 @@ static void r300_translate_fragment_shader( } /* Initialize numbers of constants for each type. */ - shader->externals_count = ttr.immediate_offset; + shader->externals_count = 0; + for (i = 0; + i < shader->code.constants.Count && + shader->code.constants.Constants[i].Type == RC_CONSTANT_EXTERNAL; i++) { + shader->externals_count = i+1; + } shader->immediates_count = 0; shader->rc_state_count = 0; diff --git a/src/gallium/drivers/r300/r300_hyperz.c b/src/gallium/drivers/r300/r300_hyperz.c index 811b5646e1..eb5b0c36f8 100644 --- a/src/gallium/drivers/r300/r300_hyperz.c +++ b/src/gallium/drivers/r300/r300_hyperz.c @@ -354,7 +354,12 @@ void r300_zmask_alloc_block(struct r300_context *r300, struct r300_surface *surf /* We currently don't handle decompression for 3D textures and cubemaps * correctly. */ if (tex->desc.b.b.target != PIPE_TEXTURE_1D && - tex->desc.b.b.target != PIPE_TEXTURE_2D) + tex->desc.b.b.target != PIPE_TEXTURE_2D && + tex->desc.b.b.target != PIPE_TEXTURE_RECT) + return; + + /* Cannot flush zmask of 16-bit zbuffers. */ + if (util_format_get_blocksizebits(tex->desc.b.b.format) == 16) return; if (tex->zmask_mem[level]) @@ -373,23 +378,36 @@ void r300_zmask_alloc_block(struct r300_context *r300, struct r300_surface *surf return; } -void r300_hyperz_init_mm(struct r300_context *r300) +boolean r300_hyperz_init_mm(struct r300_context *r300) { struct r300_screen* r300screen = r300->screen; int frag_pipes = r300screen->caps.num_frag_pipes; - if (r300screen->caps.hiz_ram) + r300->zmask_mm = u_mmInit(0, r300screen->caps.zmask_ram * frag_pipes); + if (!r300->zmask_mm) + return FALSE; + + if (r300screen->caps.hiz_ram) { r300->hiz_mm = u_mmInit(0, r300screen->caps.hiz_ram * frag_pipes); + if (!r300->hiz_mm) { + u_mmDestroy(r300->zmask_mm); + r300->zmask_mm = NULL; + return FALSE; + } + } - r300->zmask_mm = u_mmInit(0, r300screen->caps.zmask_ram * frag_pipes); + return TRUE; } void r300_hyperz_destroy_mm(struct r300_context *r300) { struct r300_screen* r300screen = r300->screen; - if (r300screen->caps.hiz_ram) + if (r300screen->caps.hiz_ram) { u_mmDestroy(r300->hiz_mm); + r300->hiz_mm = NULL; + } u_mmDestroy(r300->zmask_mm); + r300->zmask_mm = NULL; } diff --git a/src/gallium/drivers/r300/r300_hyperz.h b/src/gallium/drivers/r300/r300_hyperz.h index 09e1ff6625..30a23ec649 100644 --- a/src/gallium/drivers/r300/r300_hyperz.h +++ b/src/gallium/drivers/r300/r300_hyperz.h @@ -30,6 +30,6 @@ void r300_update_hyperz_state(struct r300_context* r300); void r300_hiz_alloc_block(struct r300_context *r300, struct r300_surface *surf); void r300_zmask_alloc_block(struct r300_context *r300, struct r300_surface *surf, int compress); -void r300_hyperz_init_mm(struct r300_context *r300); +boolean r300_hyperz_init_mm(struct r300_context *r300); void r300_hyperz_destroy_mm(struct r300_context *r300); #endif diff --git a/src/gallium/drivers/r300/r300_reg.h b/src/gallium/drivers/r300/r300_reg.h index 60d3b600cb..6bea783f69 100644 --- a/src/gallium/drivers/r300/r300_reg.h +++ b/src/gallium/drivers/r300/r300_reg.h @@ -1607,6 +1607,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. # define R300_TX_FORMAT_3D (1 << 25) # define R300_TX_FORMAT_CUBIC_MAP (2 << 25) +# define R300_TX_FORMAT_TEX_COORD_TYPE_MASK (0x3 << 25) /* alpha modes, convenience mostly */ /* if you have alpha, pick constant appropriate to the diff --git a/src/gallium/drivers/r300/r300_render.c b/src/gallium/drivers/r300/r300_render.c index 86b11ca045..20bad2c56f 100644 --- a/src/gallium/drivers/r300/r300_render.c +++ b/src/gallium/drivers/r300/r300_render.c @@ -118,13 +118,13 @@ static uint32_t r300_provoking_vertex_fixes(struct r300_context *r300, return color_control; } -static boolean index_bias_supported(struct r300_context *r300) +boolean r500_index_bias_supported(struct r300_context *r300) { return r300->screen->caps.is_r500 && r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0); } -static void r500_emit_index_bias(struct r300_context *r300, int index_bias) +void r500_emit_index_bias(struct r300_context *r300, int index_bias) { CS_LOCALS(r300); @@ -199,7 +199,7 @@ static void r300_prepare_for_rendering(struct r300_context *r300, boolean emit_aos = flags & PREP_EMIT_AOS; boolean emit_aos_swtcl = flags & PREP_EMIT_AOS_SWTCL; boolean indexed = flags & PREP_INDEXED; - boolean hw_index_bias = index_bias_supported(r300); + boolean hw_index_bias = r500_index_bias_supported(r300); /* Add dirty state, index offset, and AOS. */ if (first_draw) { @@ -506,7 +506,7 @@ static void r300_draw_range_elements(struct pipe_context* pipe, translate = TRUE; } - if (indexBias && !index_bias_supported(r300)) { + if (indexBias && !r500_index_bias_supported(r300)) { r300_split_index_bias(r300, indexBias, &buffer_offset, &index_offset); } @@ -680,18 +680,11 @@ static void r300_swtcl_draw_vbo(struct pipe_context* pipe, if (info->indexed && r300->index_buffer.buffer) { indices = pipe_buffer_map(pipe, r300->index_buffer.buffer, PIPE_TRANSFER_READ, &ib_transfer); - if (indices) - indices = (void *) ((char *) indices + r300->index_buffer.offset); } - draw_set_mapped_element_buffer_range(r300->draw, (indices) ? - r300->index_buffer.index_size : 0, - info->index_bias, - info->min_index, - info->max_index, - indices); + draw_set_mapped_index_buffer(r300->draw, indices); - draw_arrays(r300->draw, info->mode, info->start, count); + draw_vbo(r300->draw, info); /* XXX Not sure whether this is the best fix. * It prevents CS from being rejected and weird assertion failures. */ @@ -707,8 +700,7 @@ static void r300_swtcl_draw_vbo(struct pipe_context* pipe, if (ib_transfer) { pipe_buffer_unmap(pipe, r300->index_buffer.buffer, ib_transfer); - draw_set_mapped_element_buffer_range(r300->draw, 0, 0, info->start, - info->start + count - 1, NULL); + draw_set_mapped_index_buffer(r300->draw, NULL); } } @@ -726,8 +718,6 @@ struct r300_render { unsigned hwprim; /* VBO */ - struct pipe_resource* vbo; - size_t vbo_size; size_t vbo_offset; size_t vbo_max_used; void * vbo_ptr; @@ -759,31 +749,31 @@ static boolean r300_render_allocate_vertices(struct vbuf_render* render, struct pipe_screen* screen = r300->context.screen; size_t size = (size_t)vertex_size * (size_t)count; - if (size + r300render->vbo_offset > r300render->vbo_size) + if (size + r300render->vbo_offset > r300->draw_vbo_size) { - pipe_resource_reference(&r300->vbo, NULL); - r300render->vbo = pipe_buffer_create(screen, - PIPE_BIND_VERTEX_BUFFER, - R300_MAX_DRAW_VBO_SIZE); + pipe_resource_reference(&r300->vbo, NULL); + r300->vbo = pipe_buffer_create(screen, + PIPE_BIND_VERTEX_BUFFER, + R300_MAX_DRAW_VBO_SIZE); r300render->vbo_offset = 0; - r300render->vbo_size = R300_MAX_DRAW_VBO_SIZE; + r300->draw_vbo_size = R300_MAX_DRAW_VBO_SIZE; } r300render->vertex_size = vertex_size; - r300->vbo = r300render->vbo; r300->vbo_offset = r300render->vbo_offset; - return (r300render->vbo) ? TRUE : FALSE; + return (r300->vbo) ? TRUE : FALSE; } static void* r300_render_map_vertices(struct vbuf_render* render) { struct r300_render* r300render = r300_render(render); + struct r300_context* r300 = r300render->r300; assert(!r300render->vbo_transfer); r300render->vbo_ptr = pipe_buffer_map(&r300render->r300->context, - r300render->vbo, + r300->vbo, PIPE_TRANSFER_WRITE, &r300render->vbo_transfer); @@ -798,12 +788,13 @@ static void r300_render_unmap_vertices(struct vbuf_render* render, { struct r300_render* r300render = r300_render(render); struct pipe_context* context = &r300render->r300->context; + struct r300_context* r300 = r300render->r300; assert(r300render->vbo_transfer); r300render->vbo_max_used = MAX2(r300render->vbo_max_used, r300render->vertex_size * (max + 1)); - pipe_buffer_unmap(context, r300render->vbo, r300render->vbo_transfer); + pipe_buffer_unmap(context, r300->vbo, r300render->vbo_transfer); r300render->vbo_transfer = NULL; } @@ -880,7 +871,7 @@ static void r300_render_draw_elements(struct vbuf_render* render, struct r300_context* r300 = r300render->r300; int i; unsigned end_cs_dwords; - unsigned max_index = (r300render->vbo_size - r300render->vbo_offset) / + unsigned max_index = (r300->draw_vbo_size - r300render->vbo_offset) / (r300render->r300->vertex_info.size * 4) - 1; unsigned short_count; unsigned free_dwords; @@ -956,8 +947,6 @@ static struct vbuf_render* r300_render_create(struct r300_context* r300) r300render->base.release_vertices = r300_render_release_vertices; r300render->base.destroy = r300_render_destroy; - r300render->vbo = NULL; - r300render->vbo_size = 0; r300render->vbo_offset = 0; return &r300render->base; @@ -986,6 +975,12 @@ struct draw_stage* r300_draw_stage(struct r300_context* r300) return stage; } +void r300_draw_flush_vbuf(struct r300_context *r300) +{ + pipe_resource_reference(&r300->vbo, NULL); + r300->draw_vbo_size = 0; +} + /**************************************************************************** * End of SW TCL functions * ***************************************************************************/ diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c index 239edd98e3..8ccb63964e 100644 --- a/src/gallium/drivers/r300/r300_state.c +++ b/src/gallium/drivers/r300/r300_state.c @@ -23,7 +23,7 @@ #include "draw/draw_context.h" -#include "util/u_blitter.h" +#include "util/u_framebuffer.h" #include "util/u_math.h" #include "util/u_mm.h" #include "util/u_memory.h" @@ -748,7 +748,7 @@ static void /* The tiling flags are dependent on the surface miplevel, unfortunately. */ r300_fb_set_tiling_flags(r300, state); - util_assign_framebuffer_state(r300->fb_state.state, state); + util_copy_framebuffer_state(r300->fb_state.state, state); r300_mark_fb_state_dirty(r300, R300_CHANGED_FB_STATE); @@ -865,6 +865,9 @@ void r300_mark_fs_code_dirty(struct r300_context *r300) r300->fs_rc_constant_state.size = fs->shader->rc_state_count * 5; r300->fs_constants.size = fs->shader->externals_count * 4 + 1; } + + ((struct r300_constant_buffer*)r300->fs_constants.state)->remap_table = + fs->shader->code.constants_remap_table; } /* Bind fragment shader state. */ @@ -937,9 +940,9 @@ static void* r300_create_rs_state(struct pipe_context* pipe, uint32_t stuffing_enable; /* R300_GB_ENABLE: 0x4008 */ /* Point sprites texture coordinates, 0: lower left, 1: upper right */ - float point_texcoord_left; /* R300_GA_POINT_S0: 0x4200 */ + float point_texcoord_left = 0; /* R300_GA_POINT_S0: 0x4200 */ float point_texcoord_bottom = 0;/* R300_GA_POINT_T0: 0x4204 */ - float point_texcoord_right; /* R300_GA_POINT_S1: 0x4208 */ + float point_texcoord_right = 1; /* R300_GA_POINT_S1: 0x4208 */ float point_texcoord_top = 0; /* R300_GA_POINT_T1: 0x420c */ CB_LOCALS; @@ -947,6 +950,11 @@ static void* r300_create_rs_state(struct pipe_context* pipe, rs->rs = *state; rs->rs_draw = *state; + /* Generate point sprite texture coordinates in GENERIC0 + * if point_quad_rasterization is TRUE. */ + rs->rs.sprite_coord_enable = state->point_quad_rasterization * + (state->sprite_coord_enable | 1); + /* Override some states for Draw. */ rs->rs_draw.sprite_coord_enable = 0; /* We can do this in HW. */ @@ -1048,16 +1056,13 @@ static void* r300_create_rs_state(struct pipe_context* pipe, /* Point sprites */ stuffing_enable = 0; - if (state->sprite_coord_enable) { + if (rs->rs.sprite_coord_enable) { stuffing_enable = R300_GB_POINT_STUFF_ENABLE; - for (i = 0; i < 8; i++) { - if (state->sprite_coord_enable & (1 << i)) + for (i = 0; i < 8; i++) { + if (rs->rs.sprite_coord_enable & (1 << i)) stuffing_enable |= R300_GB_TEX_ST << (R300_GB_TEX0_SOURCE_SHIFT + (i*2)); - } - - point_texcoord_left = 0.0f; - point_texcoord_right = 1.0f; + } switch (state->sprite_coord_mode) { case PIPE_SPRITE_COORD_UPPER_LEFT: @@ -1208,8 +1213,8 @@ static void* /* Unfortunately, r300-r500 don't support floating-point mipmap lods. */ /* We must pass these to the merge function to clamp them properly. */ - sampler->min_lod = MAX2((unsigned)state->min_lod, 0); - sampler->max_lod = MAX2((unsigned)ceilf(state->max_lod), 0); + sampler->min_lod = (unsigned)MAX2(state->min_lod, 0); + sampler->max_lod = (unsigned)MAX2(ceilf(state->max_lod), 0); lod_bias = CLAMP((int)(state->lod_bias * 32 + 1), -(1 << 9), (1 << 9) - 1); @@ -1548,7 +1553,12 @@ static void r300_set_index_buffer(struct pipe_context* pipe, memset(&r300->index_buffer, 0, sizeof(r300->index_buffer)); } - /* TODO make this more like a state */ + if (r300->screen->caps.has_tcl) { + /* TODO make this more like a state */ + } + else { + draw_set_index_buffer(r300->draw, ib); + } } /* Initialize the PSC tables. */ @@ -1765,6 +1775,9 @@ static void r300_bind_vs_state(struct pipe_context* pipe, void* shader) r300->vs_constants.size = 0; } + ((struct r300_constant_buffer*)r300->vs_constants.state)->remap_table = + vs->code.constants_remap_table; + r300->pvs_flush.dirty = TRUE; } else { draw_bind_vertex_shader(r300->draw, @@ -1779,6 +1792,8 @@ static void r300_delete_vs_state(struct pipe_context* pipe, void* shader) if (r300->screen->caps.has_tcl) { rc_constants_destroy(&vs->code.constants); + if (vs->code.constants_remap_table) + FREE(vs->code.constants_remap_table); } else { draw_delete_vertex_shader(r300->draw, (struct draw_vertex_shader*)vs->draw_vs); @@ -1795,47 +1810,28 @@ static void r300_set_constant_buffer(struct pipe_context *pipe, struct r300_context* r300 = r300_context(pipe); struct r300_constant_buffer *cbuf; uint32_t *mapped = r300_buffer(buf)->user_buffer; - int max_size = 0, max_size_bytes = 0, clamped_size = 0; switch (shader) { case PIPE_SHADER_VERTEX: cbuf = (struct r300_constant_buffer*)r300->vs_constants.state; - max_size = 256; break; case PIPE_SHADER_FRAGMENT: cbuf = (struct r300_constant_buffer*)r300->fs_constants.state; - if (r300->screen->caps.is_r500) { - max_size = 256; - } else { - max_size = 32; - } break; default: assert(0); return; } - max_size_bytes = max_size * 4 * sizeof(float); if (buf == NULL || buf->width0 == 0 || (mapped = r300_buffer(buf)->constant_buffer) == NULL) { - cbuf->count = 0; return; } if (shader == PIPE_SHADER_FRAGMENT || (shader == PIPE_SHADER_VERTEX && r300->screen->caps.has_tcl)) { assert((buf->width0 % (4 * sizeof(float))) == 0); - - /* Check the size of the constant buffer. */ - /* XXX Subtract immediates and RC_STATE_* variables. */ - if (buf->width0 > max_size_bytes) { - fprintf(stderr, "r300: Max size of the constant buffer is " - "%i*4 floats.\n", max_size); - } - - clamped_size = MIN2(buf->width0, max_size_bytes); - cbuf->count = clamped_size / (4 * sizeof(float)); - cbuf->ptr = mapped; + cbuf->ptr = mapped + index*4; } if (shader == PIPE_SHADER_VERTEX) { diff --git a/src/gallium/drivers/r300/r300_state_derived.c b/src/gallium/drivers/r300/r300_state_derived.c index 4a63ed7fc1..960dfdbaf0 100644 --- a/src/gallium/drivers/r300/r300_state_derived.c +++ b/src/gallium/drivers/r300/r300_state_derived.c @@ -211,7 +211,7 @@ static void r300_rs_col(struct r300_rs_block* rs, int id, int ptr, static void r300_rs_col_write(struct r300_rs_block* rs, int id, int fp_offset, enum r300_rs_col_write_type type) { - assert(type != WRITE_COLOR); + assert(type == WRITE_COLOR); rs->inst[id] |= R300_RS_INST_COL_CN_WRITE | R300_RS_INST_COL_ADDR(fp_offset); } @@ -592,6 +592,25 @@ static void r300_merge_textures_and_samplers(struct r300_context* r300) texstate->filter1 = sampler->filter1; texstate->border_color = sampler->border_color; + /* determine min/max levels */ + max_level = MIN3(sampler->max_lod + view->base.first_level, + tex->desc.b.b.last_level, view->base.last_level); + min_level = MIN2(sampler->min_lod + view->base.first_level, + max_level); + + if (tex->desc.is_npot && min_level > 0) { + /* Even though we do not implement mipmapping for NPOT + * textures, we should at least honor the minimum level + * which is allowed to be displayed. We do this by setting up + * an i-th mipmap level as the zero level. */ + r300_texture_setup_format_state(r300->screen, &tex->desc, + min_level, + &texstate->format); + texstate->format.tile_config |= + tex->desc.offset_in_bytes[min_level] & 0xffffffe0; + assert((tex->desc.offset_in_bytes[min_level] & 0x1f) == 0); + } + /* Assign a texture cache region. */ texstate->format.format1 |= view->texcache_region; @@ -654,12 +673,7 @@ static void r300_merge_textures_and_samplers(struct r300_context* r300) texstate->filter0 |= R300_TX_WRAP_T(R300_TX_CLAMP_TO_EDGE); } } else { - /* determine min/max levels */ /* the MAX_MIP level is the largest (finest) one */ - max_level = MIN3(sampler->max_lod + view->base.first_level, - tex->desc.b.b.last_level, view->base.last_level); - min_level = MIN2(sampler->min_lod + view->base.first_level, - max_level); texstate->format.format0 |= R300_TX_NUM_LEVELS(max_level); texstate->filter0 |= R300_TX_MAX_MIP_LEVEL(min_level); } diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c index da8eadd3b5..66f6d80bd0 100644 --- a/src/gallium/drivers/r300/r300_texture.c +++ b/src/gallium/drivers/r300/r300_texture.c @@ -541,48 +541,55 @@ boolean r300_is_sampler_format_supported(enum pipe_format format) return r300_translate_texformat(format, 0, TRUE) != ~0; } -static void r300_texture_setup_immutable_state(struct r300_screen* screen, - struct r300_texture* tex) +void r300_texture_setup_format_state(struct r300_screen *screen, + struct r300_texture_desc *desc, + unsigned level, + struct r300_texture_format_state *out) { - struct r300_texture_format_state* f = &tex->tx_format; - struct pipe_resource *pt = &tex->desc.b.b; + struct pipe_resource *pt = &desc->b.b; boolean is_r500 = screen->caps.is_r500; + /* Mask out all the fields we change. */ + out->format0 = 0; + out->format1 &= ~R300_TX_FORMAT_TEX_COORD_TYPE_MASK; + out->format2 &= R500_TXFORMAT_MSB; + out->tile_config = 0; + /* Set sampler state. */ - f->format0 = R300_TX_WIDTH((pt->width0 - 1) & 0x7ff) | - R300_TX_HEIGHT((pt->height0 - 1) & 0x7ff); + out->format0 = R300_TX_WIDTH((u_minify(pt->width0, level) - 1) & 0x7ff) | + R300_TX_HEIGHT((u_minify(pt->height0, level) - 1) & 0x7ff); - if (tex->desc.uses_stride_addressing) { + if (desc->uses_stride_addressing) { /* rectangles love this */ - f->format0 |= R300_TX_PITCH_EN; - f->format2 = (tex->desc.stride_in_pixels[0] - 1) & 0x1fff; + out->format0 |= R300_TX_PITCH_EN; + out->format2 = (desc->stride_in_pixels[level] - 1) & 0x1fff; } else { /* Power of two textures (3D, mipmaps, and no pitch), * also NPOT textures with a width being POT. */ - f->format0 |= R300_TX_DEPTH(util_logbase2(pt->depth0) & 0xf); + out->format0 |= + R300_TX_DEPTH(util_logbase2(u_minify(pt->depth0, level)) & 0xf); } - f->format1 = 0; if (pt->target == PIPE_TEXTURE_CUBE) { - f->format1 |= R300_TX_FORMAT_CUBIC_MAP; + out->format1 |= R300_TX_FORMAT_CUBIC_MAP; } if (pt->target == PIPE_TEXTURE_3D) { - f->format1 |= R300_TX_FORMAT_3D; + out->format1 |= R300_TX_FORMAT_3D; } /* large textures on r500 */ if (is_r500) { if (pt->width0 > 2048) { - f->format2 |= R500_TXWIDTH_BIT11; + out->format2 |= R500_TXWIDTH_BIT11; } if (pt->height0 > 2048) { - f->format2 |= R500_TXHEIGHT_BIT11; + out->format2 |= R500_TXHEIGHT_BIT11; } } - f->tile_config = R300_TXO_MACRO_TILE(tex->desc.macrotile[0]) | - R300_TXO_MICRO_TILE(tex->desc.microtile); + out->tile_config = R300_TXO_MACRO_TILE(desc->macrotile[level]) | + R300_TXO_MICRO_TILE(desc->microtile); } static void r300_texture_setup_fb_state(struct r300_screen* screen, @@ -716,7 +723,7 @@ r300_texture_create_object(struct r300_screen *rscreen, return NULL; } /* Initialize the hardware state. */ - r300_texture_setup_immutable_state(rscreen, tex); + r300_texture_setup_format_state(rscreen, &tex->desc, 0, &tex->tx_format); r300_texture_setup_fb_state(rscreen, tex); tex->desc.b.vtbl = &r300_texture_vtbl; @@ -754,7 +761,8 @@ struct pipe_resource *r300_texture_create(struct pipe_screen *screen, /* Refuse to create a texture with size 0. */ if (!base->width0 || (!base->height0 && (base->target == PIPE_TEXTURE_2D || - base->target == PIPE_TEXTURE_CUBE)) || + base->target == PIPE_TEXTURE_CUBE || + base->target == PIPE_TEXTURE_RECT)) || (!base->depth0 && base->target == PIPE_TEXTURE_3D)) { fprintf(stderr, "r300: texture_create: " "Got invalid texture dimensions: %ix%ix%i\n", @@ -787,7 +795,8 @@ struct pipe_resource *r300_texture_from_handle(struct pipe_screen *screen, unsigned stride, size; /* Support only 2D textures without mipmaps */ - if (base->target != PIPE_TEXTURE_2D || + if ((base->target != PIPE_TEXTURE_2D && + base->target != PIPE_TEXTURE_RECT) || base->depth0 != 1 || base->last_level != 0) { return NULL; diff --git a/src/gallium/drivers/r300/r300_texture.h b/src/gallium/drivers/r300/r300_texture.h index a4524320fd..c4588a0c90 100644 --- a/src/gallium/drivers/r300/r300_texture.h +++ b/src/gallium/drivers/r300/r300_texture.h @@ -23,11 +23,14 @@ #ifndef R300_TEXTURE_H #define R300_TEXTURE_H +#include "pipe/p_compiler.h" #include "pipe/p_format.h" struct pipe_screen; struct pipe_resource; struct winsys_handle; +struct r300_texture_format_state; +struct r300_texture_desc; struct r300_texture; struct r300_screen; @@ -50,6 +53,10 @@ boolean r300_is_zs_format_supported(enum pipe_format format); boolean r300_is_sampler_format_supported(enum pipe_format format); +void r300_texture_setup_format_state(struct r300_screen *screen, + struct r300_texture_desc *desc, + unsigned level, + struct r300_texture_format_state *out); struct pipe_resource* r300_texture_from_handle(struct pipe_screen* screen, diff --git a/src/gallium/drivers/r300/r300_texture_desc.c b/src/gallium/drivers/r300/r300_texture_desc.c index 5d690e8c33..2fe5d72188 100644 --- a/src/gallium/drivers/r300/r300_texture_desc.c +++ b/src/gallium/drivers/r300/r300_texture_desc.c @@ -184,7 +184,8 @@ static unsigned r300_texture_get_nblocksy(struct r300_texture_desc *desc, /* This is needed for the kernel checker, unfortunately. */ if ((desc->b.b.target != PIPE_TEXTURE_1D && - desc->b.b.target != PIPE_TEXTURE_2D) || + desc->b.b.target != PIPE_TEXTURE_2D && + desc->b.b.target != PIPE_TEXTURE_RECT) || desc->b.b.last_level != 0) { height = util_next_power_of_two(height); } @@ -202,7 +203,8 @@ static unsigned r300_texture_get_nblocksy(struct r300_texture_desc *desc, * Do so for 3 or more macrotiles in the Y direction. */ if (level == 0 && desc->b.b.last_level == 0 && (desc->b.b.target == PIPE_TEXTURE_1D || - desc->b.b.target == PIPE_TEXTURE_2D) && + desc->b.b.target == PIPE_TEXTURE_2D || + desc->b.b.target == PIPE_TEXTURE_RECT) && height >= tile_height * 3) { height = align(height, tile_height * 2); } diff --git a/src/gallium/drivers/r300/r300_texture_desc.h b/src/gallium/drivers/r300/r300_texture_desc.h index 95de66f654..3d7fe1fb47 100644 --- a/src/gallium/drivers/r300/r300_texture_desc.h +++ b/src/gallium/drivers/r300/r300_texture_desc.h @@ -24,6 +24,7 @@ #ifndef R300_TEXTURE_DESC_H #define R300_TEXTURE_DESC_H +#include "pipe/p_format.h" #include "r300_defines.h" struct pipe_resource; diff --git a/src/gallium/drivers/r300/r300_tgsi_to_rc.c b/src/gallium/drivers/r300/r300_tgsi_to_rc.c index dd697b9c37..a4911b9a2a 100644 --- a/src/gallium/drivers/r300/r300_tgsi_to_rc.c +++ b/src/gallium/drivers/r300/r300_tgsi_to_rc.c @@ -97,13 +97,13 @@ static unsigned translate_opcode(unsigned opcode) /* case TGSI_OPCODE_BRA: return RC_OPCODE_BRA; */ /* case TGSI_OPCODE_CAL: return RC_OPCODE_CAL; */ /* case TGSI_OPCODE_RET: return RC_OPCODE_RET; */ - /* case TGSI_OPCODE_SSG: return RC_OPCODE_SSG; */ + case TGSI_OPCODE_SSG: return RC_OPCODE_SSG; case TGSI_OPCODE_CMP: return RC_OPCODE_CMP; case TGSI_OPCODE_SCS: return RC_OPCODE_SCS; case TGSI_OPCODE_TXB: return RC_OPCODE_TXB; /* case TGSI_OPCODE_NRM: return RC_OPCODE_NRM; */ /* case TGSI_OPCODE_DIV: return RC_OPCODE_DIV; */ - /* case TGSI_OPCODE_DP2: return RC_OPCODE_DP2; */ + case TGSI_OPCODE_DP2: return RC_OPCODE_DP2; case TGSI_OPCODE_TXL: return RC_OPCODE_TXL; case TGSI_OPCODE_BRK: return RC_OPCODE_BRK; case TGSI_OPCODE_IF: return RC_OPCODE_IF; diff --git a/src/gallium/drivers/r300/r300_vs.c b/src/gallium/drivers/r300/r300_vs.c index 54c8de1241..5f8dbb28d0 100644 --- a/src/gallium/drivers/r300/r300_vs.c +++ b/src/gallium/drivers/r300/r300_vs.c @@ -196,6 +196,7 @@ void r300_translate_vertex_shader(struct r300_context *r300, { struct r300_vertex_program_compiler compiler; struct tgsi_to_rc ttr; + unsigned i; /* Setup the compiler */ rc_init(&compiler.Base); @@ -205,6 +206,7 @@ void r300_translate_vertex_shader(struct r300_context *r300, compiler.UserData = vs; compiler.Base.is_r500 = r300->screen->caps.is_r500; compiler.Base.max_temp_regs = 32; + compiler.Base.remove_unused_constants = TRUE; if (compiler.Base.Debug) { DBG(r300, DBG_VP, "r300: Initial vertex program\n"); @@ -227,9 +229,8 @@ void r300_translate_vertex_shader(struct r300_context *r300, /* Invoke the compiler */ r3xx_compile_vertex_program(&compiler); if (compiler.Base.Error) { - DBG(r300, DBG_VP, "r300 VP: Compiler error:\n%sUsing a dummy shader" - " instead.\nIf there's an 'unknown opcode' message, please" - " file a bug report and attach this log.\n", compiler.Base.ErrorMsg); + fprintf(stderr, "r300 VP: Compiler error:\n%sUsing a dummy shader" + " instead.\n", compiler.Base.ErrorMsg); if (vs->dummy) { fprintf(stderr, "r300 VP: Cannot compile the dummy shader! " @@ -243,7 +244,15 @@ void r300_translate_vertex_shader(struct r300_context *r300, } /* Initialize numbers of constants for each type. */ - vs->externals_count = ttr.immediate_offset; + vs->externals_count = 0; + for (i = 0; + i < vs->code.constants.Count && + vs->code.constants.Constants[i].Type == RC_CONSTANT_EXTERNAL; i++) { + vs->externals_count = i+1; + } + for (; i < vs->code.constants.Count; i++) { + assert(vs->code.constants.Constants[i].Type == RC_CONSTANT_IMMEDIATE); + } vs->immediates_count = vs->code.constants.Count - vs->externals_count; /* And, finally... */ diff --git a/src/gallium/drivers/r300/r300_winsys.h b/src/gallium/drivers/r300/r300_winsys.h index 187780750f..4597332399 100644 --- a/src/gallium/drivers/r300/r300_winsys.h +++ b/src/gallium/drivers/r300/r300_winsys.h @@ -33,6 +33,7 @@ #include "r300_defines.h" +struct winsys_handle; struct r300_winsys_screen; struct r300_winsys_buffer; diff --git a/src/gallium/drivers/r600/r600_asm.c b/src/gallium/drivers/r600/r600_asm.c index 9ea9d4354d..6483dac703 100644 --- a/src/gallium/drivers/r600/r600_asm.c +++ b/src/gallium/drivers/r600/r600_asm.c @@ -76,6 +76,27 @@ int r600_bc_init(struct r600_bc *bc, enum radeon_family family) { LIST_INITHEAD(&bc->cf); bc->family = family; + switch (bc->family) { + case CHIP_R600: + case CHIP_RV610: + case CHIP_RV630: + case CHIP_RV670: + case CHIP_RV620: + case CHIP_RV635: + case CHIP_RS780: + case CHIP_RS880: + bc->chiprev = 0; + break; + case CHIP_RV770: + case CHIP_RV730: + case CHIP_RV710: + case CHIP_RV740: + bc->chiprev = 1; + break; + default: + R600_ERR("unknown family %d\n", bc->family); + return -EINVAL; + } return 0; } @@ -107,7 +128,7 @@ int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output) return 0; } -int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu) +int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int type) { struct r600_bc_alu *nalu = r600_bc_alu(); struct r600_bc_alu *lalu; @@ -119,7 +140,7 @@ int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu) nalu->nliteral = 0; /* cf can contains only alu or only vtx or only tex */ - if (bc->cf_last == NULL || bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3) || + if (bc->cf_last == NULL || bc->cf_last->inst != (type << 3) || bc->force_add_cf) { /* at most 128 slots, one add alu can add 4 slots + 4 constant worst case */ r = r600_bc_add_cf(bc); @@ -127,7 +148,7 @@ int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu) free(nalu); return r; } - bc->cf_last->inst = V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3; + bc->cf_last->inst = (type << 3); } if (alu->last && (bc->cf_last->ndw >> 1) >= 124) { bc->force_add_cf = 1; @@ -162,6 +183,11 @@ int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu) return 0; } +int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu) +{ + return r600_bc_add_alu_type(bc, alu, V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU); +} + int r600_bc_add_literal(struct r600_bc *bc, const u32 *value) { struct r600_bc_alu *alu; @@ -172,7 +198,17 @@ int r600_bc_add_literal(struct r600_bc *bc, const u32 *value) if (bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_TEX) { return 0; } - if (bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3) || + if (bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_JUMP || + bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_ELSE || + bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL || + bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK || + bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE || + bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END || + bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_POP) { + return 0; + } + if (((bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3)) && + (bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3))) || LIST_IS_EMPTY(&bc->cf_last->alu)) { R600_ERR("last CF is not ALU (%p)\n", bc->cf_last); return -EINVAL; @@ -241,6 +277,18 @@ int r600_bc_add_tex(struct r600_bc *bc, const struct r600_bc_tex *tex) return 0; } +int r600_bc_add_cfinst(struct r600_bc *bc, int inst) +{ + int r; + r = r600_bc_add_cf(bc); + if (r) + return r; + + bc->cf_last->cond = V_SQ_CF_COND_ACTIVE; + bc->cf_last->inst = inst; + return 0; +} + static int r600_bc_vtx_build(struct r600_bc *bc, struct r600_bc_vtx *vtx, unsigned id) { bc->bytecode[id++] = S_SQ_VTX_WORD0_BUFFER_ID(vtx->buffer_id) | @@ -292,38 +340,44 @@ static int r600_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsign unsigned i; /* don't replace gpr by pv or ps for destination register */ + bc->bytecode[id++] = S_SQ_ALU_WORD0_SRC0_SEL(alu->src[0].sel) | + S_SQ_ALU_WORD0_SRC0_REL(alu->src[0].rel) | + S_SQ_ALU_WORD0_SRC0_CHAN(alu->src[0].chan) | + S_SQ_ALU_WORD0_SRC0_NEG(alu->src[0].neg) | + S_SQ_ALU_WORD0_SRC1_SEL(alu->src[1].sel) | + S_SQ_ALU_WORD0_SRC1_REL(alu->src[1].rel) | + S_SQ_ALU_WORD0_SRC1_CHAN(alu->src[1].chan) | + S_SQ_ALU_WORD0_SRC1_NEG(alu->src[1].neg) | + S_SQ_ALU_WORD0_LAST(alu->last); + if (alu->is_op3) { - bc->bytecode[id++] = S_SQ_ALU_WORD0_SRC0_SEL(alu->src[0].sel) | - S_SQ_ALU_WORD0_SRC0_CHAN(alu->src[0].chan) | - S_SQ_ALU_WORD0_SRC1_SEL(alu->src[1].sel) | - S_SQ_ALU_WORD0_SRC1_CHAN(alu->src[1].chan) | - S_SQ_ALU_WORD0_LAST(alu->last); bc->bytecode[id++] = S_SQ_ALU_WORD1_DST_GPR(alu->dst.sel) | S_SQ_ALU_WORD1_DST_CHAN(alu->dst.chan) | + S_SQ_ALU_WORD1_DST_REL(alu->dst.rel) | S_SQ_ALU_WORD1_CLAMP(alu->dst.clamp) | S_SQ_ALU_WORD1_OP3_SRC2_SEL(alu->src[2].sel) | + S_SQ_ALU_WORD1_OP3_SRC2_REL(alu->src[2].rel) | S_SQ_ALU_WORD1_OP3_SRC2_CHAN(alu->src[2].chan) | S_SQ_ALU_WORD1_OP3_SRC2_NEG(alu->src[2].neg) | S_SQ_ALU_WORD1_OP3_ALU_INST(alu->inst) | S_SQ_ALU_WORD1_BANK_SWIZZLE(0); } else { - bc->bytecode[id++] = S_SQ_ALU_WORD0_SRC0_SEL(alu->src[0].sel) | - S_SQ_ALU_WORD0_SRC0_CHAN(alu->src[0].chan) | - S_SQ_ALU_WORD0_SRC0_NEG(alu->src[0].neg) | - S_SQ_ALU_WORD0_SRC1_SEL(alu->src[1].sel) | - S_SQ_ALU_WORD0_SRC1_CHAN(alu->src[1].chan) | - S_SQ_ALU_WORD0_SRC1_NEG(alu->src[1].neg) | - S_SQ_ALU_WORD0_LAST(alu->last); bc->bytecode[id++] = S_SQ_ALU_WORD1_DST_GPR(alu->dst.sel) | S_SQ_ALU_WORD1_DST_CHAN(alu->dst.chan) | + S_SQ_ALU_WORD1_DST_REL(alu->dst.rel) | S_SQ_ALU_WORD1_CLAMP(alu->dst.clamp) | S_SQ_ALU_WORD1_OP2_SRC0_ABS(alu->src[0].abs) | S_SQ_ALU_WORD1_OP2_SRC1_ABS(alu->src[1].abs) | S_SQ_ALU_WORD1_OP2_WRITE_MASK(alu->dst.write) | S_SQ_ALU_WORD1_OP2_ALU_INST(alu->inst) | - S_SQ_ALU_WORD1_BANK_SWIZZLE(0); + S_SQ_ALU_WORD1_BANK_SWIZZLE(0) | + S_SQ_ALU_WORD1_OP2_UPDATE_EXECUTE_MASK(alu->predicate) | + S_SQ_ALU_WORD1_OP2_UPDATE_PRED(alu->predicate); } if (alu->last) { + if (alu->nliteral && !alu->literal_added) { + R600_ERR("Bug in ALU processing for instruction 0x%08x, literal not added correctly\n"); + } for (i = 0; i < alu->nliteral; i++) { bc->bytecode[id++] = alu->value[i]; } @@ -337,6 +391,7 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) switch (cf->inst) { case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3): + case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3): bc->bytecode[id++] = S_SQ_CF_ALU_WORD0_ADDR(cf->addr >> 1); bc->bytecode[id++] = S_SQ_CF_ALU_WORD1_CF_INST(cf->inst >> 3) | S_SQ_CF_ALU_WORD1_BARRIER(1) | @@ -364,6 +419,20 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->output.inst) | S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(cf->output.end_of_program); break; + case V_SQ_CF_WORD1_SQ_CF_INST_JUMP: + case V_SQ_CF_WORD1_SQ_CF_INST_ELSE: + case V_SQ_CF_WORD1_SQ_CF_INST_POP: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK: + bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->cf_addr >> 1); + bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) | + S_SQ_CF_WORD1_BARRIER(1) | + S_SQ_CF_WORD1_COND(cf->cond) | + S_SQ_CF_WORD1_POP_COUNT(cf->pop_count); + + break; default: R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst); return -EINVAL; @@ -380,6 +449,8 @@ int r600_bc_build(struct r600_bc *bc) unsigned addr; int r; + if (bc->callstack[0].max > 0) + bc->nstack = ((bc->callstack[0].max + 3) >> 2) + 2; /* first path compute addr of each CF block */ /* addr start after all the CF instructions */ @@ -387,6 +458,7 @@ int r600_bc_build(struct r600_bc *bc) LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) { switch (cf->inst) { case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3): + case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3): break; case V_SQ_CF_WORD1_SQ_CF_INST_TEX: case V_SQ_CF_WORD1_SQ_CF_INST_VTX: @@ -398,6 +470,14 @@ int r600_bc_build(struct r600_bc *bc) case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: break; + case V_SQ_CF_WORD1_SQ_CF_INST_JUMP: + case V_SQ_CF_WORD1_SQ_CF_INST_ELSE: + case V_SQ_CF_WORD1_SQ_CF_INST_POP: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK: + break; default: R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst); return -EINVAL; @@ -417,22 +497,13 @@ int r600_bc_build(struct r600_bc *bc) return r; switch (cf->inst) { case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3): + case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3): LIST_FOR_EACH_ENTRY(alu, &cf->alu, list) { - switch (bc->family) { - case CHIP_R600: - case CHIP_RV610: - case CHIP_RV630: - case CHIP_RV670: - case CHIP_RV620: - case CHIP_RV635: - case CHIP_RS780: - case CHIP_RS880: + switch(bc->chiprev) { + case 0: r = r600_bc_alu_build(bc, alu, addr); break; - case CHIP_RV770: - case CHIP_RV730: - case CHIP_RV710: - case CHIP_RV740: + case 1: r = r700_bc_alu_build(bc, alu, addr); break; default: @@ -466,6 +537,13 @@ int r600_bc_build(struct r600_bc *bc) break; case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK: + case V_SQ_CF_WORD1_SQ_CF_INST_JUMP: + case V_SQ_CF_WORD1_SQ_CF_INST_ELSE: + case V_SQ_CF_WORD1_SQ_CF_INST_POP: break; default: R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst); diff --git a/src/gallium/drivers/r600/r600_asm.h b/src/gallium/drivers/r600/r600_asm.h index 10d98afaf0..9e65fcdd4f 100644 --- a/src/gallium/drivers/r600/r600_asm.h +++ b/src/gallium/drivers/r600/r600_asm.h @@ -31,6 +31,7 @@ struct r600_bc_alu_src { unsigned chan; unsigned neg; unsigned abs; + unsigned rel; }; struct r600_bc_alu_dst { @@ -38,6 +39,7 @@ struct r600_bc_alu_dst { unsigned chan; unsigned clamp; unsigned write; + unsigned rel; }; struct r600_bc_alu { @@ -47,6 +49,7 @@ struct r600_bc_alu { unsigned inst; unsigned last; unsigned is_op3; + unsigned predicate; unsigned nliteral; unsigned literal_added; u32 value[4]; @@ -114,22 +117,55 @@ struct r600_bc_cf { unsigned addr; unsigned ndw; unsigned id; + unsigned cond; + unsigned pop_count; + unsigned cf_addr; /* control flow addr */ struct list_head alu; struct list_head tex; struct list_head vtx; struct r600_bc_output output; }; +#define FC_NONE 0 +#define FC_IF 1 +#define FC_LOOP 2 +#define FC_REP 3 +#define FC_PUSH_VPM 4 +#define FC_PUSH_WQM 5 + +struct r600_cf_stack_entry { + int type; + struct r600_bc_cf *start; + struct r600_bc_cf **mid; /* used to store the else point */ + int num_mid; +}; + +#define SQ_MAX_CALL_DEPTH 0x00000020 +struct r600_cf_callstack { + unsigned fc_sp_before_entry; + int sub_desc_index; + int current; + int max; +}; + struct r600_bc { enum radeon_family family; + int chiprev; /* 0 - r600, 1 - r700, 2 - evergreen */ struct list_head cf; struct r600_bc_cf *cf_last; unsigned ndw; unsigned ncf; unsigned ngpr; + unsigned nstack; unsigned nresource; unsigned force_add_cf; u32 *bytecode; + + u32 fc_sp; + struct r600_cf_stack_entry fc_stack[32]; + + unsigned call_sp; + struct r600_cf_callstack callstack[SQ_MAX_CALL_DEPTH]; }; int r600_bc_init(struct r600_bc *bc, enum radeon_family family); @@ -139,5 +175,6 @@ int r600_bc_add_vtx(struct r600_bc *bc, const struct r600_bc_vtx *vtx); int r600_bc_add_tex(struct r600_bc *bc, const struct r600_bc_tex *tex); int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output); int r600_bc_build(struct r600_bc *bc); - +int r600_bc_add_cfinst(struct r600_bc *bc, int inst); +int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int type); #endif diff --git a/src/gallium/drivers/r600/r600_blit.c b/src/gallium/drivers/r600/r600_blit.c index f4eedfe4cb..e6ded342e5 100644 --- a/src/gallium/drivers/r600/r600_blit.c +++ b/src/gallium/drivers/r600/r600_blit.c @@ -24,6 +24,7 @@ * Jerome Glisse * Marek Olšák */ +#include <errno.h> #include <pipe/p_screen.h> #include <util/u_blitter.h> #include <util/u_inlines.h> @@ -31,9 +32,12 @@ #include "util/u_surface.h" #include "r600_screen.h" #include "r600_context.h" +#include "r600d.h" -static void r600_blitter_save_states(struct r600_context *rctx) +static void r600_blitter_save_states(struct pipe_context *ctx) { + struct r600_context *rctx = r600_context(ctx); + util_blitter_save_blend(rctx->blitter, rctx->blend); util_blitter_save_depth_stencil_alpha(rctx->blitter, rctx->dsa); if (rctx->stencil_ref) { @@ -47,48 +51,58 @@ static void r600_blitter_save_states(struct r600_context *rctx) if (rctx->viewport) { util_blitter_save_viewport(rctx->blitter, &rctx->viewport->state.viewport); } - /* XXX util_blitter_save_clip(rctx->blitter, &rctx->clip); */ + if (rctx->clip) { + util_blitter_save_clip(rctx->blitter, &rctx->clip->state.clip); + } util_blitter_save_vertex_buffers(rctx->blitter, rctx->nvertex_buffer, rctx->vertex_buffer); /* remove ptr so they don't get deleted */ rctx->blend = NULL; + rctx->clip = NULL; rctx->vs_shader = NULL; rctx->ps_shader = NULL; rctx->rasterizer = NULL; rctx->dsa = NULL; rctx->vertex_elements = NULL; + + /* suspend queries */ + r600_queries_suspend(ctx); } static void r600_clear(struct pipe_context *ctx, unsigned buffers, - const float *rgba, double depth, unsigned stencil) + const float *rgba, double depth, unsigned stencil) { struct r600_context *rctx = r600_context(ctx); struct pipe_framebuffer_state *fb = &rctx->framebuffer->state.framebuffer; - r600_blitter_save_states(rctx); + r600_blitter_save_states(ctx); util_blitter_clear(rctx->blitter, fb->width, fb->height, fb->nr_cbufs, buffers, rgba, depth, stencil); + /* resume queries */ + r600_queries_resume(ctx); } -static void r600_clear_render_target(struct pipe_context *pipe, +static void r600_clear_render_target(struct pipe_context *ctx, struct pipe_surface *dst, const float *rgba, unsigned dstx, unsigned dsty, unsigned width, unsigned height) { - struct r600_context *rctx = r600_context(pipe); + struct r600_context *rctx = r600_context(ctx); struct pipe_framebuffer_state *fb = &rctx->framebuffer->state.framebuffer; - r600_blitter_save_states(rctx); + r600_blitter_save_states(ctx); util_blitter_save_framebuffer(rctx->blitter, fb); util_blitter_clear_render_target(rctx->blitter, dst, rgba, dstx, dsty, width, height); + /* resume queries */ + r600_queries_resume(ctx); } -static void r600_clear_depth_stencil(struct pipe_context *pipe, +static void r600_clear_depth_stencil(struct pipe_context *ctx, struct pipe_surface *dst, unsigned clear_flags, double depth, @@ -96,17 +110,20 @@ static void r600_clear_depth_stencil(struct pipe_context *pipe, unsigned dstx, unsigned dsty, unsigned width, unsigned height) { - struct r600_context *rctx = r600_context(pipe); + struct r600_context *rctx = r600_context(ctx); struct pipe_framebuffer_state *fb = &rctx->framebuffer->state.framebuffer; - r600_blitter_save_states(rctx); + r600_blitter_save_states(ctx); util_blitter_save_framebuffer(rctx->blitter, fb); util_blitter_clear_depth_stencil(rctx->blitter, dst, clear_flags, depth, stencil, dstx, dsty, width, height); + /* resume queries */ + r600_queries_resume(ctx); } -static void r600_resource_copy_region(struct pipe_context *pipe, + +static void r600_resource_copy_region(struct pipe_context *ctx, struct pipe_resource *dst, struct pipe_subresource subdst, unsigned dstx, unsigned dsty, unsigned dstz, @@ -115,7 +132,7 @@ static void r600_resource_copy_region(struct pipe_context *pipe, unsigned srcx, unsigned srcy, unsigned srcz, unsigned width, unsigned height) { - util_resource_copy_region(pipe, dst, subdst, dstx, dsty, dstz, + util_resource_copy_region(ctx, dst, subdst, dstx, dsty, dstz, src, subsrc, srcx, srcy, srcz, width, height); } @@ -126,3 +143,446 @@ void r600_init_blit_functions(struct r600_context *rctx) rctx->context.clear_depth_stencil = r600_clear_depth_stencil; rctx->context.resource_copy_region = r600_resource_copy_region; } + + +struct r600_blit_states { + struct radeon_state rasterizer; + struct radeon_state dsa; + struct radeon_state blend; + struct radeon_state cb_cntl; + struct radeon_state vgt; + struct radeon_state draw; + struct radeon_state vs_constant0; + struct radeon_state vs_constant1; + struct radeon_state vs_constant2; + struct radeon_state vs_constant3; + struct radeon_state ps_shader; + struct radeon_state vs_shader; + struct radeon_state vs_resource0; + struct radeon_state vs_resource1; +}; + +static int r600_blit_state_vs_resources(struct r600_screen *rscreen, struct r600_blit_states *bstates) +{ + struct radeon_state *rstate; + struct radeon_bo *bo; + u32 vbo[] = { + 0xBF800000, 0xBF800000, 0x3F800000, 0x3F800000, + 0x3F000000, 0x3F000000, 0x3F000000, 0x00000000, + 0x3F800000, 0xBF800000, 0x3F800000, 0x3F800000, + 0x3F000000, 0x3F000000, 0x3F000000, 0x00000000, + 0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000, + 0x3F000000, 0x3F000000, 0x3F000000, 0x00000000, + 0xBF800000, 0x3F800000, 0x3F800000, 0x3F800000, + 0x3F000000, 0x3F000000, 0x3F000000, 0x00000000 + }; + + /* simple shader */ + bo = radeon_bo(rscreen->rw, 0, 128, 4096, NULL); + if (bo == NULL) { + return -ENOMEM; + } + if (radeon_bo_map(rscreen->rw, bo)) { + radeon_bo_decref(rscreen->rw, bo); + return -ENOMEM; + } + memcpy(bo->data, vbo, 128); + radeon_bo_unmap(rscreen->rw, bo); + + rstate = &bstates->vs_resource0; + radeon_state_init(rstate, rscreen->rw, R600_STATE_RESOURCE, 0, R600_SHADER_VS); + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD0] = 0x00000000; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD1] = 0x00000080; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD2] = 0x02302000; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD3] = 0x00000000; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD4] = 0x00000000; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD5] = 0x00000000; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD6] = 0xC0000000; + rstate->bo[0] = bo; + rstate->nbo = 1; + rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + if (radeon_state_pm4(rstate)) { + radeon_state_fini(rstate); + return -ENOMEM; + } + + rstate = &bstates->vs_resource1; + radeon_state_init(rstate, rscreen->rw, R600_STATE_RESOURCE, 1, R600_SHADER_VS); + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD0] = 0x00000010; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD1] = 0x00000070; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD2] = 0x02302000; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD3] = 0x00000000; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD4] = 0x00000000; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD5] = 0x00000000; + rstate->states[R600_VS_RESOURCE__RESOURCE160_WORD6] = 0xC0000000; + rstate->bo[0] = radeon_bo_incref(rscreen->rw, bo); + rstate->nbo = 1; + rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + if (radeon_state_pm4(rstate)) { + radeon_state_fini(rstate); + return -ENOMEM; + } + + return 0; +} + +static void r600_blit_state_vs_shader(struct r600_screen *rscreen, struct radeon_state *rstate) +{ + struct radeon_bo *bo; + u32 shader_bc_r600[] = { + 0x00000004, 0x81000400, + 0x00000008, 0xA01C0000, + 0xC001A03C, 0x94000688, + 0xC0024000, 0x94200688, + 0x7C000000, 0x002D1001, + 0x00080000, 0x00000000, + 0x7C000100, 0x002D1002, + 0x00080000, 0x00000000, + 0x00000001, 0x00601910, + 0x00000401, 0x20601910, + 0x00000801, 0x40601910, + 0x80000C01, 0x60601910, + 0x00000002, 0x00801910, + 0x00000402, 0x20801910, + 0x00000802, 0x40801910, + 0x80000C02, 0x60801910 + }; + u32 shader_bc_r700[] = { + 0x00000004, 0x81000400, + 0x00000008, 0xA01C0000, + 0xC001A03C, 0x94000688, + 0xC0024000, 0x94200688, + 0x7C000000, 0x002D1001, + 0x00080000, 0x00000000, + 0x7C000100, 0x002D1002, + 0x00080000, 0x00000000, + 0x00000001, 0x00600C90, + 0x00000401, 0x20600C90, + 0x00000801, 0x40600C90, + 0x80000C01, 0x60600C90, + 0x00000002, 0x00800C90, + 0x00000402, 0x20800C90, + 0x00000802, 0x40800C90, + 0x80000C02, 0x60800C90 + }; + + /* simple shader */ + bo = radeon_bo(rscreen->rw, 0, 128, 4096, NULL); + if (bo == NULL) { + return; + } + if (radeon_bo_map(rscreen->rw, bo)) { + radeon_bo_decref(rscreen->rw, bo); + return; + } + switch (rscreen->chip_class) { + case R600: + memcpy(bo->data, shader_bc_r600, 128); + break; + case R700: + memcpy(bo->data, shader_bc_r700, 128); + break; + default: + R600_ERR("unsupported chip family\n"); + radeon_bo_unmap(rscreen->rw, bo); + radeon_bo_decref(rscreen->rw, bo); + return; + } + radeon_bo_unmap(rscreen->rw, bo); + + radeon_state_init(rstate, rscreen->rw, R600_STATE_SHADER, 0, R600_SHADER_VS); + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_VS_SHADER__SPI_VS_OUT_ID_0] = 0x03020100; + rstate->states[R600_VS_SHADER__SPI_VS_OUT_ID_1] = 0x07060504; + rstate->states[R600_VS_SHADER__SQ_PGM_RESOURCES_VS] = 0x00000005; + + rstate->bo[0] = bo; + rstate->bo[1] = radeon_bo_incref(rscreen->rw, bo); + rstate->nbo = 2; + rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + rstate->placement[2] = RADEON_GEM_DOMAIN_GTT; + + radeon_state_pm4(rstate); +} + +static void r600_blit_state_ps_shader(struct r600_screen *rscreen, struct radeon_state *rstate) +{ + struct radeon_bo *bo; + u32 shader_bc_r600[] = { + 0x00000002, 0xA00C0000, + 0xC0008000, 0x94200688, + 0x00000000, 0x00201910, + 0x00000400, 0x20201910, + 0x00000800, 0x40201910, + 0x80000C00, 0x60201910 + }; + u32 shader_bc_r700[] = { + 0x00000002, 0xA00C0000, + 0xC0008000, 0x94200688, + 0x00000000, 0x00200C90, + 0x00000400, 0x20200C90, + 0x00000800, 0x40200C90, + 0x80000C00, 0x60200C90 + }; + + /* simple shader */ + bo = radeon_bo(rscreen->rw, 0, 128, 4096, NULL); + if (bo == NULL) { + radeon_bo_decref(rscreen->rw, bo); + return; + } + if (radeon_bo_map(rscreen->rw, bo)) { + return; + } + switch (rscreen->chip_class) { + case R600: + memcpy(bo->data, shader_bc_r600, 48); + break; + case R700: + memcpy(bo->data, shader_bc_r700, 48); + break; + default: + R600_ERR("unsupported chip family\n"); + radeon_bo_unmap(rscreen->rw, bo); + radeon_bo_decref(rscreen->rw, bo); + return; + } + radeon_bo_unmap(rscreen->rw, bo); + + radeon_state_init(rstate, rscreen->rw, R600_STATE_SHADER, 0, R600_SHADER_PS); + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_PS_SHADER__SPI_PS_INPUT_CNTL_0] = 0x00000C00; + rstate->states[R600_PS_SHADER__SPI_PS_IN_CONTROL_0] = 0x10000001; + rstate->states[R600_PS_SHADER__SQ_PGM_EXPORTS_PS] = 0x00000002; + rstate->states[R600_PS_SHADER__SQ_PGM_RESOURCES_PS] = 0x00000002; + + rstate->bo[0] = bo; + rstate->nbo = 1; + rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + + radeon_state_pm4(rstate); +} + +static void r600_blit_state_vgt(struct r600_screen *rscreen, struct radeon_state *rstate) +{ + radeon_state_init(rstate, rscreen->rw, R600_STATE_VGT, 0, 0); + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_VGT__VGT_DMA_NUM_INSTANCES] = 0x00000001; + rstate->states[R600_VGT__VGT_MAX_VTX_INDX] = 0x00FFFFFF; + rstate->states[R600_VGT__VGT_PRIMITIVE_TYPE] = 0x00000005; + + radeon_state_pm4(rstate); +} + +static void r600_blit_state_draw(struct r600_screen *rscreen, struct radeon_state *rstate) +{ + radeon_state_init(rstate, rscreen->rw, R600_STATE_DRAW, 0, 0); + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_DRAW__VGT_DRAW_INITIATOR] = 0x00000002; + rstate->states[R600_DRAW__VGT_NUM_INDICES] = 0x00000004; + + radeon_state_pm4(rstate); +} + +static void r600_blit_state_vs_constant(struct r600_screen *rscreen, struct radeon_state *rstate, + unsigned id, float c0, float c1, float c2, float c3) +{ + radeon_state_init(rstate, rscreen->rw, R600_STATE_CONSTANT, id, R600_SHADER_VS); + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_VS_CONSTANT__SQ_ALU_CONSTANT0_256] = fui(c0); + rstate->states[R600_VS_CONSTANT__SQ_ALU_CONSTANT1_256] = fui(c1); + rstate->states[R600_VS_CONSTANT__SQ_ALU_CONSTANT2_256] = fui(c2); + rstate->states[R600_VS_CONSTANT__SQ_ALU_CONSTANT3_256] = fui(c3); + + radeon_state_pm4(rstate); +} + +static void r600_blit_state_rasterizer(struct r600_screen *rscreen, struct radeon_state *rstate) +{ + radeon_state_init(rstate, rscreen->rw, R600_STATE_RASTERIZER, 0, 0); + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_RASTERIZER__PA_CL_GB_HORZ_CLIP_ADJ] = 0x3F800000; + rstate->states[R600_RASTERIZER__PA_CL_GB_HORZ_DISC_ADJ] = 0x3F800000; + rstate->states[R600_RASTERIZER__PA_CL_GB_VERT_CLIP_ADJ] = 0x3F800000; + rstate->states[R600_RASTERIZER__PA_CL_GB_VERT_DISC_ADJ] = 0x3F800000; + rstate->states[R600_RASTERIZER__PA_SC_LINE_CNTL] = 0x00000400; + rstate->states[R600_RASTERIZER__PA_SC_LINE_STIPPLE] = 0x00000005; + rstate->states[R600_RASTERIZER__PA_SU_LINE_CNTL] = 0x00000008; + rstate->states[R600_RASTERIZER__PA_SU_POINT_MINMAX] = 0x80000000; + rstate->states[R600_RASTERIZER__PA_SU_SC_MODE_CNTL] = 0x00080004; + rstate->states[R600_RASTERIZER__SPI_INTERP_CONTROL_0] = 0x00000001; + + radeon_state_pm4(rstate); +} + +static void r600_blit_state_dsa(struct r600_screen *rscreen, struct radeon_state *rstate) +{ + radeon_state_init(rstate, rscreen->rw, R600_STATE_DSA, 0, 0); + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_DSA__DB_ALPHA_TO_MASK] = 0x0000AA00; + rstate->states[R600_DSA__DB_DEPTH_CLEAR] = 0x3F800000; + rstate->states[R600_DSA__DB_RENDER_CONTROL] = 0x00000060; + rstate->states[R600_DSA__DB_RENDER_OVERRIDE] = 0x0000002A; + rstate->states[R600_DSA__DB_SHADER_CONTROL] = 0x00000210; + + radeon_state_pm4(rstate); +} + +static void r600_blit_state_blend(struct r600_screen *rscreen, struct radeon_state *rstate) +{ + radeon_state_init(rstate, rscreen->rw, R600_STATE_BLEND, 0, 0); + radeon_state_pm4(rstate); +} + +static void r600_blit_state_cb_cntl(struct r600_screen *rscreen, struct radeon_state *rstate) +{ + radeon_state_init(rstate, rscreen->rw, R600_STATE_CB_CNTL, 0, 0); + rstate->states[R600_CB_CNTL__CB_CLRCMP_CONTROL] = 0x01000000; + rstate->states[R600_CB_CNTL__CB_CLRCMP_DST] = 0x000000FF; + rstate->states[R600_CB_CNTL__CB_CLRCMP_MSK] = 0xFFFFFFFF; + rstate->states[R600_CB_CNTL__CB_COLOR_CONTROL] = 0x00CC0080; + rstate->states[R600_CB_CNTL__CB_SHADER_MASK] = 0x0000000F; + rstate->states[R600_CB_CNTL__CB_TARGET_MASK] = 0x0000000F; + rstate->states[R600_CB_CNTL__PA_SC_AA_MASK] = 0xFFFFFFFF; + radeon_state_pm4(rstate); +} + +static int r600_blit_states_init(struct pipe_context *ctx, struct r600_blit_states *bstates) +{ + struct r600_screen *rscreen = r600_screen(ctx->screen); + + r600_blit_state_ps_shader(rscreen, &bstates->ps_shader); + r600_blit_state_vs_shader(rscreen, &bstates->vs_shader); + r600_blit_state_vgt(rscreen, &bstates->vgt); + r600_blit_state_draw(rscreen, &bstates->draw); + r600_blit_state_vs_constant(rscreen, &bstates->vs_constant0, 0, 1.0, 0.0, 0.0, 0.0); + r600_blit_state_vs_constant(rscreen, &bstates->vs_constant1, 1, 0.0, 1.0, 0.0, 0.0); + r600_blit_state_vs_constant(rscreen, &bstates->vs_constant2, 2, 0.0, 0.0, -0.00199900055, 0.0); + r600_blit_state_vs_constant(rscreen, &bstates->vs_constant3, 3, 0.0, 0.0, -0.99900049, 1.0); + r600_blit_state_rasterizer(rscreen, &bstates->rasterizer); + r600_blit_state_dsa(rscreen, &bstates->dsa); + r600_blit_state_blend(rscreen, &bstates->blend); + r600_blit_state_cb_cntl(rscreen, &bstates->cb_cntl); + r600_blit_state_vs_resources(rscreen, bstates); + return 0; +} + +static void r600_blit_states_destroy(struct pipe_context *ctx, struct r600_blit_states *bstates) +{ + radeon_state_fini(&bstates->ps_shader); + radeon_state_fini(&bstates->vs_shader); + radeon_state_fini(&bstates->vs_resource0); + radeon_state_fini(&bstates->vs_resource1); +} + +int r600_blit_uncompress_depth(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level) +{ + struct r600_screen *rscreen = r600_screen(ctx->screen); + struct r600_context *rctx = r600_context(ctx); + struct radeon_draw draw; + struct r600_blit_states bstates; + int r; + + r = r600_texture_scissor(ctx, rtexture, level); + if (r) { + return r; + } + r = r600_texture_cb(ctx, rtexture, 0, level); + if (r) { + return r; + } + r = r600_texture_db(ctx, rtexture, level); + if (r) { + return r; + } + r = r600_texture_viewport(ctx, rtexture, level); + if (r) { + return r; + } + + r = r600_blit_states_init(ctx, &bstates); + if (r) { + return r; + } + bstates.dsa.states[R600_DSA__DB_RENDER_CONTROL] = 0x0000008C; + bstates.cb_cntl.states[R600_CB_CNTL__CB_TARGET_MASK] = 0x00000001; + /* force rebuild */ + bstates.dsa.cpm4 = bstates.cb_cntl.cpm4 = 0; + if (radeon_state_pm4(&bstates.dsa)) { + goto out; + } + if (radeon_state_pm4(&bstates.cb_cntl)) { + goto out; + } + + r = radeon_draw_init(&draw, rscreen->rw); + if (r) { + R600_ERR("failed creating draw for uncompressing textures\n"); + goto out; + } + + radeon_draw_bind(&draw, &bstates.vs_shader); + radeon_draw_bind(&draw, &bstates.ps_shader); + radeon_draw_bind(&draw, &bstates.rasterizer); + radeon_draw_bind(&draw, &bstates.dsa); + radeon_draw_bind(&draw, &bstates.blend); + radeon_draw_bind(&draw, &bstates.cb_cntl); + radeon_draw_bind(&draw, &rctx->config); + radeon_draw_bind(&draw, &bstates.vgt); + radeon_draw_bind(&draw, &bstates.draw); + radeon_draw_bind(&draw, &bstates.vs_resource0); + radeon_draw_bind(&draw, &bstates.vs_resource1); + radeon_draw_bind(&draw, &bstates.vs_constant0); + radeon_draw_bind(&draw, &bstates.vs_constant1); + radeon_draw_bind(&draw, &bstates.vs_constant2); + radeon_draw_bind(&draw, &bstates.vs_constant3); + radeon_draw_bind(&draw, &rtexture->viewport[level]); + radeon_draw_bind(&draw, &rtexture->scissor[level]); + radeon_draw_bind(&draw, &rtexture->cb[0][level]); + radeon_draw_bind(&draw, &rtexture->db[level]); + + /* suspend queries */ + r600_queries_suspend(ctx); + + /* schedule draw*/ + r = radeon_ctx_set_draw(&rctx->ctx, &draw); + if (r == -EBUSY) { + r600_flush(ctx, 0, NULL); + r = radeon_ctx_set_draw(&rctx->ctx, &draw); + } + if (r) { + goto out; + } + + /* resume queries */ + r600_queries_resume(ctx); + +out: + r600_blit_states_destroy(ctx, &bstates); + return r; +} diff --git a/src/gallium/drivers/r600/r600_context.c b/src/gallium/drivers/r600/r600_context.c index edde80c660..7a0e5b4049 100644 --- a/src/gallium/drivers/r600/r600_context.c +++ b/src/gallium/drivers/r600/r600_context.c @@ -34,10 +34,26 @@ #include "r600_resource.h" #include "r600d.h" + static void r600_destroy_context(struct pipe_context *context) { struct r600_context *rctx = r600_context(context); + rctx->rasterizer = r600_context_state_decref(rctx->rasterizer); + rctx->poly_stipple = r600_context_state_decref(rctx->poly_stipple); + rctx->scissor = r600_context_state_decref(rctx->scissor); + rctx->clip = r600_context_state_decref(rctx->clip); + rctx->ps_shader = r600_context_state_decref(rctx->ps_shader); + rctx->vs_shader = r600_context_state_decref(rctx->vs_shader); + rctx->depth = r600_context_state_decref(rctx->depth); + rctx->stencil = r600_context_state_decref(rctx->stencil); + rctx->alpha = r600_context_state_decref(rctx->alpha); + rctx->dsa = r600_context_state_decref(rctx->dsa); + rctx->blend = r600_context_state_decref(rctx->blend); + rctx->stencil_ref = r600_context_state_decref(rctx->stencil_ref); + rctx->viewport = r600_context_state_decref(rctx->viewport); + rctx->framebuffer = r600_context_state_decref(rctx->framebuffer); + radeon_ctx_fini(&rctx->ctx); FREE(rctx); } @@ -45,27 +61,35 @@ void r600_flush(struct pipe_context *ctx, unsigned flags, struct pipe_fence_handle **fence) { struct r600_context *rctx = r600_context(ctx); - struct r600_screen *rscreen = rctx->screen; + struct r600_query *rquery; static int dc = 0; char dname[256]; - if (radeon_ctx_pm4(rctx->ctx)) - return; + /* suspend queries */ + r600_queries_suspend(ctx); /* FIXME dumping should be removed once shader support instructions * without throwing bad code */ - if (!rctx->ctx->cpm4) + if (!rctx->ctx.cdwords) goto out; +#if 0 sprintf(dname, "gallium-%08d.bof", dc); - if (dc < 1) - radeon_ctx_dump_bof(rctx->ctx, dname); + if (dc < 2) { + radeon_ctx_dump_bof(&rctx->ctx, dname); + R600_ERR("dumped %s\n", dname); + } +#endif #if 1 - radeon_ctx_submit(rctx->ctx); + radeon_ctx_submit(&rctx->ctx); #endif + LIST_FOR_EACH_ENTRY(rquery, &rctx->query_list, list) { + rquery->flushed = true; + } dc++; out: - rctx->ctx = radeon_ctx_decref(rctx->ctx); - rctx->ctx = radeon_ctx(rscreen->rw); + radeon_ctx_clear(&rctx->ctx); + /* resume queries */ + r600_queries_resume(ctx); } static void r600_init_config(struct r600_context *rctx) @@ -207,9 +231,9 @@ static void r600_init_config(struct r600_context *rctx) num_es_stack_entries = 0; break; } - rctx->hw_states.config = radeon_state(rctx->rw, R600_CONFIG_TYPE, R600_CONFIG); + radeon_state_init(&rctx->config, rctx->rw, R600_STATE_CONFIG, 0, 0); - rctx->hw_states.config->states[R600_CONFIG__SQ_CONFIG] = 0x00000000; + rctx->config.states[R600_CONFIG__SQ_CONFIG] = 0x00000000; switch (family) { case CHIP_RV610: case CHIP_RV620: @@ -218,75 +242,85 @@ static void r600_init_config(struct r600_context *rctx) case CHIP_RV710: break; default: - rctx->hw_states.config->states[R600_CONFIG__SQ_CONFIG] |= S_008C00_VC_ENABLE(1); + rctx->config.states[R600_CONFIG__SQ_CONFIG] |= S_008C00_VC_ENABLE(1); break; } - rctx->hw_states.config->states[R600_CONFIG__SQ_CONFIG] |= S_008C00_DX9_CONSTS(1); - rctx->hw_states.config->states[R600_CONFIG__SQ_CONFIG] |= S_008C00_ALU_INST_PREFER_VECTOR(1); - rctx->hw_states.config->states[R600_CONFIG__SQ_CONFIG] |= S_008C00_PS_PRIO(ps_prio); - rctx->hw_states.config->states[R600_CONFIG__SQ_CONFIG] |= S_008C00_VS_PRIO(vs_prio); - rctx->hw_states.config->states[R600_CONFIG__SQ_CONFIG] |= S_008C00_GS_PRIO(gs_prio); - rctx->hw_states.config->states[R600_CONFIG__SQ_CONFIG] |= S_008C00_ES_PRIO(es_prio); + rctx->config.states[R600_CONFIG__SQ_CONFIG] |= S_008C00_DX9_CONSTS(1); + rctx->config.states[R600_CONFIG__SQ_CONFIG] |= S_008C00_ALU_INST_PREFER_VECTOR(1); + rctx->config.states[R600_CONFIG__SQ_CONFIG] |= S_008C00_PS_PRIO(ps_prio); + rctx->config.states[R600_CONFIG__SQ_CONFIG] |= S_008C00_VS_PRIO(vs_prio); + rctx->config.states[R600_CONFIG__SQ_CONFIG] |= S_008C00_GS_PRIO(gs_prio); + rctx->config.states[R600_CONFIG__SQ_CONFIG] |= S_008C00_ES_PRIO(es_prio); + + rctx->config.states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_1] = 0; + rctx->config.states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_1] |= S_008C04_NUM_PS_GPRS(num_ps_gprs); + rctx->config.states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_1] |= S_008C04_NUM_VS_GPRS(num_vs_gprs); + rctx->config.states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_1] |= S_008C04_NUM_CLAUSE_TEMP_GPRS(num_temp_gprs); - rctx->hw_states.config->states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_1] = 0; - rctx->hw_states.config->states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_1] |= S_008C04_NUM_PS_GPRS(num_ps_gprs); - rctx->hw_states.config->states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_1] |= S_008C04_NUM_VS_GPRS(num_vs_gprs); - rctx->hw_states.config->states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_1] |= S_008C04_NUM_CLAUSE_TEMP_GPRS(num_temp_gprs); + rctx->config.states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_2] = 0; + rctx->config.states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_2] |= S_008C08_NUM_GS_GPRS(num_gs_gprs); + rctx->config.states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_2] |= S_008C08_NUM_GS_GPRS(num_es_gprs); - rctx->hw_states.config->states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_2] = 0; - rctx->hw_states.config->states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_2] |= S_008C08_NUM_GS_GPRS(num_gs_gprs); - rctx->hw_states.config->states[R600_CONFIG__SQ_GPR_RESOURCE_MGMT_2] |= S_008C08_NUM_GS_GPRS(num_es_gprs); + rctx->config.states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] = 0; + rctx->config.states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] |= S_008C0C_NUM_PS_THREADS(num_ps_threads); + rctx->config.states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] |= S_008C0C_NUM_VS_THREADS(num_vs_threads); + rctx->config.states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] |= S_008C0C_NUM_GS_THREADS(num_gs_threads); + rctx->config.states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] |= S_008C0C_NUM_ES_THREADS(num_es_threads); - rctx->hw_states.config->states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] = 0; - rctx->hw_states.config->states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] |= S_008C0C_NUM_PS_THREADS(num_ps_threads); - rctx->hw_states.config->states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] |= S_008C0C_NUM_VS_THREADS(num_vs_threads); - rctx->hw_states.config->states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] |= S_008C0C_NUM_GS_THREADS(num_gs_threads); - rctx->hw_states.config->states[R600_CONFIG__SQ_THREAD_RESOURCE_MGMT] |= S_008C0C_NUM_ES_THREADS(num_es_threads); + rctx->config.states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_1] = 0; + rctx->config.states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_1] |= S_008C10_NUM_PS_STACK_ENTRIES(num_ps_stack_entries); + rctx->config.states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_1] |= S_008C10_NUM_VS_STACK_ENTRIES(num_vs_stack_entries); - rctx->hw_states.config->states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_1] = 0; - rctx->hw_states.config->states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_1] |= S_008C10_NUM_PS_STACK_ENTRIES(num_ps_stack_entries); - rctx->hw_states.config->states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_1] |= S_008C10_NUM_VS_STACK_ENTRIES(num_vs_stack_entries); + rctx->config.states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_2] = 0; + rctx->config.states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_2] |= S_008C14_NUM_GS_STACK_ENTRIES(num_gs_stack_entries); + rctx->config.states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_2] |= S_008C14_NUM_ES_STACK_ENTRIES(num_es_stack_entries); - rctx->hw_states.config->states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_2] = 0; - rctx->hw_states.config->states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_2] |= S_008C14_NUM_GS_STACK_ENTRIES(num_gs_stack_entries); - rctx->hw_states.config->states[R600_CONFIG__SQ_STACK_RESOURCE_MGMT_2] |= S_008C14_NUM_ES_STACK_ENTRIES(num_es_stack_entries); + rctx->config.states[R600_CONFIG__VC_ENHANCE] = 0x00000000; + rctx->config.states[R600_CONFIG__SX_MISC] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SQ_DYN_GPR_CNTL_PS_FLUSH_REQ] = 0x00004000; - rctx->hw_states.config->states[R600_CONFIG__TA_CNTL_AUX] = 0x07000002; - rctx->hw_states.config->states[R600_CONFIG__VC_ENHANCE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__DB_DEBUG] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__DB_WATERMARKS] = 0x00420204; - rctx->hw_states.config->states[R600_CONFIG__SX_MISC] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SPI_THREAD_GROUPING] = 0x00000001; - rctx->hw_states.config->states[R600_CONFIG__CB_SHADER_CONTROL] = 0x00000003; - rctx->hw_states.config->states[R600_CONFIG__SQ_ESGS_RING_ITEMSIZE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SQ_GSVS_RING_ITEMSIZE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SQ_ESTMP_RING_ITEMSIZE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SQ_GSTMP_RING_ITEMSIZE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SQ_VSTMP_RING_ITEMSIZE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SQ_PSTMP_RING_ITEMSIZE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SQ_FBUF_RING_ITEMSIZE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SQ_REDUC_RING_ITEMSIZE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__SQ_GS_VERT_ITEMSIZE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_OUTPUT_PATH_CNTL] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_HOS_CNTL] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_HOS_MAX_TESS_LEVEL] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_HOS_MIN_TESS_LEVEL] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_HOS_REUSE_DEPTH] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_GROUP_PRIM_TYPE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_GROUP_FIRST_DECR] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_GROUP_DECR] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_GROUP_VECT_0_CNTL] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_GROUP_VECT_1_CNTL] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_GROUP_VECT_0_FMT_CNTL] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_GROUP_VECT_1_FMT_CNTL] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_GS_MODE] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__PA_SC_MODE_CNTL] = 0x00514000; - rctx->hw_states.config->states[R600_CONFIG__VGT_STRMOUT_EN] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_REUSE_OFF] = 0x00000001; - rctx->hw_states.config->states[R600_CONFIG__VGT_VTX_CNT_EN] = 0x00000000; - rctx->hw_states.config->states[R600_CONFIG__VGT_STRMOUT_BUFFER_EN] = 0x00000000; - radeon_state_pm4(rctx->hw_states.config); + if (family >= CHIP_RV770) { + rctx->config.states[R600_CONFIG__SQ_DYN_GPR_CNTL_PS_FLUSH_REQ] = 0x00004000; + rctx->config.states[R600_CONFIG__TA_CNTL_AUX] = 0x07000002; + rctx->config.states[R600_CONFIG__DB_DEBUG] = 0x00000000; + rctx->config.states[R600_CONFIG__DB_WATERMARKS] = 0x00420204; + rctx->config.states[R600_CONFIG__SPI_THREAD_GROUPING] = 0x00000000; + rctx->config.states[R600_CONFIG__PA_SC_MODE_CNTL] = 0x00514000; + } else { + rctx->config.states[R600_CONFIG__SQ_DYN_GPR_CNTL_PS_FLUSH_REQ] = 0x00000000; + rctx->config.states[R600_CONFIG__TA_CNTL_AUX] = 0x07000003; + rctx->config.states[R600_CONFIG__DB_DEBUG] = 0x82000000; + rctx->config.states[R600_CONFIG__DB_WATERMARKS] = 0x01020204; + rctx->config.states[R600_CONFIG__SPI_THREAD_GROUPING] = 0x00000001; + rctx->config.states[R600_CONFIG__PA_SC_MODE_CNTL] = 0x00004010; + } + rctx->config.states[R600_CONFIG__CB_SHADER_CONTROL] = 0x00000003; + rctx->config.states[R600_CONFIG__SQ_ESGS_RING_ITEMSIZE] = 0x00000000; + rctx->config.states[R600_CONFIG__SQ_GSVS_RING_ITEMSIZE] = 0x00000000; + rctx->config.states[R600_CONFIG__SQ_ESTMP_RING_ITEMSIZE] = 0x00000000; + rctx->config.states[R600_CONFIG__SQ_GSTMP_RING_ITEMSIZE] = 0x00000000; + rctx->config.states[R600_CONFIG__SQ_VSTMP_RING_ITEMSIZE] = 0x00000000; + rctx->config.states[R600_CONFIG__SQ_PSTMP_RING_ITEMSIZE] = 0x00000000; + rctx->config.states[R600_CONFIG__SQ_FBUF_RING_ITEMSIZE] = 0x00000000; + rctx->config.states[R600_CONFIG__SQ_REDUC_RING_ITEMSIZE] = 0x00000000; + rctx->config.states[R600_CONFIG__SQ_GS_VERT_ITEMSIZE] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_OUTPUT_PATH_CNTL] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_HOS_CNTL] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_HOS_MAX_TESS_LEVEL] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_HOS_MIN_TESS_LEVEL] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_HOS_REUSE_DEPTH] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_GROUP_PRIM_TYPE] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_GROUP_FIRST_DECR] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_GROUP_DECR] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_GROUP_VECT_0_CNTL] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_GROUP_VECT_1_CNTL] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_GROUP_VECT_0_FMT_CNTL] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_GROUP_VECT_1_FMT_CNTL] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_GS_MODE] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_STRMOUT_EN] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_REUSE_OFF] = 0x00000001; + rctx->config.states[R600_CONFIG__VGT_VTX_CNT_EN] = 0x00000000; + rctx->config.states[R600_CONFIG__VGT_STRMOUT_BUFFER_EN] = 0x00000000; + radeon_state_pm4(&rctx->config); } struct pipe_context *r600_create_context(struct pipe_screen *screen, void *priv) @@ -320,7 +354,7 @@ struct pipe_context *r600_create_context(struct pipe_screen *screen, void *priv) r600_init_config(rctx); - rctx->ctx = radeon_ctx(rscreen->rw); - rctx->draw = radeon_draw(rscreen->rw); + radeon_ctx_init(&rctx->ctx, rscreen->rw); + radeon_draw_init(&rctx->draw, rscreen->rw); return &rctx->context; } diff --git a/src/gallium/drivers/r600/r600_context.h b/src/gallium/drivers/r600/r600_context.h index 76d5de8653..cea0813054 100644 --- a/src/gallium/drivers/r600/r600_context.h +++ b/src/gallium/drivers/r600/r600_context.h @@ -30,9 +30,32 @@ #include <tgsi/tgsi_parse.h> #include <tgsi/tgsi_util.h> #include <util/u_blitter.h> +#include <util/u_double_list.h> #include "radeon.h" #include "r600_shader.h" +#define R600_QUERY_STATE_STARTED (1 << 0) +#define R600_QUERY_STATE_ENDED (1 << 1) +#define R600_QUERY_STATE_SUSPENDED (1 << 2) + +struct r600_query { + u64 result; + /* The kind of query. Currently only OQ is supported. */ + unsigned type; + /* How many results have been written, in dwords. It's incremented + * after end_query and flush. */ + unsigned num_results; + /* if we've flushed the query */ + boolean flushed; + unsigned state; + /* The buffer where query results are stored. */ + struct radeon_bo *buffer; + unsigned buffer_size; + /* linked list of queries */ + struct list_head list; + struct radeon_state rstate; +}; + /* XXX move this to a more appropriate place */ union pipe_states { struct pipe_rasterizer_state rasterizer; @@ -72,13 +95,16 @@ enum pipe_state_type { pipe_type_count }; +#define R600_MAX_RSTATE 16 + struct r600_context_state { union pipe_states state; unsigned refcount; unsigned type; - struct radeon_state *rstate; + struct radeon_state rstate[R600_MAX_RSTATE]; struct r600_shader shader; struct radeon_bo *bo; + unsigned nrstate; }; struct r600_vertex_element @@ -89,28 +115,25 @@ struct r600_vertex_element }; struct r600_context_hw_states { - struct radeon_state *rasterizer; - struct radeon_state *scissor; - struct radeon_state *dsa; - struct radeon_state *blend; - struct radeon_state *viewport; - struct radeon_state *cb[8]; - struct radeon_state *config; - struct radeon_state *cb_cntl; - struct radeon_state *db; - unsigned ps_nresource; - unsigned ps_nsampler; - struct radeon_state *ps_resource[160]; - struct radeon_state *ps_sampler[16]; + struct radeon_state rasterizer; + struct radeon_state scissor; + struct radeon_state dsa; + struct radeon_state cb_cntl; }; struct r600_context { struct pipe_context context; struct r600_screen *screen; struct radeon *rw; - struct radeon_ctx *ctx; + struct radeon_ctx ctx; struct blitter_context *blitter; - struct radeon_draw *draw; + struct radeon_draw draw; + struct radeon_state config; + /* FIXME get rid of those vs_resource,vs/ps_constant */ + struct radeon_state vs_resource[160]; + unsigned vs_nresource; + struct radeon_state vs_constant[256]; + struct radeon_state ps_constant[256]; /* hw states */ struct r600_context_hw_states hw_states; /* pipe states */ @@ -134,14 +157,15 @@ struct r600_context { struct r600_context_state *stencil_ref; struct r600_context_state *viewport; struct r600_context_state *framebuffer; - struct r600_context_state *ps_sampler[PIPE_MAX_ATTRIBS]; - struct r600_context_state *vs_sampler[PIPE_MAX_ATTRIBS]; - struct r600_context_state *ps_sampler_view[PIPE_MAX_ATTRIBS]; - struct r600_context_state *vs_sampler_view[PIPE_MAX_ATTRIBS]; + struct radeon_state *ps_sampler[PIPE_MAX_ATTRIBS]; + struct radeon_state *vs_sampler[PIPE_MAX_ATTRIBS]; + struct radeon_state *ps_sampler_view[PIPE_MAX_ATTRIBS]; + struct radeon_state *vs_sampler_view[PIPE_MAX_ATTRIBS]; struct r600_vertex_element *vertex_elements; struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS]; struct pipe_index_buffer index_buffer; - struct pipe_blend_color blend_color; + struct pipe_blend_color blend_color; + struct list_head query_list; }; /* Convenience cast wrapper. */ @@ -150,13 +174,18 @@ static INLINE struct r600_context *r600_context(struct pipe_context *pipe) return (struct r600_context*)pipe; } +static INLINE struct r600_query* r600_query(struct pipe_query* q) +{ + return (struct r600_query*)q; +} + struct r600_context_state *r600_context_state(struct r600_context *rctx, unsigned type, const void *state); struct r600_context_state *r600_context_state_incref(struct r600_context_state *rstate); struct r600_context_state *r600_context_state_decref(struct r600_context_state *rstate); void r600_flush(struct pipe_context *ctx, unsigned flags, struct pipe_fence_handle **fence); -int r600_context_hw_states(struct r600_context *rctx); +int r600_context_hw_states(struct pipe_context *ctx); void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info); @@ -178,4 +207,10 @@ extern int r600_pipe_shader_update(struct pipe_context *ctx, uint32_t r600_translate_texformat(enum pipe_format format, const unsigned char *swizzle_view, uint32_t *word4_p, uint32_t *yuv_format_p); + +/* query */ +extern void r600_queries_resume(struct pipe_context *ctx); +extern void r600_queries_suspend(struct pipe_context *ctx); + + #endif diff --git a/src/gallium/drivers/r600/r600_draw.c b/src/gallium/drivers/r600/r600_draw.c index f058455162..fabd337d23 100644 --- a/src/gallium/drivers/r600/r600_draw.c +++ b/src/gallium/drivers/r600/r600_draw.c @@ -31,6 +31,7 @@ #include <util/u_math.h> #include <util/u_inlines.h> #include <util/u_memory.h> +#include "radeon.h" #include "r600_screen.h" #include "r600_context.h" #include "r600_resource.h" @@ -38,8 +39,8 @@ struct r600_draw { struct pipe_context *ctx; - struct radeon_state *draw; - struct radeon_state *vgt; + struct radeon_state draw; + struct radeon_state vgt; unsigned mode; unsigned start; unsigned count; @@ -51,6 +52,7 @@ static int r600_draw_common(struct r600_draw *draw) { struct r600_context *rctx = r600_context(draw->ctx); struct r600_screen *rscreen = rctx->screen; + /* FIXME vs_resource */ struct radeon_state *vs_resource; struct r600_resource *rbuffer; unsigned i, j, offset, format, prim; @@ -58,7 +60,7 @@ static int r600_draw_common(struct r600_draw *draw) struct pipe_vertex_buffer *vertex_buffer; int r; - r = r600_context_hw_states(rctx); + r = r600_context_hw_states(draw->ctx); if (r) return r; switch (draw->index_size) { @@ -81,6 +83,7 @@ static int r600_draw_common(struct r600_draw *draw) r = r600_conv_pipe_prim(draw->mode, &prim); if (r) return r; + /* rebuild vertex shader if input format changed */ r = r600_pipe_shader_update(draw->ctx, rctx->vs_shader); if (r) @@ -88,26 +91,24 @@ static int r600_draw_common(struct r600_draw *draw) r = r600_pipe_shader_update(draw->ctx, rctx->ps_shader); if (r) return r; - r = radeon_draw_set(rctx->draw, rctx->vs_shader->rstate); - if (r) - return r; - r = radeon_draw_set(rctx->draw, rctx->ps_shader->rstate); - if (r) - return r; + radeon_draw_bind(&rctx->draw, &rctx->vs_shader->rstate[0]); + radeon_draw_bind(&rctx->draw, &rctx->ps_shader->rstate[0]); + for (i = 0 ; i < rctx->vs_nresource; i++) { + radeon_state_fini(&rctx->vs_resource[i]); + } for (i = 0 ; i < rctx->vertex_elements->count; i++) { + vs_resource = &rctx->vs_resource[i]; j = rctx->vertex_elements->elements[i].vertex_buffer_index; vertex_buffer = &rctx->vertex_buffer[j]; rbuffer = (struct r600_resource*)vertex_buffer->buffer; offset = rctx->vertex_elements->elements[i].src_offset + vertex_buffer->buffer_offset; format = r600_translate_colorformat(rctx->vertex_elements->elements[i].src_format); - vs_resource = radeon_state(rscreen->rw, R600_VS_RESOURCE_TYPE, R600_VS_RESOURCE + i); - if (vs_resource == NULL) - return -ENOMEM; + radeon_state_init(vs_resource, rscreen->rw, R600_STATE_RESOURCE, i, R600_SHADER_VS); vs_resource->bo[0] = radeon_bo_incref(rscreen->rw, rbuffer->bo); vs_resource->nbo = 1; vs_resource->states[R600_PS_RESOURCE__RESOURCE0_WORD0] = offset; - vs_resource->states[R600_PS_RESOURCE__RESOURCE0_WORD1] = rbuffer->bo->size - offset; + vs_resource->states[R600_PS_RESOURCE__RESOURCE0_WORD1] = rbuffer->bo->size - offset - 1; vs_resource->states[R600_PS_RESOURCE__RESOURCE0_WORD2] = S_038008_STRIDE(vertex_buffer->stride) | S_038008_DATA_FORMAT(format); vs_resource->states[R600_PS_RESOURCE__RESOURCE0_WORD3] = 0x00000000; @@ -116,59 +117,61 @@ static int r600_draw_common(struct r600_draw *draw) vs_resource->states[R600_PS_RESOURCE__RESOURCE0_WORD6] = 0xC0000000; vs_resource->placement[0] = RADEON_GEM_DOMAIN_GTT; vs_resource->placement[1] = RADEON_GEM_DOMAIN_GTT; - r = radeon_draw_set_new(rctx->draw, vs_resource); - if (r) + r = radeon_state_pm4(vs_resource); + if (r) { return r; + } + radeon_draw_bind(&rctx->draw, vs_resource); } + rctx->vs_nresource = rctx->vertex_elements->count; /* FIXME start need to change winsys */ - draw->draw = radeon_state(rscreen->rw, R600_DRAW_TYPE, R600_DRAW); - if (draw->draw == NULL) - return -ENOMEM; - draw->draw->states[R600_DRAW__VGT_NUM_INDICES] = draw->count; - draw->draw->states[R600_DRAW__VGT_DRAW_INITIATOR] = vgt_draw_initiator; + radeon_state_init(&draw->draw, rscreen->rw, R600_STATE_DRAW, 0, 0); + draw->draw.states[R600_DRAW__VGT_NUM_INDICES] = draw->count; + draw->draw.states[R600_DRAW__VGT_DRAW_INITIATOR] = vgt_draw_initiator; if (draw->index_buffer) { rbuffer = (struct r600_resource*)draw->index_buffer; - draw->draw->bo[0] = radeon_bo_incref(rscreen->rw, rbuffer->bo); - draw->draw->placement[0] = RADEON_GEM_DOMAIN_GTT; - draw->draw->placement[1] = RADEON_GEM_DOMAIN_GTT; - draw->draw->nbo = 1; + draw->draw.bo[0] = radeon_bo_incref(rscreen->rw, rbuffer->bo); + draw->draw.placement[0] = RADEON_GEM_DOMAIN_GTT; + draw->draw.placement[1] = RADEON_GEM_DOMAIN_GTT; + draw->draw.nbo = 1; } - r = radeon_draw_set_new(rctx->draw, draw->draw); - if (r) + r = radeon_state_pm4(&draw->draw); + if (r) { return r; - draw->vgt = radeon_state(rscreen->rw, R600_VGT_TYPE, R600_VGT); - if (draw->vgt == NULL) - return -ENOMEM; - draw->vgt->states[R600_VGT__VGT_PRIMITIVE_TYPE] = prim; - draw->vgt->states[R600_VGT__VGT_MAX_VTX_INDX] = 0x00FFFFFF; - draw->vgt->states[R600_VGT__VGT_MIN_VTX_INDX] = 0x00000000; - draw->vgt->states[R600_VGT__VGT_INDX_OFFSET] = draw->start; - draw->vgt->states[R600_VGT__VGT_MULTI_PRIM_IB_RESET_INDX] = 0x00000000; - draw->vgt->states[R600_VGT__VGT_DMA_INDEX_TYPE] = vgt_dma_index_type; - draw->vgt->states[R600_VGT__VGT_PRIMITIVEID_EN] = 0x00000000; - draw->vgt->states[R600_VGT__VGT_DMA_NUM_INSTANCES] = 0x00000001; - draw->vgt->states[R600_VGT__VGT_MULTI_PRIM_IB_RESET_EN] = 0x00000000; - draw->vgt->states[R600_VGT__VGT_INSTANCE_STEP_RATE_0] = 0x00000000; - draw->vgt->states[R600_VGT__VGT_INSTANCE_STEP_RATE_1] = 0x00000000; - r = radeon_draw_set_new(rctx->draw, draw->vgt); - if (r) + } + radeon_draw_bind(&rctx->draw, &draw->draw); + + radeon_state_init(&draw->vgt, rscreen->rw, R600_STATE_VGT, 0, 0); + draw->vgt.states[R600_VGT__VGT_PRIMITIVE_TYPE] = prim; + draw->vgt.states[R600_VGT__VGT_MAX_VTX_INDX] = 0x00FFFFFF; + draw->vgt.states[R600_VGT__VGT_MIN_VTX_INDX] = 0x00000000; + draw->vgt.states[R600_VGT__VGT_INDX_OFFSET] = draw->start; + draw->vgt.states[R600_VGT__VGT_MULTI_PRIM_IB_RESET_INDX] = 0x00000000; + draw->vgt.states[R600_VGT__VGT_DMA_INDEX_TYPE] = vgt_dma_index_type; + draw->vgt.states[R600_VGT__VGT_PRIMITIVEID_EN] = 0x00000000; + draw->vgt.states[R600_VGT__VGT_DMA_NUM_INSTANCES] = 0x00000001; + draw->vgt.states[R600_VGT__VGT_MULTI_PRIM_IB_RESET_EN] = 0x00000000; + draw->vgt.states[R600_VGT__VGT_INSTANCE_STEP_RATE_0] = 0x00000000; + draw->vgt.states[R600_VGT__VGT_INSTANCE_STEP_RATE_1] = 0x00000000; + r = radeon_state_pm4(&draw->vgt); + if (r) { return r; - /* FIXME */ - r = radeon_ctx_set_draw_new(rctx->ctx, rctx->draw); + } + radeon_draw_bind(&rctx->draw, &draw->vgt); + + r = radeon_ctx_set_draw(&rctx->ctx, &rctx->draw); if (r == -EBUSY) { r600_flush(draw->ctx, 0, NULL); - r = radeon_ctx_set_draw_new(rctx->ctx, rctx->draw); + r = radeon_ctx_set_draw(&rctx->ctx, &rctx->draw); } - if (r) - return r; - rctx->draw = radeon_draw_duplicate(rctx->draw); - return 0; + return r; } void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) { struct r600_context *rctx = r600_context(ctx); struct r600_draw draw; + int r; assert(info->index_bias == 0); @@ -189,5 +192,7 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) draw.index_size = 0; draw.index_buffer = NULL; } - r600_draw_common(&draw); + r = r600_draw_common(&draw); + if (r) + fprintf(stderr,"draw common failed %d\n", r); } diff --git a/src/gallium/drivers/r600/r600_query.c b/src/gallium/drivers/r600/r600_query.c index 9b02ae680e..530940ed84 100644 --- a/src/gallium/drivers/r600/r600_query.c +++ b/src/gallium/drivers/r600/r600_query.c @@ -24,39 +24,225 @@ * Jerome Glisse * Corbin Simpson */ +#include <errno.h> #include <util/u_inlines.h> #include <util/u_format.h> #include <util/u_memory.h> #include "r600_screen.h" #include "r600_context.h" -static struct pipe_query *r600_create_query(struct pipe_context *pipe, unsigned query_type) +static void r600_query_begin(struct r600_context *rctx, struct r600_query *rquery) { - return NULL; + struct r600_screen *rscreen = rctx->screen; + struct radeon_state *rstate = &rquery->rstate; + + radeon_state_fini(rstate); + radeon_state_init(rstate, rscreen->rw, R600_STATE_QUERY_BEGIN, 0, 0); + rstate->states[R600_QUERY__OFFSET] = rquery->num_results; + rstate->bo[0] = radeon_bo_incref(rscreen->rw, rquery->buffer); + rstate->nbo = 1; + rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + if (radeon_state_pm4(rstate)) { + radeon_state_fini(rstate); + } +} + +static void r600_query_end(struct r600_context *rctx, struct r600_query *rquery) +{ + struct r600_screen *rscreen = rctx->screen; + struct radeon_state *rstate = &rquery->rstate; + + radeon_state_fini(rstate); + radeon_state_init(rstate, rscreen->rw, R600_STATE_QUERY_END, 0, 0); + rstate->states[R600_QUERY__OFFSET] = rquery->num_results + 8; + rstate->bo[0] = radeon_bo_incref(rscreen->rw, rquery->buffer); + rstate->nbo = 1; + rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + if (radeon_state_pm4(rstate)) { + radeon_state_fini(rstate); + } } -static void r600_destroy_query(struct pipe_context *pipe, struct pipe_query *query) +static struct pipe_query *r600_create_query(struct pipe_context *ctx, unsigned query_type) { + struct r600_screen *rscreen = r600_screen(ctx->screen); + struct r600_context *rctx = r600_context(ctx); + struct r600_query *q; + + if (query_type != PIPE_QUERY_OCCLUSION_COUNTER) + return NULL; + + q = CALLOC_STRUCT(r600_query); + if (!q) + return NULL; + + q->type = query_type; + LIST_ADDTAIL(&q->list, &rctx->query_list); + q->buffer_size = 4096; + + q->buffer = radeon_bo(rscreen->rw, 0, q->buffer_size, 1, NULL); + if (!q->buffer) { + FREE(q); + return NULL; + } + return (struct pipe_query *)q; +} + +static void r600_destroy_query(struct pipe_context *ctx, + struct pipe_query *query) +{ + struct r600_screen *rscreen = r600_screen(ctx->screen); + struct r600_query *q = r600_query(query); + + radeon_bo_decref(rscreen->rw, q->buffer); + LIST_DEL(&q->list); FREE(query); } -static void r600_begin_query(struct pipe_context *pipe, struct pipe_query *query) +static void r600_query_result(struct pipe_context *ctx, struct r600_query *rquery) { + struct r600_screen *rscreen = r600_screen(ctx->screen); + u64 start, end; + u32 *results; + int i; + + radeon_bo_wait(rscreen->rw, rquery->buffer); + radeon_bo_map(rscreen->rw, rquery->buffer); + results = rquery->buffer->data; + for (i = 0; i < rquery->num_results; i += 4) { + start = (u64)results[i] | (u64)results[i + 1] << 32; + end = (u64)results[i + 2] | (u64)results[i + 3] << 32; + if ((start & 0x8000000000000000UL) && (end & 0x8000000000000000UL)) { + rquery->result += end - start; + } + } + radeon_bo_unmap(rscreen->rw, rquery->buffer); + rquery->num_results = 0; } -static void r600_end_query(struct pipe_context *pipe, struct pipe_query *query) +static void r600_query_resume(struct pipe_context *ctx, struct r600_query *rquery) { + struct r600_context *rctx = r600_context(ctx); + + if (rquery->num_results >= ((rquery->buffer_size >> 2) - 2)) { + /* running out of space */ + if (!rquery->flushed) { + ctx->flush(ctx, 0, NULL); + } + r600_query_result(ctx, rquery); + } + r600_query_begin(rctx, rquery); + rquery->flushed = false; +} + +static void r600_query_suspend(struct pipe_context *ctx, struct r600_query *rquery) +{ + struct r600_context *rctx = r600_context(ctx); + + r600_query_end(rctx, rquery); + rquery->num_results += 16; } -static boolean r600_get_query_result(struct pipe_context *pipe, +static void r600_begin_query(struct pipe_context *ctx, struct pipe_query *query) +{ + struct r600_context *rctx = r600_context(ctx); + struct r600_query *rquery = r600_query(query); + int r; + + rquery->state = R600_QUERY_STATE_STARTED; + rquery->num_results = 0; + rquery->flushed = false; + r600_query_resume(ctx, rquery); + r = radeon_ctx_set_query_state(&rctx->ctx, &rquery->rstate); + if (r == -EBUSY) { + /* this shouldn't happen */ + R600_ERR("had to flush while emitting end query\n"); + ctx->flush(ctx, 0, NULL); + r = radeon_ctx_set_query_state(&rctx->ctx, &rquery->rstate); + } +} + +static void r600_end_query(struct pipe_context *ctx, struct pipe_query *query) +{ + struct r600_context *rctx = r600_context(ctx); + struct r600_query *rquery = r600_query(query); + int r; + + rquery->state &= ~R600_QUERY_STATE_STARTED; + rquery->state |= R600_QUERY_STATE_ENDED; + r600_query_suspend(ctx, rquery); + r = radeon_ctx_set_query_state(&rctx->ctx, &rquery->rstate); + if (r == -EBUSY) { + /* this shouldn't happen */ + R600_ERR("had to flush while emitting end query\n"); + ctx->flush(ctx, 0, NULL); + r = radeon_ctx_set_query_state(&rctx->ctx, &rquery->rstate); + } +} + +void r600_queries_suspend(struct pipe_context *ctx) +{ + struct r600_context *rctx = r600_context(ctx); + struct r600_query *rquery; + int r; + + LIST_FOR_EACH_ENTRY(rquery, &rctx->query_list, list) { + if (rquery->state & R600_QUERY_STATE_STARTED) { + r600_query_suspend(ctx, rquery); + r = radeon_ctx_set_query_state(&rctx->ctx, &rquery->rstate); + if (r == -EBUSY) { + /* this shouldn't happen */ + R600_ERR("had to flush while emitting end query\n"); + ctx->flush(ctx, 0, NULL); + r = radeon_ctx_set_query_state(&rctx->ctx, &rquery->rstate); + } + } + rquery->state |= R600_QUERY_STATE_SUSPENDED; + } +} + +void r600_queries_resume(struct pipe_context *ctx) +{ + struct r600_context *rctx = r600_context(ctx); + struct r600_query *rquery; + int r; + + LIST_FOR_EACH_ENTRY(rquery, &rctx->query_list, list) { + if (rquery->state & R600_QUERY_STATE_STARTED) { + r600_query_resume(ctx, rquery); + r = radeon_ctx_set_query_state(&rctx->ctx, &rquery->rstate); + if (r == -EBUSY) { + /* this shouldn't happen */ + R600_ERR("had to flush while emitting end query\n"); + ctx->flush(ctx, 0, NULL); + r = radeon_ctx_set_query_state(&rctx->ctx, &rquery->rstate); + } + } + rquery->state &= ~R600_QUERY_STATE_SUSPENDED; + } +} + +static boolean r600_get_query_result(struct pipe_context *ctx, struct pipe_query *query, - boolean wait, void *result) + boolean wait, void *vresult) { + struct r600_query *rquery = r600_query(query); + uint64_t *result = (uint64_t*)vresult; + + if (!rquery->flushed) { + ctx->flush(ctx, 0, NULL); + rquery->flushed = true; + } + r600_query_result(ctx, rquery); + *result = rquery->result; + rquery->result = 0; return TRUE; } void r600_init_query_functions(struct r600_context* rctx) { + LIST_INITHEAD(&rctx->query_list); + rctx->context.create_query = r600_create_query; rctx->context.destroy_query = r600_destroy_query; rctx->context.begin_query = r600_begin_query; diff --git a/src/gallium/drivers/r600/r600_resource.h b/src/gallium/drivers/r600/r600_resource.h index bb90e76fb7..129667ad20 100644 --- a/src/gallium/drivers/r600/r600_resource.h +++ b/src/gallium/drivers/r600/r600_resource.h @@ -44,10 +44,22 @@ struct r600_resource_texture { struct r600_resource resource; unsigned long offset[PIPE_MAX_TEXTURE_LEVELS]; unsigned long pitch[PIPE_MAX_TEXTURE_LEVELS]; + unsigned long width[PIPE_MAX_TEXTURE_LEVELS]; + unsigned long height[PIPE_MAX_TEXTURE_LEVELS]; unsigned long layer_size[PIPE_MAX_TEXTURE_LEVELS]; unsigned long pitch_override; unsigned long bpt; unsigned long size; + unsigned tilled; + unsigned array_mode; + unsigned tile_type; + unsigned depth; + unsigned dirty; + struct radeon_bo *uncompressed; + struct radeon_state scissor[PIPE_MAX_TEXTURE_LEVELS]; + struct radeon_state cb[8][PIPE_MAX_TEXTURE_LEVELS]; + struct radeon_state db[PIPE_MAX_TEXTURE_LEVELS]; + struct radeon_state viewport[PIPE_MAX_TEXTURE_LEVELS]; }; void r600_init_context_resource_functions(struct r600_context *r600); diff --git a/src/gallium/drivers/r600/r600_screen.c b/src/gallium/drivers/r600/r600_screen.c index cdaca9ed7d..a047a49a6c 100644 --- a/src/gallium/drivers/r600/r600_screen.c +++ b/src/gallium/drivers/r600/r600_screen.c @@ -69,6 +69,7 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param) case PIPE_CAP_TEXTURE_SWIZZLE: case PIPE_CAP_INDEP_BLEND_ENABLE: case PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE: + case PIPE_CAP_DEPTH_CLAMP: return 1; /* Unsupported features (boolean caps). */ @@ -77,7 +78,6 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param) case PIPE_CAP_STREAM_OUTPUT: case PIPE_CAP_INDEP_BLEND_FUNC: /* FIXME allow this */ case PIPE_CAP_GEOMETRY_SHADER4: - case PIPE_CAP_DEPTH_CLAMP: /* FIXME allow this */ return 0; /* Texturing. */ @@ -234,11 +234,34 @@ static void r600_destroy_screen(struct pipe_screen* pscreen) struct pipe_screen *r600_screen_create(struct radeon *rw) { struct r600_screen* rscreen; + enum radeon_family family = radeon_get_family(rw); rscreen = CALLOC_STRUCT(r600_screen); if (rscreen == NULL) { return NULL; } + + switch (family) { + case CHIP_R600: + case CHIP_RV610: + case CHIP_RV630: + case CHIP_RV670: + case CHIP_RV620: + case CHIP_RV635: + case CHIP_RS780: + case CHIP_RS880: + rscreen->chip_class = R600; + break; + case CHIP_RV770: + case CHIP_RV730: + case CHIP_RV710: + case CHIP_RV740: + rscreen->chip_class = R700; + break; + default: + FREE(rscreen); + return NULL; + } rscreen->rw = rw; rscreen->screen.winsys = (struct pipe_winsys*)rw; rscreen->screen.destroy = r600_destroy_screen; diff --git a/src/gallium/drivers/r600/r600_screen.h b/src/gallium/drivers/r600/r600_screen.h index 53b560c617..b9938f117a 100644 --- a/src/gallium/drivers/r600/r600_screen.h +++ b/src/gallium/drivers/r600/r600_screen.h @@ -30,6 +30,7 @@ #include <radeon_drm.h> #include "radeon.h" #include "util/u_transfer.h" +#include "r600_resource.h" /* Texture transfer. */ struct r600_transfer { @@ -38,11 +39,19 @@ struct r600_transfer { /* Buffer transfer. */ struct pipe_transfer *buffer_transfer; unsigned offset; + struct pipe_resource *linear_texture; +}; + +enum chip_class { + R600, + R700, + EVERGREEN, }; struct r600_screen { struct pipe_screen screen; struct radeon *rw; + enum chip_class chip_class; }; static INLINE struct r600_screen *r600_screen(struct pipe_screen *screen) @@ -62,7 +71,7 @@ unsigned r600_buffer_is_referenced_by_cs(struct pipe_context *context, struct pipe_resource *r600_buffer_from_handle(struct pipe_screen *screen, struct winsys_handle *whandle); -/* Texture transfer functions. */ +/* r600_texture.c texture transfer functions. */ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, struct pipe_resource *texture, struct pipe_subresource sr, @@ -74,7 +83,14 @@ void* r600_texture_transfer_map(struct pipe_context *ctx, struct pipe_transfer* transfer); void r600_texture_transfer_unmap(struct pipe_context *ctx, struct pipe_transfer* transfer); +int r600_texture_scissor(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level); +int r600_texture_cb(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned cb, unsigned level); +int r600_texture_db(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level); +int r600_texture_from_depth(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level); +int r600_texture_viewport(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level); +/* r600_blit.c */ +int r600_blit_uncompress_depth(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level); /* helpers */ int r600_conv_pipe_format(unsigned pformat, unsigned *format); diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c index 956c7e7930..0ba26a2311 100644 --- a/src/gallium/drivers/r600/r600_shader.c +++ b/src/gallium/drivers/r600/r600_shader.c @@ -48,6 +48,9 @@ struct r600_shader_ctx { struct r600_bc *bc; struct r600_shader *shader; u32 value[4]; + u32 *literals; + u32 nliterals; + u32 max_driver_temp_used; }; struct r600_shader_tgsi_instruction { @@ -105,8 +108,8 @@ int r600_pipe_shader_create(struct pipe_context *ctx, struct r600_screen *rscreen = r600_screen(ctx->screen); int r; -fprintf(stderr, "--------------------------------------------------------------\n"); -tgsi_dump(tokens, 0); +//fprintf(stderr, "--------------------------------------------------------------\n"); +//tgsi_dump(tokens, 0); if (rpshader == NULL) return -ENOMEM; rpshader->shader.family = radeon_get_family(rscreen->rw); @@ -120,7 +123,7 @@ tgsi_dump(tokens, 0); R600_ERR("building bytecode failed !\n"); return r; } -fprintf(stderr, "______________________________________________________________\n"); +//fprintf(stderr, "______________________________________________________________\n"); return 0; } @@ -131,10 +134,9 @@ static int r600_pipe_shader_vs(struct pipe_context *ctx, struct r600_context_sta struct radeon_state *state; unsigned i, tmp; - rpshader->rstate = radeon_state_decref(rpshader->rstate); - state = radeon_state(rscreen->rw, R600_VS_SHADER_TYPE, R600_VS_SHADER); - if (state == NULL) - return -ENOMEM; + state = &rpshader->rstate[0]; + radeon_state_fini(&rpshader->rstate[0]); + radeon_state_init(state, rscreen->rw, R600_STATE_SHADER, 0, R600_SHADER_VS); for (i = 0; i < 10; i++) { state->states[R600_VS_SHADER__SPI_VS_OUT_ID_0 + i] = 0; } @@ -144,12 +146,13 @@ static int r600_pipe_shader_vs(struct pipe_context *ctx, struct r600_context_sta state->states[R600_VS_SHADER__SPI_VS_OUT_ID_0 + i / 4] |= tmp; } state->states[R600_VS_SHADER__SPI_VS_OUT_CONFIG] = S_0286C4_VS_EXPORT_COUNT(rshader->noutput - 2); - state->states[R600_VS_SHADER__SQ_PGM_RESOURCES_VS] = S_028868_NUM_GPRS(rshader->bc.ngpr); - rpshader->rstate = state; - rpshader->rstate->bo[0] = radeon_bo_incref(rscreen->rw, rpshader->bo); - rpshader->rstate->bo[1] = radeon_bo_incref(rscreen->rw, rpshader->bo); - rpshader->rstate->nbo = 2; - rpshader->rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + state->states[R600_VS_SHADER__SQ_PGM_RESOURCES_VS] = S_028868_NUM_GPRS(rshader->bc.ngpr) | + S_028868_STACK_SIZE(rshader->bc.nstack); + state->bo[0] = radeon_bo_incref(rscreen->rw, rpshader->bo); + state->bo[1] = radeon_bo_incref(rscreen->rw, rpshader->bo); + state->nbo = 2; + state->placement[0] = RADEON_GEM_DOMAIN_GTT; + state->placement[2] = RADEON_GEM_DOMAIN_GTT; return radeon_state_pm4(state); } @@ -161,17 +164,20 @@ static int r600_pipe_shader_ps(struct pipe_context *ctx, struct r600_context_sta struct r600_context *rctx = r600_context(ctx); struct radeon_state *state; unsigned i, tmp, exports_ps, num_cout; + boolean have_pos = FALSE; + state = &rpshader->rstate[0]; rasterizer = &rctx->rasterizer->state.rasterizer; - rpshader->rstate = radeon_state_decref(rpshader->rstate); - state = radeon_state(rscreen->rw, R600_PS_SHADER_TYPE, R600_PS_SHADER); - if (state == NULL) - return -ENOMEM; + radeon_state_fini(state); + radeon_state_init(state, rscreen->rw, R600_STATE_SHADER, 0, R600_SHADER_PS); for (i = 0; i < rshader->ninput; i++) { tmp = S_028644_SEMANTIC(i); tmp |= S_028644_SEL_CENTROID(1); + if (rshader->input[i].name == TGSI_SEMANTIC_POSITION) + have_pos = TRUE; if (rshader->input[i].name == TGSI_SEMANTIC_COLOR || - rshader->input[i].name == TGSI_SEMANTIC_BCOLOR) { + rshader->input[i].name == TGSI_SEMANTIC_BCOLOR || + rshader->input[i].name == TGSI_SEMANTIC_POSITION) { tmp |= S_028644_FLAT_SHADE(rshader->flat_shade); } if (rasterizer->sprite_coord_enable & (1 << i)) { @@ -190,15 +196,24 @@ static int r600_pipe_shader_ps(struct pipe_context *ctx, struct r600_context_sta num_cout++; } } + if (!exports_ps) { + /* always at least export 1 component per pixel */ + exports_ps = 2; + } state->states[R600_PS_SHADER__SPI_PS_IN_CONTROL_0] = S_0286CC_NUM_INTERP(rshader->ninput) | S_0286CC_PERSP_GRADIENT_ENA(1); + if (have_pos) { + state->states[R600_PS_SHADER__SPI_PS_IN_CONTROL_0] |= S_0286CC_POSITION_ENA(1) | + S_0286CC_BARYC_SAMPLE_CNTL(1); + state->states[R600_PS_SHADER__SPI_INPUT_Z] |= 1; + } state->states[R600_PS_SHADER__SPI_PS_IN_CONTROL_1] = 0x00000000; - state->states[R600_PS_SHADER__SQ_PGM_RESOURCES_PS] = S_028868_NUM_GPRS(rshader->bc.ngpr); + state->states[R600_PS_SHADER__SQ_PGM_RESOURCES_PS] = S_028868_NUM_GPRS(rshader->bc.ngpr) | + S_028868_STACK_SIZE(rshader->bc.nstack); state->states[R600_PS_SHADER__SQ_PGM_EXPORTS_PS] = exports_ps; - rpshader->rstate = state; - rpshader->rstate->bo[0] = radeon_bo_incref(rscreen->rw, rpshader->bo); - rpshader->rstate->nbo = 1; - rpshader->rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + state->bo[0] = radeon_bo_incref(rscreen->rw, rpshader->bo); + state->nbo = 1; + state->placement[0] = RADEON_GEM_DOMAIN_GTT; return radeon_state_pm4(state); } @@ -268,21 +283,24 @@ static int tgsi_is_supported(struct r600_shader_ctx *ctx) R600_ERR("predicate unsupported\n"); return -EINVAL; } +#if 0 if (i->Instruction.Label) { R600_ERR("label unsupported\n"); return -EINVAL; } +#endif for (j = 0; j < i->Instruction.NumSrcRegs; j++) { - if (i->Src[j].Register.Indirect || - i->Src[j].Register.Dimension || + if (i->Src[j].Register.Dimension || i->Src[j].Register.Absolute) { - R600_ERR("unsupported src (indirect|dimension|absolute)\n"); + R600_ERR("unsupported src %d (dimension %d|absolute %d)\n", j, + i->Src[j].Register.Dimension, + i->Src[j].Register.Absolute); return -EINVAL; } } for (j = 0; j < i->Instruction.NumDstRegs; j++) { - if (i->Dst[j].Register.Indirect || i->Dst[j].Register.Dimension) { - R600_ERR("unsupported dst (indirect|dimension)\n"); + if (i->Dst[j].Register.Dimension) { + R600_ERR("unsupported dst (dimension)\n"); return -EINVAL; } } @@ -333,6 +351,7 @@ static int tgsi_declaration(struct r600_shader_ctx *ctx) case TGSI_FILE_CONSTANT: case TGSI_FILE_TEMPORARY: case TGSI_FILE_SAMPLER: + case TGSI_FILE_ADDRESS: break; default: R600_ERR("unsupported file %d declaration\n", d->Declaration.File); @@ -341,6 +360,11 @@ static int tgsi_declaration(struct r600_shader_ctx *ctx) return 0; } +static int r600_get_temp(struct r600_shader_ctx *ctx) +{ + return ctx->temp_reg + ctx->max_driver_temp_used++; +} + int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *shader) { struct tgsi_full_immediate *immediate; @@ -362,9 +386,15 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s shader->processor_type = ctx.type; /* register allocations */ - /* Values [0,127] correspond to GPR[0..127]. - * Values [256,511] correspond to cfile constants c[0..255]. + /* Values [0,127] correspond to GPR[0..127]. + * Values [128,159] correspond to constant buffer bank 0 + * Values [160,191] correspond to constant buffer bank 1 + * Values [256,511] correspond to cfile constants c[0..255]. * Other special values are shown in the list below. + * 244 ALU_SRC_1_DBL_L: special constant 1.0 double-float, LSW. (RV670+) + * 245 ALU_SRC_1_DBL_M: special constant 1.0 double-float, MSW. (RV670+) + * 246 ALU_SRC_0_5_DBL_L: special constant 0.5 double-float, LSW. (RV670+) + * 247 ALU_SRC_0_5_DBL_M: special constant 0.5 double-float, MSW. (RV670+) * 248 SQ_ALU_SRC_0: special constant 0.0. * 249 SQ_ALU_SRC_1: special constant 1.0 float. * 250 SQ_ALU_SRC_1_INT: special constant 1 integer. @@ -389,15 +419,24 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s ctx.temp_reg = ctx.file_offset[TGSI_FILE_TEMPORARY] + ctx.info.file_count[TGSI_FILE_TEMPORARY]; + ctx.nliterals = 0; + ctx.literals = NULL; + while (!tgsi_parse_end_of_tokens(&ctx.parse)) { tgsi_parse_token(&ctx.parse); switch (ctx.parse.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_IMMEDIATE: immediate = &ctx.parse.FullToken.FullImmediate; - ctx.value[0] = immediate->u[0].Uint; - ctx.value[1] = immediate->u[1].Uint; - ctx.value[2] = immediate->u[2].Uint; - ctx.value[3] = immediate->u[3].Uint; + ctx.literals = realloc(ctx.literals, (ctx.nliterals + 1) * 16); + if(ctx.literals == NULL) { + r = -ENOMEM; + goto out_err; + } + ctx.literals[ctx.nliterals * 4 + 0] = immediate->u[0].Uint; + ctx.literals[ctx.nliterals * 4 + 1] = immediate->u[1].Uint; + ctx.literals[ctx.nliterals * 4 + 2] = immediate->u[2].Uint; + ctx.literals[ctx.nliterals * 4 + 3] = immediate->u[3].Uint; + ctx.nliterals++; break; case TGSI_TOKEN_TYPE_DECLARATION: r = tgsi_declaration(&ctx); @@ -408,6 +447,9 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s r = tgsi_is_supported(&ctx); if (r) goto out_err; + ctx.max_driver_temp_used = 0; + /* reserve first tmp for everyone */ + r600_get_temp(&ctx); opcode = ctx.parse.FullToken.FullInstruction.Instruction.Opcode; ctx.inst_info = &r600_shader_tgsi_instruction[opcode]; r = ctx.inst_info->process(&ctx); @@ -458,6 +500,8 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; } else if (shader->output[i].name == TGSI_SEMANTIC_POSITION) { output[i].array_base = 61; + output[i].swizzle_x = 2; + output[i].swizzle_y = output[i].swizzle_z = output[i].swizzle_w = 7; output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; } else { R600_ERR("unsupported fragment output name %d\n", shader->output[i].name); @@ -504,7 +548,7 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s output[0].swizzle_z = 7; output[0].swizzle_w = 7; output[0].barrier = 1; - output[0].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PARAM; + output[0].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; output[0].array_base = 0; output[0].inst = V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT; noutput++; @@ -525,9 +569,11 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s if (r) goto out_err; } + free(ctx.literals); tgsi_parse_free(&ctx.parse); return 0; out_err: + free(ctx.literals); tgsi_parse_free(&ctx.parse); return r; } @@ -547,11 +593,19 @@ static int tgsi_src(struct r600_shader_ctx *ctx, const struct tgsi_full_src_register *tgsi_src, struct r600_bc_alu_src *r600_src) { + int index; memset(r600_src, 0, sizeof(struct r600_bc_alu_src)); r600_src->sel = tgsi_src->Register.Index; if (tgsi_src->Register.File == TGSI_FILE_IMMEDIATE) { r600_src->sel = 0; + index = tgsi_src->Register.Index; + ctx->value[0] = ctx->literals[index * 4 + 0]; + ctx->value[1] = ctx->literals[index * 4 + 1]; + ctx->value[2] = ctx->literals[index * 4 + 2]; + ctx->value[3] = ctx->literals[index * 4 + 3]; } + if (tgsi_src->Register.Indirect) + r600_src->rel = V_SQ_REL_RELATIVE; r600_src->neg = tgsi_src->Register.Negate; r600_src->sel += ctx->file_offset[tgsi_src->Register.File]; return 0; @@ -568,6 +622,8 @@ static int tgsi_dst(struct r600_shader_ctx *ctx, r600_dst->sel += ctx->file_offset[tgsi_dst->Register.File]; r600_dst->chan = swizzle; r600_dst->write = 1; + if (tgsi_dst->Register.Indirect) + r600_dst->rel = V_SQ_REL_RELATIVE; if (inst->Instruction.Saturate) { r600_dst->clamp = 1; } @@ -607,12 +663,13 @@ static int tgsi_split_constant(struct r600_shader_ctx *ctx, struct r600_bc_alu_s } for (i = 0, j = nconst - 1; i < inst->Instruction.NumSrcRegs; i++) { if (inst->Src[j].Register.File == TGSI_FILE_CONSTANT && j > 0) { + int treg = r600_get_temp(ctx); for (k = 0; k < 4; k++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; - alu.src[0].sel = r600_src[0].sel; + alu.src[0].sel = r600_src[j].sel; alu.src[0].chan = k; - alu.dst.sel = ctx->temp_reg + j; + alu.dst.sel = treg; alu.dst.chan = k; alu.dst.write = 1; if (k == 3) @@ -621,37 +678,90 @@ static int tgsi_split_constant(struct r600_shader_ctx *ctx, struct r600_bc_alu_s if (r) return r; } - r600_src[0].sel = ctx->temp_reg + j; + r600_src[j].sel = treg; j--; } } return 0; } -static int tgsi_op2(struct r600_shader_ctx *ctx) +/* need to move any immediate into a temp - for trig functions which use literal for PI stuff */ +static int tgsi_split_literal_constant(struct r600_shader_ctx *ctx, struct r600_bc_alu_src r600_src[3]) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu alu; + int i, j, k, nliteral, r; + + for (i = 0, nliteral = 0; i < inst->Instruction.NumSrcRegs; i++) { + if (inst->Src[i].Register.File == TGSI_FILE_IMMEDIATE) { + nliteral++; + } + } + for (i = 0, j = 0; i < inst->Instruction.NumSrcRegs; i++) { + if (inst->Src[j].Register.File == TGSI_FILE_IMMEDIATE) { + int treg = r600_get_temp(ctx); + for (k = 0; k < 4; k++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; + alu.src[0].sel = r600_src[j].sel; + alu.src[0].chan = k; + alu.dst.sel = treg; + alu.dst.chan = k; + alu.dst.write = 1; + if (k == 3) + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + r600_src[j].sel = treg; + j++; + } + } + return 0; +} + +static int tgsi_op2_s(struct r600_shader_ctx *ctx, int swap) { struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; struct r600_bc_alu_src r600_src[3]; struct r600_bc_alu alu; int i, j, r; + int lasti = 0; + + for (i = 0; i < 4; i++) { + if (inst->Dst[0].Register.WriteMask & (1 << i)) { + lasti = i; + } + } r = tgsi_split_constant(ctx, r600_src); if (r) return r; - for (i = 0; i < 4; i++) { + for (i = 0; i < lasti + 1; i++) { + if (!(inst->Dst[0].Register.WriteMask & (1 << i))) + continue; + memset(&alu, 0, sizeof(struct r600_bc_alu)); - if (!(inst->Dst[0].Register.WriteMask & (1 << i))) { - alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP; - alu.dst.chan = i; - } else { - alu.inst = ctx->inst_info->r600_opcode; + r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); + if (r) + return r; + + alu.inst = ctx->inst_info->r600_opcode; + if (!swap) { for (j = 0; j < inst->Instruction.NumSrcRegs; j++) { alu.src[j] = r600_src[j]; alu.src[j].chan = tgsi_chan(&inst->Src[j], i); } - r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); - if (r) - return r; + } else { + alu.src[0] = r600_src[1]; + alu.src[0].chan = tgsi_chan(&inst->Src[1], i); + + alu.src[1] = r600_src[0]; + alu.src[1].chan = tgsi_chan(&inst->Src[0], i); } /* handle some special cases */ switch (ctx->inst_info->tgsi_opcode) { @@ -664,7 +774,7 @@ static int tgsi_op2(struct r600_shader_ctx *ctx) default: break; } - if (i == 3) { + if (i == lasti) { alu.last = 1; } r = r600_bc_add_alu(ctx->bc, &alu); @@ -674,24 +784,154 @@ static int tgsi_op2(struct r600_shader_ctx *ctx) return 0; } -static int tgsi_kill(struct r600_shader_ctx *ctx) +static int tgsi_op2(struct r600_shader_ctx *ctx) +{ + return tgsi_op2_s(ctx, 0); +} + +static int tgsi_op2_swap(struct r600_shader_ctx *ctx) +{ + return tgsi_op2_s(ctx, 1); +} + +/* + * r600 - trunc to -PI..PI range + * r700 - normalize by dividing by 2PI + * see fdo bug 27901 + */ +static int tgsi_setup_trig(struct r600_shader_ctx *ctx, + struct r600_bc_alu_src r600_src[3]) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + int r; + uint32_t lit_vals[4]; + struct r600_bc_alu alu; + + memset(lit_vals, 0, 4*4); + r = tgsi_split_constant(ctx, r600_src); + if (r) + return r; + + r = tgsi_split_literal_constant(ctx, r600_src); + if (r) + return r; + + lit_vals[0] = fui(1.0 /(3.1415926535 * 2)); + lit_vals[1] = fui(0.5f); + + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MULADD; + alu.is_op3 = 1; + + alu.dst.chan = 0; + alu.dst.sel = ctx->temp_reg; + alu.dst.write = 1; + + alu.src[0] = r600_src[0]; + alu.src[0].chan = tgsi_chan(&inst->Src[0], 0); + + alu.src[1].sel = V_SQ_ALU_SRC_LITERAL; + alu.src[1].chan = 0; + alu.src[2].sel = V_SQ_ALU_SRC_LITERAL; + alu.src[2].chan = 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + r = r600_bc_add_literal(ctx->bc, lit_vals); + if (r) + return r; + + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FRACT; + + alu.dst.chan = 0; + alu.dst.sel = ctx->temp_reg; + alu.dst.write = 1; + + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 0; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + if (ctx->bc->chiprev == 0) { + lit_vals[0] = fui(3.1415926535897f * 2.0f); + lit_vals[1] = fui(-3.1415926535897f); + } else { + lit_vals[0] = fui(1.0f); + lit_vals[1] = fui(-0.5f); + } + + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MULADD; + alu.is_op3 = 1; + + alu.dst.chan = 0; + alu.dst.sel = ctx->temp_reg; + alu.dst.write = 1; + + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 0; + + alu.src[1].sel = V_SQ_ALU_SRC_LITERAL; + alu.src[1].chan = 0; + alu.src[2].sel = V_SQ_ALU_SRC_LITERAL; + alu.src[2].chan = 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + r = r600_bc_add_literal(ctx->bc, lit_vals); + if (r) + return r; + return 0; +} + +static int tgsi_trig(struct r600_shader_ctx *ctx) { struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu_src r600_src[3]; struct r600_bc_alu alu; int i, r; + int lasti = 0; + + r = tgsi_setup_trig(ctx, r600_src); + if (r) + return r; + + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = ctx->inst_info->r600_opcode; + alu.dst.chan = 0; + alu.dst.sel = ctx->temp_reg; + alu.dst.write = 1; + + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 0; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + /* replicate result */ for (i = 0; i < 4; i++) { + if (inst->Dst[0].Register.WriteMask & (1 << i)) + lasti = i; + } + for (i = 0; i < lasti + 1; i++) { + if (!(inst->Dst[0].Register.WriteMask & (1 << i))) + continue; + memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.inst = ctx->inst_info->r600_opcode; - alu.dst.chan = i; - alu.src[0].sel = 248; - r = tgsi_src(ctx, &inst->Src[0], &alu.src[1]); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; + + alu.src[0].sel = ctx->temp_reg; + r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); if (r) return r; - alu.src[1].chan = tgsi_chan(&inst->Src[0], i); - if (i == 3) { + if (i == lasti) alu.last = 1; - } r = r600_bc_add_alu(ctx->bc, &alu); if (r) return r; @@ -699,30 +939,70 @@ static int tgsi_kill(struct r600_shader_ctx *ctx) return 0; } -static int tgsi_slt(struct r600_shader_ctx *ctx) +static int tgsi_scs(struct r600_shader_ctx *ctx) { struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; struct r600_bc_alu_src r600_src[3]; struct r600_bc_alu alu; - int i, r; + int r; - r = tgsi_split_constant(ctx, r600_src); + r = tgsi_setup_trig(ctx, r600_src); + if (r) + return r; + + + /* dst.x = COS */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS; + r = tgsi_dst(ctx, &inst->Dst[0], 0, &alu.dst); if (r) return r; + + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 0; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + /* dst.y = SIN */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SIN; + r = tgsi_dst(ctx, &inst->Dst[0], 1, &alu.dst); + if (r) + return r; + + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 0; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + return 0; +} + +static int tgsi_kill(struct r600_shader_ctx *ctx) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu alu; + int i, r; + for (i = 0; i < 4; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); - if (!(inst->Dst[0].Register.WriteMask & (1 << i))) { - alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP; - alu.dst.chan = i; + alu.inst = ctx->inst_info->r600_opcode; + + alu.dst.chan = i; + + alu.src[0].sel = V_SQ_ALU_SRC_0; + + if (ctx->inst_info->tgsi_opcode == TGSI_OPCODE_KILP) { + alu.src[1].sel = V_SQ_ALU_SRC_1; + alu.src[1].neg = 1; } else { - alu.inst = ctx->inst_info->r600_opcode; - alu.src[1] = r600_src[0]; - alu.src[1].chan = tgsi_chan(&inst->Src[0], i); - alu.src[0] = r600_src[1]; - alu.src[0].chan = tgsi_chan(&inst->Src[1], i); - r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); + r = tgsi_src(ctx, &inst->Src[0], &alu.src[1]); if (r) return r; + alu.src[1].chan = tgsi_chan(&inst->Src[0], i); } if (i == 3) { alu.last = 1; @@ -731,6 +1011,13 @@ static int tgsi_slt(struct r600_shader_ctx *ctx) if (r) return r; } + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + + /* kill must be last in ALU */ + ctx->bc->force_add_cf = 1; + ctx->shader->uses_kill = TRUE; return 0; } @@ -738,12 +1025,20 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) { struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; struct r600_bc_alu alu; + struct r600_bc_alu_src r600_src[3]; int r; + r = tgsi_split_constant(ctx, r600_src); + if (r) + return r; + r = tgsi_split_literal_constant(ctx, r600_src); + if (r) + return r; + /* dst.x, <- 1.0 */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; - alu.src[0].sel = 249; /*1.0*/ + alu.src[0].sel = V_SQ_ALU_SRC_1; /*1.0*/ alu.src[0].chan = 0; r = tgsi_dst(ctx, &inst->Dst[0], 0, &alu.dst); if (r) @@ -756,11 +1051,9 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) /* dst.y = max(src.x, 0.0) */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX; - r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); - if (r) - return r; - alu.src[1].sel = 248; /*0.0*/ - alu.src[1].chan = tgsi_chan(&inst->Src[0], 0); + alu.src[0] = r600_src[0]; + alu.src[1].sel = V_SQ_ALU_SRC_0; /*0.0*/ + alu.src[1].chan = 0; r = tgsi_dst(ctx, &inst->Dst[0], 1, &alu.dst); if (r) return r; @@ -769,18 +1062,10 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) if (r) return r; - /* dst.z = NOP - fill Z slot */ - memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP; - alu.dst.chan = 2; - r = r600_bc_add_alu(ctx->bc, &alu); - if (r) - return r; - /* dst.w, <- 1.0 */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; - alu.src[0].sel = 249; + alu.src[0].sel = V_SQ_ALU_SRC_1; alu.src[0].chan = 0; r = tgsi_dst(ctx, &inst->Dst[0], 3, &alu.dst); if (r) @@ -791,6 +1076,10 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) if (r) return r; + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + if (inst->Dst[0].Register.WriteMask & (1 << 2)) { int chan; @@ -799,9 +1088,7 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) /* dst.z = log(src.y) */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_CLAMPED; - r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); - if (r) - return r; + alu.src[0] = r600_src[0]; alu.src[0].chan = tgsi_chan(&inst->Src[0], 1); r = tgsi_dst(ctx, &inst->Dst[0], 2, &alu.dst); if (r) @@ -811,21 +1098,22 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) if (r) return r; + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + chan = alu.dst.chan; sel = alu.dst.sel; /* tmp.x = amd MUL_LIT(src.w, dst.z, src.x ) */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT; - r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); - if (r) - return r; + alu.src[0] = r600_src[0]; alu.src[0].chan = tgsi_chan(&inst->Src[0], 3); alu.src[1].sel = sel; alu.src[1].chan = chan; - r = tgsi_src(ctx, &inst->Src[0], &alu.src[2]); - if (r) - return r; + + alu.src[2] = r600_src[0]; alu.src[2].chan = tgsi_chan(&inst->Src[0], 0); alu.dst.sel = ctx->temp_reg; alu.dst.chan = 0; @@ -836,6 +1124,9 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) if (r) return r; + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; /* dst.z = exp(tmp.x) */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE; @@ -880,19 +1171,43 @@ static int tgsi_trans(struct r600_shader_ctx *ctx) return 0; } +static int tgsi_helper_tempx_replicate(struct r600_shader_ctx *ctx) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu alu; + int i, r; + + for (i = 0; i < 4; i++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.src[0].sel = ctx->temp_reg; + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; + alu.dst.chan = i; + r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); + if (r) + return r; + alu.dst.write = (inst->Dst[0].Register.WriteMask >> i) & 1; + if (i == 3) + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + return 0; +} + static int tgsi_trans_srcx_replicate(struct r600_shader_ctx *ctx) { struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; struct r600_bc_alu alu; - int i, j, r; + int i, r; memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = ctx->inst_info->r600_opcode; - for (j = 0; j < inst->Instruction.NumSrcRegs; j++) { - r = tgsi_src(ctx, &inst->Src[j], &alu.src[j]); + for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { + r = tgsi_src(ctx, &inst->Src[i], &alu.src[i]); if (r) return r; - alu.src[j].chan = tgsi_chan(&inst->Src[j], 0); + alu.src[i].chan = tgsi_chan(&inst->Src[i], 0); } alu.dst.sel = ctx->temp_reg; alu.dst.write = 1; @@ -900,16 +1215,124 @@ static int tgsi_trans_srcx_replicate(struct r600_shader_ctx *ctx) r = r600_bc_add_alu(ctx->bc, &alu); if (r) return r; + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; /* replicate result */ + return tgsi_helper_tempx_replicate(ctx); +} + +static int tgsi_pow(struct r600_shader_ctx *ctx) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu alu; + int r; + + /* LOG2(a) */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE; + r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); + if (r) + return r; + alu.src[0].chan = tgsi_chan(&inst->Src[0], 0); + alu.dst.sel = ctx->temp_reg; + alu.dst.write = 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + r = r600_bc_add_literal(ctx->bc,ctx->value); + if (r) + return r; + /* b * LOG2(a) */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL_IEEE; + r = tgsi_src(ctx, &inst->Src[1], &alu.src[0]); + if (r) + return r; + alu.src[0].chan = tgsi_chan(&inst->Src[1], 0); + alu.src[1].sel = ctx->temp_reg; + alu.dst.sel = ctx->temp_reg; + alu.dst.write = 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + r = r600_bc_add_literal(ctx->bc,ctx->value); + if (r) + return r; + /* POW(a,b) = EXP2(b * LOG2(a))*/ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE; + alu.src[0].sel = ctx->temp_reg; + alu.dst.sel = ctx->temp_reg; + alu.dst.write = 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + r = r600_bc_add_literal(ctx->bc,ctx->value); + if (r) + return r; + return tgsi_helper_tempx_replicate(ctx); +} + +static int tgsi_ssg(struct r600_shader_ctx *ctx) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu alu; + struct r600_bc_alu_src r600_src[3]; + int i, r; + + r = tgsi_split_constant(ctx, r600_src); + if (r) + return r; + + /* tmp = (src > 0 ? 1 : src) */ for (i = 0; i < 4; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.src[0].sel = ctx->temp_reg; - alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; + alu.inst = V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_CNDGT; + alu.is_op3 = 1; + + alu.dst.sel = ctx->temp_reg; alu.dst.chan = i; + + alu.src[0] = r600_src[0]; + alu.src[0].chan = tgsi_chan(&inst->Src[0], i); + + alu.src[1].sel = V_SQ_ALU_SRC_1; + + alu.src[2] = r600_src[0]; + alu.src[2].chan = tgsi_chan(&inst->Src[0], i); + if (i == 3) + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + + /* dst = (-tmp > 0 ? -1 : tmp) */ + for (i = 0; i < 4; i++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_CNDGT; + alu.is_op3 = 1; r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); if (r) return r; - alu.dst.write = (inst->Dst[0].Register.WriteMask >> i) & 1; + + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = i; + alu.src[0].neg = 1; + + alu.src[1].sel = V_SQ_ALU_SRC_1; + alu.src[1].neg = 1; + + alu.src[2].sel = ctx->temp_reg; + alu.src[2].chan = i; + if (i == 3) alu.last = 1; r = r600_bc_add_alu(ctx->bc, &alu); @@ -1006,16 +1429,23 @@ static int tgsi_dp(struct r600_shader_ctx *ctx) switch (ctx->inst_info->tgsi_opcode) { case TGSI_OPCODE_DP2: if (i > 1) { - alu.src[0].sel = alu.src[1].sel = 248; + alu.src[0].sel = alu.src[1].sel = V_SQ_ALU_SRC_0; alu.src[0].chan = alu.src[1].chan = 0; } break; case TGSI_OPCODE_DP3: if (i > 2) { - alu.src[0].sel = alu.src[1].sel = 248; + alu.src[0].sel = alu.src[1].sel = V_SQ_ALU_SRC_0; alu.src[0].chan = alu.src[1].chan = 0; } break; + case TGSI_OPCODE_DPH: + if (i == 3) { + alu.src[0].sel = V_SQ_ALU_SRC_1; + alu.src[0].chan = 0; + alu.src[0].neg = 0; + } + break; default: break; } @@ -1035,75 +1465,197 @@ static int tgsi_tex(struct r600_shader_ctx *ctx) struct r600_bc_tex tex; struct r600_bc_alu alu; unsigned src_gpr; - int r; + int r, i; + int opcode; + boolean src_not_temp = inst->Src[0].Register.File != TGSI_FILE_TEMPORARY; + uint32_t lit_vals[4]; src_gpr = ctx->file_offset[inst->Src[0].Register.File] + inst->Src[0].Register.Index; - /* Add perspective divide */ - memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE; - alu.src[0].sel = src_gpr; - alu.src[0].chan = tgsi_chan(&inst->Src[0], 3); - alu.dst.sel = ctx->temp_reg; - alu.dst.chan = 3; - alu.last = 1; - alu.dst.write = 1; - r = r600_bc_add_alu(ctx->bc, &alu); - if (r) - return r; + if (inst->Instruction.Opcode == TGSI_OPCODE_TXP) { + /* Add perspective divide */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE; + r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); + if (r) + return r; - memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL; - alu.src[0].sel = ctx->temp_reg; - alu.src[0].chan = 3; - alu.src[1].sel = src_gpr; - alu.src[1].chan = tgsi_chan(&inst->Src[0], 0); - alu.dst.sel = ctx->temp_reg; - alu.dst.chan = 0; - alu.dst.write = 1; - r = r600_bc_add_alu(ctx->bc, &alu); - if (r) - return r; - memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL; - alu.src[0].sel = ctx->temp_reg; - alu.src[0].chan = 3; - alu.src[1].sel = src_gpr; - alu.src[1].chan = tgsi_chan(&inst->Src[0], 1); - alu.dst.sel = ctx->temp_reg; - alu.dst.chan = 1; - alu.dst.write = 1; - r = r600_bc_add_alu(ctx->bc, &alu); - if (r) - return r; - memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL; - alu.src[0].sel = ctx->temp_reg; - alu.src[0].chan = 3; - alu.src[1].sel = src_gpr; - alu.src[1].chan = tgsi_chan(&inst->Src[0], 2); - alu.dst.sel = ctx->temp_reg; - alu.dst.chan = 2; - alu.dst.write = 1; - r = r600_bc_add_alu(ctx->bc, &alu); - if (r) - return r; - memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; - alu.src[0].sel = 249; - alu.src[0].chan = 0; - alu.dst.sel = ctx->temp_reg; - alu.dst.chan = 3; - alu.last = 1; - alu.dst.write = 1; - r = r600_bc_add_alu(ctx->bc, &alu); - if (r) - return r; - src_gpr = ctx->temp_reg; + alu.src[0].chan = tgsi_chan(&inst->Src[0], 3); + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 3; + alu.last = 1; + alu.dst.write = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + for (i = 0; i < 3; i++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL; + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 3; + r = tgsi_src(ctx, &inst->Src[0], &alu.src[1]); + if (r) + return r; + alu.src[1].chan = tgsi_chan(&inst->Src[0], i); + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = i; + alu.dst.write = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; + alu.src[0].sel = V_SQ_ALU_SRC_1; + alu.src[0].chan = 0; + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 3; + alu.last = 1; + alu.dst.write = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + src_not_temp = false; + src_gpr = ctx->temp_reg; + } + + if (inst->Texture.Texture == TGSI_TEXTURE_CUBE) { + int src_chan, src2_chan; + + /* tmp1.xyzw = CUBE(R0.zzxy, R0.yxzz) */ + for (i = 0; i < 4; i++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE; + switch (i) { + case 0: + src_chan = 2; + src2_chan = 1; + break; + case 1: + src_chan = 2; + src2_chan = 0; + break; + case 2: + src_chan = 0; + src2_chan = 2; + break; + case 3: + src_chan = 1; + src2_chan = 2; + break; + } + r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); + if (r) + return r; + alu.src[0].chan = tgsi_chan(&inst->Src[0], src_chan); + r = tgsi_src(ctx, &inst->Src[0], &alu.src[1]); + if (r) + return r; + alu.src[1].chan = tgsi_chan(&inst->Src[0], src2_chan); + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = i; + if (i == 3) + alu.last = 1; + alu.dst.write = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + + /* tmp1.z = RCP_e(|tmp1.z|) */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE; + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 2; + alu.src[0].abs = 1; + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 2; + alu.dst.write = 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + /* MULADD R0.x, R0.x, PS1, (0x3FC00000, 1.5f).x + * MULADD R0.y, R0.y, PS1, (0x3FC00000, 1.5f).x + * muladd has no writemask, have to use another temp + */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MULADD; + alu.is_op3 = 1; + + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 0; + alu.src[1].sel = ctx->temp_reg; + alu.src[1].chan = 2; + + alu.src[2].sel = V_SQ_ALU_SRC_LITERAL; + alu.src[2].chan = 0; + + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 0; + alu.dst.write = 1; + + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MULADD; + alu.is_op3 = 1; + + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 1; + alu.src[1].sel = ctx->temp_reg; + alu.src[1].chan = 2; + + alu.src[2].sel = V_SQ_ALU_SRC_LITERAL; + alu.src[2].chan = 0; + + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 1; + alu.dst.write = 1; + + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + lit_vals[0] = fui(1.5f); + + r = r600_bc_add_literal(ctx->bc, lit_vals); + if (r) + return r; + src_not_temp = false; + src_gpr = ctx->temp_reg; + } + + if (src_not_temp) { + for (i = 0; i < 4; i++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; + alu.src[0].sel = src_gpr; + alu.src[0].chan = i; + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = i; + if (i == 3) + alu.last = 1; + alu.dst.write = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + src_gpr = ctx->temp_reg; + } + + opcode = ctx->inst_info->r600_opcode; + if (opcode == SQ_TEX_INST_SAMPLE && + (inst->Texture.Texture == TGSI_TEXTURE_SHADOW1D || inst->Texture.Texture == TGSI_TEXTURE_SHADOW2D)) + opcode = SQ_TEX_INST_SAMPLE_C; - /* TODO use temp if src_gpr is not a temporary reg (File != TEMPORARY) */ memset(&tex, 0, sizeof(struct r600_bc_tex)); - tex.inst = ctx->inst_info->r600_opcode; + tex.inst = opcode; tex.resource_id = ctx->file_offset[inst->Src[1].Register.File] + inst->Src[1].Register.Index; tex.sampler_id = tex.resource_id; tex.src_gpr = src_gpr; @@ -1117,13 +1669,30 @@ static int tgsi_tex(struct r600_shader_ctx *ctx) tex.src_sel_z = 2; tex.src_sel_w = 3; + if (inst->Texture.Texture == TGSI_TEXTURE_CUBE) { + tex.src_sel_x = 1; + tex.src_sel_y = 0; + tex.src_sel_z = 3; + tex.src_sel_w = 1; + } + if (inst->Texture.Texture != TGSI_TEXTURE_RECT) { tex.coord_type_x = 1; tex.coord_type_y = 1; tex.coord_type_z = 1; tex.coord_type_w = 1; } - return r600_bc_add_tex(ctx->bc, &tex); + + if (inst->Texture.Texture == TGSI_TEXTURE_SHADOW1D || inst->Texture.Texture == TGSI_TEXTURE_SHADOW2D) + tex.src_sel_w = 2; + + r = r600_bc_add_tex(ctx->bc, &tex); + if (r) + return r; + + /* add shadow ambient support - gallium doesn't do it yet */ + return 0; + } static int tgsi_lrp(struct r600_shader_ctx *ctx) @@ -1141,7 +1710,7 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx) for (i = 0; i < 4; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ADD; - alu.src[0].sel = 249; + alu.src[0].sel = V_SQ_ALU_SRC_1; alu.src[0].chan = 0; alu.src[1] = r600_src[0]; alu.src[1].chan = tgsi_chan(&inst->Src[0], i); @@ -1205,23 +1774,654 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx) return tgsi_helper_copy(ctx, inst); } +static int tgsi_cmp(struct r600_shader_ctx *ctx) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu_src r600_src[3]; + struct r600_bc_alu alu; + int use_temp = 0; + int i, r; + + r = tgsi_split_constant(ctx, r600_src); + if (r) + return r; + + if (inst->Dst[0].Register.WriteMask != 0xf) + use_temp = 1; + + for (i = 0; i < 4; i++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_CNDGE; + alu.src[0] = r600_src[0]; + alu.src[0].chan = tgsi_chan(&inst->Src[0], i); + + alu.src[1] = r600_src[2]; + alu.src[1].chan = tgsi_chan(&inst->Src[2], i); + + alu.src[2] = r600_src[1]; + alu.src[2].chan = tgsi_chan(&inst->Src[1], i); + + if (use_temp) + alu.dst.sel = ctx->temp_reg; + else { + r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); + if (r) + return r; + } + alu.dst.chan = i; + alu.dst.write = 1; + alu.is_op3 = 1; + if (i == 3) + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + if (use_temp) + return tgsi_helper_copy(ctx, inst); + return 0; +} + +static int tgsi_xpd(struct r600_shader_ctx *ctx) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu_src r600_src[3]; + struct r600_bc_alu alu; + uint32_t use_temp = 0; + int i, r; + + if (inst->Dst[0].Register.WriteMask != 0xf) + use_temp = 1; + + r = tgsi_split_constant(ctx, r600_src); + if (r) + return r; + + for (i = 0; i < 4; i++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL; + + alu.src[0] = r600_src[0]; + switch (i) { + case 0: + alu.src[0].chan = tgsi_chan(&inst->Src[0], 2); + break; + case 1: + alu.src[0].chan = tgsi_chan(&inst->Src[0], 0); + break; + case 2: + alu.src[0].chan = tgsi_chan(&inst->Src[0], 1); + break; + case 3: + alu.src[0].sel = V_SQ_ALU_SRC_0; + alu.src[0].chan = i; + } + + alu.src[1] = r600_src[1]; + switch (i) { + case 0: + alu.src[1].chan = tgsi_chan(&inst->Src[1], 1); + break; + case 1: + alu.src[1].chan = tgsi_chan(&inst->Src[1], 2); + break; + case 2: + alu.src[1].chan = tgsi_chan(&inst->Src[1], 0); + break; + case 3: + alu.src[1].sel = V_SQ_ALU_SRC_0; + alu.src[1].chan = i; + } + + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = i; + alu.dst.write = 1; + + if (i == 3) + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + + for (i = 0; i < 4; i++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MULADD; + + alu.src[0] = r600_src[0]; + switch (i) { + case 0: + alu.src[0].chan = tgsi_chan(&inst->Src[0], 1); + break; + case 1: + alu.src[0].chan = tgsi_chan(&inst->Src[0], 2); + break; + case 2: + alu.src[0].chan = tgsi_chan(&inst->Src[0], 0); + break; + case 3: + alu.src[0].sel = V_SQ_ALU_SRC_0; + alu.src[0].chan = i; + } + + alu.src[1] = r600_src[1]; + switch (i) { + case 0: + alu.src[1].chan = tgsi_chan(&inst->Src[1], 2); + break; + case 1: + alu.src[1].chan = tgsi_chan(&inst->Src[1], 0); + break; + case 2: + alu.src[1].chan = tgsi_chan(&inst->Src[1], 1); + break; + case 3: + alu.src[1].sel = V_SQ_ALU_SRC_0; + alu.src[1].chan = i; + } + + alu.src[2].sel = ctx->temp_reg; + alu.src[2].neg = 1; + alu.src[2].chan = i; + + if (use_temp) + alu.dst.sel = ctx->temp_reg; + else { + r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); + if (r) + return r; + } + alu.dst.chan = i; + alu.dst.write = 1; + alu.is_op3 = 1; + if (i == 3) + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + if (use_temp) + return tgsi_helper_copy(ctx, inst); + return 0; +} + +static int tgsi_exp(struct r600_shader_ctx *ctx) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu_src r600_src[3]; + struct r600_bc_alu alu; + int r; + + /* result.x = 2^floor(src); */ + if (inst->Dst[0].Register.WriteMask & 1) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLOOR; + r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); + if (r) + return r; + + alu.src[0].chan = tgsi_chan(&inst->Src[0], 0); + + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 0; + alu.dst.write = 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE; + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 0; + + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 0; + alu.dst.write = 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + } + + /* result.y = tmp - floor(tmp); */ + if ((inst->Dst[0].Register.WriteMask >> 1) & 1) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FRACT; + alu.src[0] = r600_src[0]; + r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); + if (r) + return r; + alu.src[0].chan = tgsi_chan(&inst->Src[0], 0); + + alu.dst.sel = ctx->temp_reg; +// r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); +// if (r) +// return r; + alu.dst.write = 1; + alu.dst.chan = 1; + + alu.last = 1; + + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + } + + /* result.z = RoughApprox2ToX(tmp);*/ + if ((inst->Dst[0].Register.WriteMask >> 2) & 0x1) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE; + r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); + if (r) + return r; + alu.src[0].chan = tgsi_chan(&inst->Src[0], 0); + + alu.dst.sel = ctx->temp_reg; + alu.dst.write = 1; + alu.dst.chan = 2; + + alu.last = 1; + + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + } + + /* result.w = 1.0;*/ + if ((inst->Dst[0].Register.WriteMask >> 3) & 0x1) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV; + alu.src[0].sel = V_SQ_ALU_SRC_1; + alu.src[0].chan = 0; + + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 3; + alu.dst.write = 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + r = r600_bc_add_literal(ctx->bc, ctx->value); + if (r) + return r; + } + return tgsi_helper_copy(ctx, inst); +} + +static int tgsi_arl(struct r600_shader_ctx *ctx) +{ + /* TODO from r600c, ar values don't persist between clauses */ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu alu; + int r; + memset(&alu, 0, sizeof(struct r600_bc_alu)); + + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_FLOOR; + + r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); + if (r) + return r; + alu.src[0].chan = tgsi_chan(&inst->Src[0], 0); + + alu.last = 1; + + r = r600_bc_add_alu_type(ctx->bc, &alu, V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU); + if (r) + return r; + return 0; +} + +static int tgsi_opdst(struct r600_shader_ctx *ctx) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu alu; + int i, r = 0; + + for (i = 0; i < 4; i++) { + memset(&alu, 0, sizeof(struct r600_bc_alu)); + + alu.inst = V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL; + r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); + if (r) + return r; + + if (i == 0 || i == 3) { + alu.src[0].sel = V_SQ_ALU_SRC_1; + } else { + r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); + if (r) + return r; + alu.src[0].chan = tgsi_chan(&inst->Src[0], i); + } + + if (i == 0 || i == 2) { + alu.src[1].sel = V_SQ_ALU_SRC_1; + } else { + r = tgsi_src(ctx, &inst->Src[1], &alu.src[1]); + if (r) + return r; + alu.src[1].chan = tgsi_chan(&inst->Src[1], i); + } + if (i == 3) + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + } + return 0; +} + +static int emit_logic_pred(struct r600_shader_ctx *ctx, int opcode) +{ + struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction; + struct r600_bc_alu alu; + int r; + + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = opcode; + alu.predicate = 1; + + alu.dst.sel = ctx->temp_reg; + alu.dst.write = 1; + alu.dst.chan = 0; + + r = tgsi_src(ctx, &inst->Src[0], &alu.src[0]); + if (r) + return r; + alu.src[0].chan = tgsi_chan(&inst->Src[0], 0); + alu.src[1].sel = V_SQ_ALU_SRC_0; + alu.src[1].chan = 0; + + alu.last = 1; + + r = r600_bc_add_alu_type(ctx->bc, &alu, V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE); + if (r) + return r; + return 0; +} + +static int pops(struct r600_shader_ctx *ctx, int pops) +{ + r600_bc_add_cfinst(ctx->bc, V_SQ_CF_WORD1_SQ_CF_INST_POP); + ctx->bc->cf_last->pop_count = pops; + return 0; +} + +static inline void callstack_decrease_current(struct r600_shader_ctx *ctx, unsigned reason) +{ + switch(reason) { + case FC_PUSH_VPM: + ctx->bc->callstack[ctx->bc->call_sp].current--; + break; + case FC_PUSH_WQM: + case FC_LOOP: + ctx->bc->callstack[ctx->bc->call_sp].current -= 4; + break; + case FC_REP: + /* TOODO : for 16 vp asic should -= 2; */ + ctx->bc->callstack[ctx->bc->call_sp].current --; + break; + } +} + +static inline void callstack_check_depth(struct r600_shader_ctx *ctx, unsigned reason, unsigned check_max_only) +{ + if (check_max_only) { + int diff; + switch (reason) { + case FC_PUSH_VPM: + diff = 1; + break; + case FC_PUSH_WQM: + diff = 4; + break; + } + if ((ctx->bc->callstack[ctx->bc->call_sp].current + diff) > + ctx->bc->callstack[ctx->bc->call_sp].max) { + ctx->bc->callstack[ctx->bc->call_sp].max = + ctx->bc->callstack[ctx->bc->call_sp].current + diff; + } + return; + } + switch (reason) { + case FC_PUSH_VPM: + ctx->bc->callstack[ctx->bc->call_sp].current++; + break; + case FC_PUSH_WQM: + case FC_LOOP: + ctx->bc->callstack[ctx->bc->call_sp].current += 4; + break; + case FC_REP: + ctx->bc->callstack[ctx->bc->call_sp].current++; + break; + } + + if ((ctx->bc->callstack[ctx->bc->call_sp].current) > + ctx->bc->callstack[ctx->bc->call_sp].max) { + ctx->bc->callstack[ctx->bc->call_sp].max = + ctx->bc->callstack[ctx->bc->call_sp].current; + } +} + +static void fc_set_mid(struct r600_shader_ctx *ctx, int fc_sp) +{ + struct r600_cf_stack_entry *sp = &ctx->bc->fc_stack[fc_sp]; + + sp->mid = (struct r600_bc_cf **)realloc((void *)sp->mid, + sizeof(struct r600_bc_cf *) * (sp->num_mid + 1)); + sp->mid[sp->num_mid] = ctx->bc->cf_last; + sp->num_mid++; +} + +static void fc_pushlevel(struct r600_shader_ctx *ctx, int type) +{ + ctx->bc->fc_sp++; + ctx->bc->fc_stack[ctx->bc->fc_sp].type = type; + ctx->bc->fc_stack[ctx->bc->fc_sp].start = ctx->bc->cf_last; +} + +static void fc_poplevel(struct r600_shader_ctx *ctx) +{ + struct r600_cf_stack_entry *sp = &ctx->bc->fc_stack[ctx->bc->fc_sp]; + if (sp->mid) { + free(sp->mid); + sp->mid = NULL; + } + sp->num_mid = 0; + sp->start = NULL; + sp->type = 0; + ctx->bc->fc_sp--; +} + +#if 0 +static int emit_return(struct r600_shader_ctx *ctx) +{ + r600_bc_add_cfinst(ctx->bc, V_SQ_CF_WORD1_SQ_CF_INST_RETURN); + return 0; +} + +static int emit_jump_to_offset(struct r600_shader_ctx *ctx, int pops, int offset) +{ + + r600_bc_add_cfinst(ctx->bc, V_SQ_CF_WORD1_SQ_CF_INST_JUMP); + ctx->bc->cf_last->pop_count = pops; + /* TODO work out offset */ + return 0; +} + +static int emit_setret_in_loop_flag(struct r600_shader_ctx *ctx, unsigned flag_value) +{ + return 0; +} + +static void emit_testflag(struct r600_shader_ctx *ctx) +{ + +} + +static void emit_return_on_flag(struct r600_shader_ctx *ctx, unsigned ifidx) +{ + emit_testflag(ctx); + emit_jump_to_offset(ctx, 1, 4); + emit_setret_in_loop_flag(ctx, V_SQ_ALU_SRC_0); + pops(ctx, ifidx + 1); + emit_return(ctx); +} + +static void break_loop_on_flag(struct r600_shader_ctx *ctx, unsigned fc_sp) +{ + emit_testflag(ctx); + + r600_bc_add_cfinst(ctx->bc, ctx->inst_info->r600_opcode); + ctx->bc->cf_last->pop_count = 1; + + fc_set_mid(ctx, fc_sp); + + pops(ctx, 1); +} +#endif + +static int tgsi_if(struct r600_shader_ctx *ctx) +{ + emit_logic_pred(ctx, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE); + + r600_bc_add_cfinst(ctx->bc, V_SQ_CF_WORD1_SQ_CF_INST_JUMP); + + fc_pushlevel(ctx, FC_IF); + + callstack_check_depth(ctx, FC_PUSH_VPM, 0); + return 0; +} + +static int tgsi_else(struct r600_shader_ctx *ctx) +{ + r600_bc_add_cfinst(ctx->bc, V_SQ_CF_WORD1_SQ_CF_INST_ELSE); + ctx->bc->cf_last->pop_count = 1; + + fc_set_mid(ctx, ctx->bc->fc_sp); + ctx->bc->fc_stack[ctx->bc->fc_sp].start->cf_addr = ctx->bc->cf_last->id; + return 0; +} + +static int tgsi_endif(struct r600_shader_ctx *ctx) +{ + pops(ctx, 1); + if (ctx->bc->fc_stack[ctx->bc->fc_sp].type != FC_IF) { + R600_ERR("if/endif unbalanced in shader\n"); + return -1; + } + + if (ctx->bc->fc_stack[ctx->bc->fc_sp].mid == NULL) { + ctx->bc->fc_stack[ctx->bc->fc_sp].start->cf_addr = ctx->bc->cf_last->id + 2; + ctx->bc->fc_stack[ctx->bc->fc_sp].start->pop_count = 1; + } else { + ctx->bc->fc_stack[ctx->bc->fc_sp].mid[0]->cf_addr = ctx->bc->cf_last->id + 2; + } + fc_poplevel(ctx); + + callstack_decrease_current(ctx, FC_PUSH_VPM); + return 0; +} + +static int tgsi_bgnloop(struct r600_shader_ctx *ctx) +{ + r600_bc_add_cfinst(ctx->bc, V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL); + + fc_pushlevel(ctx, FC_LOOP); + + /* check stack depth */ + callstack_check_depth(ctx, FC_LOOP, 0); + return 0; +} + +static int tgsi_endloop(struct r600_shader_ctx *ctx) +{ + int i; + + r600_bc_add_cfinst(ctx->bc, V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END); + + if (ctx->bc->fc_stack[ctx->bc->fc_sp].type != FC_LOOP) { + R600_ERR("loop/endloop in shader code are not paired.\n"); + return -EINVAL; + } + + /* fixup loop pointers - from r600isa + LOOP END points to CF after LOOP START, + LOOP START point to CF after LOOP END + BRK/CONT point to LOOP END CF + */ + ctx->bc->cf_last->cf_addr = ctx->bc->fc_stack[ctx->bc->fc_sp].start->id + 2; + + ctx->bc->fc_stack[ctx->bc->fc_sp].start->cf_addr = ctx->bc->cf_last->id + 2; + + for (i = 0; i < ctx->bc->fc_stack[ctx->bc->fc_sp].num_mid; i++) { + ctx->bc->fc_stack[ctx->bc->fc_sp].mid[i]->cf_addr = ctx->bc->cf_last->id; + } + /* TODO add LOOPRET support */ + fc_poplevel(ctx); + callstack_decrease_current(ctx, FC_LOOP); + return 0; +} + +static int tgsi_loop_brk_cont(struct r600_shader_ctx *ctx) +{ + unsigned int fscp; + + for (fscp = ctx->bc->fc_sp; fscp > 0; fscp--) + { + if (FC_LOOP == ctx->bc->fc_stack[fscp].type) + break; + } + + if (fscp == 0) { + R600_ERR("Break not inside loop/endloop pair\n"); + return -EINVAL; + } + + r600_bc_add_cfinst(ctx->bc, ctx->inst_info->r600_opcode); + ctx->bc->cf_last->pop_count = 1; + + fc_set_mid(ctx, fscp); + + pops(ctx, 1); + callstack_check_depth(ctx, FC_PUSH_VPM, 1); + return 0; +} + static struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[] = { - {TGSI_OPCODE_ARL, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_ARL, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_arl}, {TGSI_OPCODE_MOV, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV, tgsi_op2}, {TGSI_OPCODE_LIT, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_lit}, {TGSI_OPCODE_RCP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE, tgsi_trans_srcx_replicate}, {TGSI_OPCODE_RSQ, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_IEEE, tgsi_trans_srcx_replicate}, - {TGSI_OPCODE_EXP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_EXP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_exp}, {TGSI_OPCODE_LOG, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_MUL, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL, tgsi_op2}, {TGSI_OPCODE_ADD, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ADD, tgsi_op2}, {TGSI_OPCODE_DP3, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4, tgsi_dp}, {TGSI_OPCODE_DP4, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4, tgsi_dp}, - {TGSI_OPCODE_DST, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_DST, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_opdst}, {TGSI_OPCODE_MIN, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MIN, tgsi_op2}, {TGSI_OPCODE_MAX, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX, tgsi_op2}, - {TGSI_OPCODE_SLT, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGT, tgsi_slt}, - {TGSI_OPCODE_SGE, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_SLT, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGT, tgsi_op2_swap}, + {TGSI_OPCODE_SGE, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGE, tgsi_op2}, {TGSI_OPCODE_MAD, 1, V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MULADD, tgsi_op3}, {TGSI_OPCODE_SUB, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ADD, tgsi_op2}, {TGSI_OPCODE_LRP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_lrp}, @@ -1232,38 +2432,38 @@ static struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[] = { /* gap */ {22, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {23, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_FRC, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_FRC, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FRACT, tgsi_op2}, {TGSI_OPCODE_CLAMP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_FLR, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_FLR, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLOOR, tgsi_op2}, {TGSI_OPCODE_ROUND, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_EX2, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE, tgsi_trans_srcx_replicate}, - {TGSI_OPCODE_LG2, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_POW, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_XPD, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_LG2, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE, tgsi_trans_srcx_replicate}, + {TGSI_OPCODE_POW, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_pow}, + {TGSI_OPCODE_XPD, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_xpd}, /* gap */ {32, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_ABS, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV, tgsi_op2}, {TGSI_OPCODE_RCC, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_DPH, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_COS, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_DDX, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_DDY, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_KILP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, /* predicated kill */ + {TGSI_OPCODE_DPH, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4, tgsi_dp}, + {TGSI_OPCODE_COS, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS, tgsi_trig}, + {TGSI_OPCODE_DDX, 0, SQ_TEX_INST_GET_GRADIENTS_H, tgsi_tex}, + {TGSI_OPCODE_DDY, 0, SQ_TEX_INST_GET_GRADIENTS_V, tgsi_tex}, + {TGSI_OPCODE_KILP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT, tgsi_kill}, /* predicated kill */ {TGSI_OPCODE_PK2H, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_PK2US, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_PK4B, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_PK4UB, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_RFL, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_SEQ, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_SEQ, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETE, tgsi_op2}, {TGSI_OPCODE_SFL, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_SGT, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_SIN, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_SLE, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_SNE, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_SGT, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGT, tgsi_op2}, + {TGSI_OPCODE_SIN, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SIN, tgsi_trig}, + {TGSI_OPCODE_SLE, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGE, tgsi_op2_swap}, + {TGSI_OPCODE_SNE, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETNE, tgsi_op2}, {TGSI_OPCODE_STR, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_TEX, 0, 0x10, tgsi_tex}, + {TGSI_OPCODE_TEX, 0, SQ_TEX_INST_SAMPLE, tgsi_tex}, {TGSI_OPCODE_TXD, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_TXP, 0, 0x10, tgsi_tex}, + {TGSI_OPCODE_TXP, 0, SQ_TEX_INST_SAMPLE, tgsi_tex}, {TGSI_OPCODE_UP2H, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_UP2US, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_UP4B, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, @@ -1274,21 +2474,21 @@ static struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[] = { {TGSI_OPCODE_BRA, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_CAL, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_RET, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_SSG, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, /* SGN */ - {TGSI_OPCODE_CMP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_SCS, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_TXB, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_SSG, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_ssg}, + {TGSI_OPCODE_CMP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_cmp}, + {TGSI_OPCODE_SCS, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_scs}, + {TGSI_OPCODE_TXB, 0, SQ_TEX_INST_SAMPLE_L, tgsi_tex}, {TGSI_OPCODE_NRM, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_DIV, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_DP2, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4, tgsi_dp}, {TGSI_OPCODE_TXL, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_BRK, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_IF, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_BRK, 0, V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK, tgsi_loop_brk_cont}, + {TGSI_OPCODE_IF, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_if}, /* gap */ {75, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {76, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_ELSE, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_ENDIF, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_ELSE, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_else}, + {TGSI_OPCODE_ENDIF, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_endif}, /* gap */ {79, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {80, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, @@ -1297,7 +2497,7 @@ static struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[] = { {TGSI_OPCODE_CEIL, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_I2F, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_NOT, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_TRUNC, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_TRUNC, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_TRUNC, tgsi_trans_srcx_replicate}, {TGSI_OPCODE_SHL, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, /* gap */ {88, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, @@ -1308,12 +2508,12 @@ static struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[] = { {TGSI_OPCODE_SAD, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_TXF, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_TXQ, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_CONT, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_CONT, 0, V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE, tgsi_loop_brk_cont}, {TGSI_OPCODE_EMIT, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, {TGSI_OPCODE_ENDPRIM, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_BGNLOOP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_BGNLOOP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_bgnloop}, {TGSI_OPCODE_BGNSUB, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, - {TGSI_OPCODE_ENDLOOP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, + {TGSI_OPCODE_ENDLOOP, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_endloop}, {TGSI_OPCODE_ENDSUB, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, /* gap */ {103, 0, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_unsupported}, diff --git a/src/gallium/drivers/r600/r600_shader.h b/src/gallium/drivers/r600/r600_shader.h index 2ee7780ead..7c722c07cb 100644 --- a/src/gallium/drivers/r600/r600_shader.h +++ b/src/gallium/drivers/r600/r600_shader.h @@ -42,6 +42,7 @@ struct r600_shader { struct r600_shader_io input[32]; struct r600_shader_io output[32]; enum radeon_family family; + boolean uses_kill; }; #endif diff --git a/src/gallium/drivers/r600/r600_sq.h b/src/gallium/drivers/r600/r600_sq.h index 002660c654..fa7a31742a 100644 --- a/src/gallium/drivers/r600/r600_sq.h +++ b/src/gallium/drivers/r600/r600_sq.h @@ -206,6 +206,26 @@ #define S_SQ_ALU_WORD0_SRC0_SEL(x) (((x) & 0x1FF) << 0) #define G_SQ_ALU_WORD0_SRC0_SEL(x) (((x) >> 0) & 0x1FF) #define C_SQ_ALU_WORD0_SRC0_SEL 0xFFFFFE00 +/* + * 244 ALU_SRC_1_DBL_L: special constant 1.0 double-float, LSW. (RV670+) + * 245 ALU_SRC_1_DBL_M: special constant 1.0 double-float, MSW. (RV670+) + * 246 ALU_SRC_0_5_DBL_L: special constant 0.5 double-float, LSW. (RV670+) + * 247 ALU_SRC_0_5_DBL_M: special constant 0.5 double-float, MSW. (RV670+) + * 248 SQ_ALU_SRC_0: special constant 0.0. + * 249 SQ_ALU_SRC_1: special constant 1.0 float. + * 250 SQ_ALU_SRC_1_INT: special constant 1 integer. + * 251 SQ_ALU_SRC_M_1_INT: special constant -1 integer. + * 252 SQ_ALU_SRC_0_5: special constant 0.5 float. + * 253 SQ_ALU_SRC_LITERAL: literal constant. + * 254 SQ_ALU_SRC_PV: previous vector result. + * 255 SQ_ALU_SRC_PS: previous scalar result. + */ +#define V_SQ_ALU_SRC_0 0x000000F8 +#define V_SQ_ALU_SRC_1 0x000000F9 +#define V_SQ_ALU_SRC_1_INT 0x000000FA +#define V_SQ_ALU_SRC_M_1_INT 0x000000FB +#define V_SQ_ALU_SRC_0_5 0x000000FC +#define V_SQ_ALU_SRC_LITERAL 0x000000FD #define S_SQ_ALU_WORD0_SRC0_REL(x) (((x) & 0x1) << 9) #define G_SQ_ALU_WORD0_SRC0_REL(x) (((x) >> 9) & 0x1) #define C_SQ_ALU_WORD0_SRC0_REL 0xFFFFFDFF @@ -583,4 +603,11 @@ #define G_SQ_TEX_WORD2_SRC_SEL_W(x) (((x) >> 29) & 0x7) #define C_SQ_TEX_WORD2_SRC_SEL_W 0x1FFFFFFF +#define V_SQ_CF_COND_ACTIVE 0x00 +#define V_SQ_CF_COND_FALSE 0x01 +#define V_SQ_CF_COND_BOOL 0x02 +#define V_SQ_CF_COND_NOT_BOOL 0x03 + +#define V_SQ_REL_ABSOLUTE 0 +#define V_SQ_REL_RELATIVE 1 #endif diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c index 3efd409ae0..66cab7d7a6 100644 --- a/src/gallium/drivers/r600/r600_state.c +++ b/src/gallium/drivers/r600/r600_state.c @@ -34,6 +34,17 @@ #include "r600d.h" #include "r600_state_inlines.h" +static void r600_blend(struct r600_context *rctx, struct radeon_state *rstate, const struct pipe_blend_state *state); +static void r600_viewport(struct r600_context *rctx, struct radeon_state *rstate, const struct pipe_viewport_state *state); +static void r600_ucp(struct r600_context *rctx, struct radeon_state *rstate, const struct pipe_clip_state *state); +static void r600_sampler(struct r600_context *rctx, struct radeon_state *rstate, const struct pipe_sampler_state *state, unsigned id); +static void r600_resource(struct pipe_context *ctx, struct radeon_state *rstate, const struct pipe_sampler_view *view, unsigned id); +static void r600_cb(struct r600_context *rctx, struct radeon_state *rstate, + const struct pipe_framebuffer_state *state, int cb); +static void r600_db(struct r600_context *rctx, struct radeon_state *rstate, + const struct pipe_framebuffer_state *state); + + static void *r600_create_blend_state(struct pipe_context *ctx, const struct pipe_blend_state *state) { @@ -81,11 +92,12 @@ static struct pipe_sampler_view *r600_create_sampler_view(struct pipe_context *c struct r600_context *rctx = r600_context(ctx); struct r600_context_state *rstate; - rstate = r600_context_state(rctx, pipe_sampler_type, state); + rstate = r600_context_state(rctx, pipe_sampler_view_type, state); pipe_reference(NULL, &texture->reference); rstate->state.sampler_view.texture = texture; rstate->state.sampler_view.reference.count = 1; rstate->state.sampler_view.context = ctx; + r600_resource(ctx, &rstate->rstate[0], &rstate->state.sampler_view, 0); return &rstate->state.sampler_view; } @@ -223,12 +235,24 @@ static void r600_bind_ps_sampler(struct pipe_context *ctx, struct r600_context_state *rstate; unsigned i; - for (i = 0; i < rctx->ps_nsampler; i++) { - rctx->ps_sampler[i] = r600_context_state_decref(rctx->ps_sampler[i]); + for (i = 0; i < count; i++) { + rstate = (struct r600_context_state *)states[i]; + if (rstate) { + rstate->nrstate = 0; + } } for (i = 0; i < count; i++) { rstate = (struct r600_context_state *)states[i]; - rctx->ps_sampler[i] = r600_context_state_incref(rstate); + if (rstate) { + if (rstate->nrstate >= R600_MAX_RSTATE) + continue; + if (rstate->nrstate) { + memcpy(&rstate->rstate[rstate->nrstate], &rstate->rstate[0], sizeof(struct radeon_state)); + } + radeon_state_convert(&rstate->rstate[rstate->nrstate], R600_STATE_SAMPLER, i, R600_SHADER_PS); + rctx->ps_sampler[i] = &rstate->rstate[rstate->nrstate]; + rstate->nrstate++; + } } rctx->ps_nsampler = count; } @@ -240,12 +264,24 @@ static void r600_bind_vs_sampler(struct pipe_context *ctx, struct r600_context_state *rstate; unsigned i; - for (i = 0; i < rctx->vs_nsampler; i++) { - rctx->vs_sampler[i] = r600_context_state_decref(rctx->vs_sampler[i]); + for (i = 0; i < count; i++) { + rstate = (struct r600_context_state *)states[i]; + if (rstate) { + rstate->nrstate = 0; + } } for (i = 0; i < count; i++) { rstate = (struct r600_context_state *)states[i]; - rctx->vs_sampler[i] = r600_context_state_incref(rstate); + if (rstate) { + if (rstate->nrstate >= R600_MAX_RSTATE) + continue; + if (rstate->nrstate) { + memcpy(&rstate->rstate[rstate->nrstate], &rstate->rstate[0], sizeof(struct radeon_state)); + } + radeon_state_convert(&rstate->rstate[rstate->nrstate], R600_STATE_SAMPLER, i, R600_SHADER_VS); + rctx->vs_sampler[i] = &rstate->rstate[rstate->nrstate]; + rstate->nrstate++; + } } rctx->vs_nsampler = count; } @@ -268,6 +304,13 @@ static void r600_set_blend_color(struct pipe_context *ctx, static void r600_set_clip_state(struct pipe_context *ctx, const struct pipe_clip_state *state) { + struct r600_context *rctx = r600_context(ctx); + struct r600_context_state *rstate; + + rstate = r600_context_state(rctx, pipe_clip_type, state); + r600_bind_state(ctx, rstate); + /* refcount is taken care of this */ + r600_delete_state(ctx, rstate); } static void r600_set_constant_buffer(struct pipe_context *ctx, @@ -276,19 +319,21 @@ static void r600_set_constant_buffer(struct pipe_context *ctx, { struct r600_screen *rscreen = r600_screen(ctx->screen); struct r600_context *rctx = r600_context(ctx); - unsigned nconstant = 0, i, type, id; - struct radeon_state *rstate; + unsigned nconstant = 0, i, type, shader_class; + struct radeon_state *rstate, *rstates; struct pipe_transfer *transfer; u32 *ptr; + type = R600_STATE_CONSTANT; + switch (shader) { case PIPE_SHADER_VERTEX: - id = R600_VS_CONSTANT; - type = R600_VS_CONSTANT_TYPE; + shader_class = R600_SHADER_VS; + rstates = rctx->vs_constant; break; case PIPE_SHADER_FRAGMENT: - id = R600_PS_CONSTANT; - type = R600_PS_CONSTANT_TYPE; + shader_class = R600_SHADER_PS; + rstates = rctx->ps_constant; break; default: R600_ERR("unsupported %d\n", shader); @@ -300,17 +345,15 @@ static void r600_set_constant_buffer(struct pipe_context *ctx, if (ptr == NULL) return; for (i = 0; i < nconstant; i++) { - rstate = radeon_state(rscreen->rw, type, id + i); - if (rstate == NULL) - return; + rstate = &rstates[i]; + radeon_state_init(rstate, rscreen->rw, type, i, shader_class); rstate->states[R600_PS_CONSTANT__SQ_ALU_CONSTANT0_0] = ptr[i * 4 + 0]; rstate->states[R600_PS_CONSTANT__SQ_ALU_CONSTANT1_0] = ptr[i * 4 + 1]; rstate->states[R600_PS_CONSTANT__SQ_ALU_CONSTANT2_0] = ptr[i * 4 + 2]; rstate->states[R600_PS_CONSTANT__SQ_ALU_CONSTANT3_0] = ptr[i * 4 + 3]; if (radeon_state_pm4(rstate)) return; - if (radeon_draw_set_new(rctx->draw, rstate)) - return; + radeon_draw_bind(&rctx->draw, rstate); } pipe_buffer_unmap(ctx, buffer, transfer); } @@ -324,12 +367,24 @@ static void r600_set_ps_sampler_view(struct pipe_context *ctx, struct r600_context_state *rstate; unsigned i; - for (i = 0; i < rctx->ps_nsampler_view; i++) { - rctx->ps_sampler_view[i] = r600_context_state_decref(rctx->ps_sampler_view[i]); + for (i = 0; i < count; i++) { + rstate = (struct r600_context_state *)views[i]; + if (rstate) { + rstate->nrstate = 0; + } } for (i = 0; i < count; i++) { rstate = (struct r600_context_state *)views[i]; - rctx->ps_sampler_view[i] = r600_context_state_incref(rstate); + if (rstate) { + if (rstate->nrstate >= R600_MAX_RSTATE) + continue; + if (rstate->nrstate) { + memcpy(&rstate->rstate[rstate->nrstate], &rstate->rstate[0], sizeof(struct radeon_state)); + } + radeon_state_convert(&rstate->rstate[rstate->nrstate], R600_STATE_RESOURCE, i, R600_SHADER_PS); + rctx->ps_sampler_view[i] = &rstate->rstate[rstate->nrstate]; + rstate->nrstate++; + } } rctx->ps_nsampler_view = count; } @@ -342,12 +397,24 @@ static void r600_set_vs_sampler_view(struct pipe_context *ctx, struct r600_context_state *rstate; unsigned i; - for (i = 0; i < rctx->vs_nsampler_view; i++) { - rctx->vs_sampler_view[i] = r600_context_state_decref(rctx->vs_sampler_view[i]); + for (i = 0; i < count; i++) { + rstate = (struct r600_context_state *)views[i]; + if (rstate) { + rstate->nrstate = 0; + } } for (i = 0; i < count; i++) { rstate = (struct r600_context_state *)views[i]; - rctx->vs_sampler_view[i] = r600_context_state_incref(rstate); + if (rstate) { + if (rstate->nrstate >= R600_MAX_RSTATE) + continue; + if (rstate->nrstate) { + memcpy(&rstate->rstate[rstate->nrstate], &rstate->rstate[0], sizeof(struct radeon_state)); + } + radeon_state_convert(&rstate->rstate[rstate->nrstate], R600_STATE_RESOURCE, i, R600_SHADER_VS); + rctx->vs_sampler_view[i] = &rstate->rstate[rstate->nrstate]; + rstate->nrstate++; + } } rctx->vs_nsampler_view = count; } @@ -360,6 +427,12 @@ static void r600_set_framebuffer_state(struct pipe_context *ctx, rstate = r600_context_state(rctx, pipe_framebuffer_type, state); r600_bind_state(ctx, rstate); + for (int i = 0; i < state->nr_cbufs; i++) { + r600_cb(rctx, &rstate->rstate[i+1], state, i); + } + if (state->zsbuf) { + r600_db(rctx, &rstate->rstate[0], state); + } } static void r600_set_polygon_stipple(struct pipe_context *ctx, @@ -525,7 +598,7 @@ struct r600_context_state *r600_context_state_decref(struct r600_context_state * R600_ERR("invalid type %d\n", rstate->type); return NULL; } - radeon_state_decref(rstate->rstate); + radeon_state_fini(&rstate->rstate[0]); FREE(rstate); return NULL; } @@ -558,6 +631,7 @@ struct r600_context_state *r600_context_state(struct r600_context *rctx, unsigne break; case pipe_viewport_type: rstate->state.viewport = (*states).viewport; + r600_viewport(rctx, &rstate->rstate[0], &rstate->state.viewport); break; case pipe_depth_type: rstate->state.depth = (*states).depth; @@ -573,6 +647,7 @@ struct r600_context_state *r600_context_state(struct r600_context *rctx, unsigne break; case pipe_clip_type: rstate->state.clip = (*states).clip; + r600_ucp(rctx, &rstate->rstate[0], &rstate->state.clip); break; case pipe_stencil_type: rstate->state.stencil = (*states).stencil; @@ -585,6 +660,7 @@ struct r600_context_state *r600_context_state(struct r600_context *rctx, unsigne break; case pipe_blend_type: rstate->state.blend = (*states).blend; + r600_blend(rctx, &rstate->rstate[0], &rstate->state.blend); break; case pipe_stencil_ref_type: rstate->state.stencil_ref = (*states).stencil_ref; @@ -599,6 +675,7 @@ struct r600_context_state *r600_context_state(struct r600_context *rctx, unsigne break; case pipe_sampler_type: rstate->state.sampler = (*states).sampler; + r600_sampler(rctx, &rstate->rstate[0], &rstate->state.sampler, 0); break; default: R600_ERR("invalid type %d\n", rstate->type); @@ -608,16 +685,12 @@ struct r600_context_state *r600_context_state(struct r600_context *rctx, unsigne return rstate; } -static struct radeon_state *r600_blend(struct r600_context *rctx) +static void r600_blend(struct r600_context *rctx, struct radeon_state *rstate, const struct pipe_blend_state *state) { struct r600_screen *rscreen = rctx->screen; - struct radeon_state *rstate; - const struct pipe_blend_state *state = &rctx->blend->state.blend; int i; - rstate = radeon_state(rscreen->rw, R600_BLEND_TYPE, R600_BLEND); - if (rstate == NULL) - return NULL; + radeon_state_init(rstate, rscreen->rw, R600_STATE_BLEND, 0, 0); rstate->states[R600_BLEND__CB_BLEND_RED] = fui(rctx->blend_color.color[0]); rstate->states[R600_BLEND__CB_BLEND_GREEN] = fui(rctx->blend_color.color[1]); rstate->states[R600_BLEND__CB_BLEND_BLUE] = fui(rctx->blend_color.color[2]); @@ -661,29 +734,38 @@ static struct radeon_state *r600_blend(struct r600_context *rctx) rstate->states[R600_BLEND__CB_BLEND_CONTROL] = bc; } - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; + radeon_state_pm4(rstate); +} + +static void r600_ucp(struct r600_context *rctx, struct radeon_state *rstate, + const struct pipe_clip_state *state) +{ + struct r600_screen *rscreen = rctx->screen; + + radeon_state_init(rstate, rscreen->rw, R600_STATE_UCP, 0, 0); + + for (int i = 0; i < state->nr; i++) { + rstate->states[i * 4 + 0] = fui(state->ucp[i][0]); + rstate->states[i * 4 + 1] = fui(state->ucp[i][1]); + rstate->states[i * 4 + 2] = fui(state->ucp[i][2]); + rstate->states[i * 4 + 3] = fui(state->ucp[i][3]); } - return rstate; + radeon_state_pm4(rstate); } -static struct radeon_state *r600_cb(struct r600_context *rctx, int cb) +static void r600_cb(struct r600_context *rctx, struct radeon_state *rstate, + const struct pipe_framebuffer_state *state, int cb) { struct r600_screen *rscreen = rctx->screen; struct r600_resource_texture *rtex; struct r600_resource *rbuffer; - struct radeon_state *rstate; - const struct pipe_framebuffer_state *state = &rctx->framebuffer->state.framebuffer; unsigned level = state->cbufs[cb]->level; unsigned pitch, slice; unsigned color_info; unsigned format, swap, ntype; const struct util_format_description *desc; - rstate = radeon_state(rscreen->rw, R600_CB0_TYPE + cb, R600_CB0 + cb); - if (rstate == NULL) - return NULL; + radeon_state_init(rstate, rscreen->rw, R600_STATE_CB0 + cb, 0, 0); rtex = (struct r600_resource_texture*)state->cbufs[cb]->texture; rbuffer = &rtex->resource; rstate->bo[0] = radeon_bo_incref(rscreen->rw, rbuffer->bo); @@ -710,7 +792,7 @@ static struct radeon_state *r600_cb(struct r600_context *rctx, int cb) S_0280A0_SOURCE_FORMAT(1) | S_0280A0_NUMBER_TYPE(ntype); - rstate->states[R600_CB0__CB_COLOR0_BASE] = 0x00000000; + rstate->states[R600_CB0__CB_COLOR0_BASE] = state->cbufs[cb]->offset >> 8; rstate->states[R600_CB0__CB_COLOR0_INFO] = color_info; rstate->states[R600_CB0__CB_COLOR0_SIZE] = S_028060_PITCH_TILE_MAX(pitch) | S_028060_SLICE_TILE_MAX(slice); @@ -718,32 +800,29 @@ static struct radeon_state *r600_cb(struct r600_context *rctx, int cb) rstate->states[R600_CB0__CB_COLOR0_FRAG] = 0x00000000; rstate->states[R600_CB0__CB_COLOR0_TILE] = 0x00000000; rstate->states[R600_CB0__CB_COLOR0_MASK] = 0x00000000; - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; - } - return rstate; + radeon_state_pm4(rstate); } -static struct radeon_state *r600_db(struct r600_context *rctx) +static void r600_db(struct r600_context *rctx, struct radeon_state *rstate, + const struct pipe_framebuffer_state *state) { struct r600_screen *rscreen = rctx->screen; struct r600_resource_texture *rtex; struct r600_resource *rbuffer; - struct radeon_state *rstate; - const struct pipe_framebuffer_state *state = &rctx->framebuffer->state.framebuffer; unsigned level; unsigned pitch, slice, format; + radeon_state_init(rstate, rscreen->rw, R600_STATE_DB, 0, 0); if (state->zsbuf == NULL) - return NULL; - - rstate = radeon_state(rscreen->rw, R600_DB_TYPE, R600_DB); - if (rstate == NULL) - return NULL; + return; rtex = (struct r600_resource_texture*)state->zsbuf->texture; + rtex->tilled = 1; + rtex->array_mode = 2; + rtex->tile_type = 1; + rtex->depth = 1; rbuffer = &rtex->resource; + rstate->bo[0] = radeon_bo_incref(rscreen->rw, rbuffer->bo); rstate->nbo = 1; rstate->placement[0] = RADEON_GEM_DOMAIN_VRAM; @@ -751,31 +830,30 @@ static struct radeon_state *r600_db(struct r600_context *rctx) pitch = (rtex->pitch[level] / rtex->bpt) / 8 - 1; slice = (rtex->pitch[level] / rtex->bpt) * state->zsbuf->height / 64 - 1; format = r600_translate_dbformat(state->zsbuf->texture->format); - rstate->states[R600_DB__DB_DEPTH_BASE] = 0x00000000; - rstate->states[R600_DB__DB_DEPTH_INFO] = 0x00010000 | + rstate->states[R600_DB__DB_DEPTH_BASE] = state->zsbuf->offset >> 8; + rstate->states[R600_DB__DB_DEPTH_INFO] = S_028010_ARRAY_MODE(rtex->array_mode) | S_028010_FORMAT(format); rstate->states[R600_DB__DB_DEPTH_VIEW] = 0x00000000; rstate->states[R600_DB__DB_PREFETCH_LIMIT] = (state->zsbuf->height / 8) -1; rstate->states[R600_DB__DB_DEPTH_SIZE] = S_028000_PITCH_TILE_MAX(pitch) | S_028000_SLICE_TILE_MAX(slice); - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; - } - return rstate; + radeon_state_pm4(rstate); } -static struct radeon_state *r600_rasterizer(struct r600_context *rctx) +static void r600_rasterizer(struct r600_context *rctx, struct radeon_state *rstate) { const struct pipe_rasterizer_state *state = &rctx->rasterizer->state.rasterizer; const struct pipe_framebuffer_state *fb = &rctx->framebuffer->state.framebuffer; + const struct pipe_clip_state *clip = NULL; struct r600_screen *rscreen = rctx->screen; - struct radeon_state *rstate; float offset_units = 0, offset_scale = 0; char depth = 0; unsigned offset_db_fmt_cntl = 0; unsigned tmp; unsigned prov_vtx = 1; + + if (rctx->clip) + clip = &rctx->clip->state.clip; if (fb->zsbuf) { offset_units = state->offset_units; offset_scale = state->offset_scale * 12.0f; @@ -796,7 +874,7 @@ static struct radeon_state *r600_rasterizer(struct r600_context *rctx) break; default: R600_ERR("unsupported %d\n", fb->zsbuf->texture->format); - return NULL; + return; } } offset_db_fmt_cntl |= S_028DF8_POLY_OFFSET_NEG_NUM_DB_BITS(depth); @@ -805,9 +883,7 @@ static struct radeon_state *r600_rasterizer(struct r600_context *rctx) prov_vtx = 0; rctx->flat_shade = state->flatshade; - rstate = radeon_state(rscreen->rw, R600_RASTERIZER_TYPE, R600_RASTERIZER); - if (rstate == NULL) - return NULL; + radeon_state_init(rstate, rscreen->rw, R600_STATE_RASTERIZER, 0, 0); rstate->states[R600_RASTERIZER__SPI_INTERP_CONTROL_0] = 0x00000001; if (state->sprite_coord_enable) { rstate->states[R600_RASTERIZER__SPI_INTERP_CONTROL_0] |= @@ -821,7 +897,12 @@ static struct radeon_state *r600_rasterizer(struct r600_context *rctx) S_0286D4_PNT_SPRITE_TOP_1(1); } } - rstate->states[R600_RASTERIZER__PA_CL_CLIP_CNTL] = 0x00000000; + rstate->states[R600_RASTERIZER__PA_CL_CLIP_CNTL] = 0; + if (clip) { + rstate->states[R600_RASTERIZER__PA_CL_CLIP_CNTL] = S_028810_PS_UCP_MODE(3) | ((1 << clip->nr) - 1); + rstate->states[R600_RASTERIZER__PA_CL_CLIP_CNTL] |= S_028810_ZCLIP_NEAR_DISABLE(clip->depth_clamp); + rstate->states[R600_RASTERIZER__PA_CL_CLIP_CNTL] |= S_028810_ZCLIP_FAR_DISABLE(clip->depth_clamp); + } rstate->states[R600_RASTERIZER__PA_SU_SC_MODE_CNTL] = S_028814_PROVOKING_VTX_LAST(prov_vtx) | S_028814_CULL_FRONT((state->cull_face & PIPE_FACE_FRONT) ? 1 : 0) | @@ -835,7 +916,7 @@ static struct radeon_state *r600_rasterizer(struct r600_context *rctx) S_02881C_VS_OUT_MISC_VEC_ENA(state->point_size_per_vertex); rstate->states[R600_RASTERIZER__PA_CL_NANINF_CNTL] = 0x00000000; /* point size 12.4 fixed point */ - tmp = (unsigned)(state->point_size * 8.0 / 2.0); + tmp = (unsigned)(state->point_size * 8.0); rstate->states[R600_RASTERIZER__PA_SU_POINT_SIZE] = S_028A00_HEIGHT(tmp) | S_028A00_WIDTH(tmp); rstate->states[R600_RASTERIZER__PA_SU_POINT_MINMAX] = 0x80000000; rstate->states[R600_RASTERIZER__PA_SU_LINE_CNTL] = 0x00000008; @@ -852,19 +933,14 @@ static struct radeon_state *r600_rasterizer(struct r600_context *rctx) rstate->states[R600_RASTERIZER__PA_SU_POLY_OFFSET_FRONT_OFFSET] = fui(offset_units); rstate->states[R600_RASTERIZER__PA_SU_POLY_OFFSET_BACK_SCALE] = fui(offset_scale); rstate->states[R600_RASTERIZER__PA_SU_POLY_OFFSET_BACK_OFFSET] = fui(offset_units); - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; - } - return rstate; + radeon_state_pm4(rstate); } -static struct radeon_state *r600_scissor(struct r600_context *rctx) +static void r600_scissor(struct r600_context *rctx, struct radeon_state *rstate) { const struct pipe_scissor_state *state = &rctx->scissor->state.scissor; const struct pipe_framebuffer_state *fb = &rctx->framebuffer->state.framebuffer; struct r600_screen *rscreen = rctx->screen; - struct radeon_state *rstate; unsigned minx, maxx, miny, maxy; u32 tl, br; @@ -881,9 +957,7 @@ static struct radeon_state *r600_scissor(struct r600_context *rctx) } tl = S_028240_TL_X(minx) | S_028240_TL_Y(miny) | S_028240_WINDOW_OFFSET_DISABLE(1); br = S_028244_BR_X(maxx) | S_028244_BR_Y(maxy); - rstate = radeon_state(rscreen->rw, R600_SCISSOR_TYPE, R600_SCISSOR); - if (rstate == NULL) - return NULL; + radeon_state_init(rstate, rscreen->rw, R600_STATE_SCISSOR, 0, 0); rstate->states[R600_SCISSOR__PA_SC_SCREEN_SCISSOR_TL] = tl; rstate->states[R600_SCISSOR__PA_SC_SCREEN_SCISSOR_BR] = br; rstate->states[R600_SCISSOR__PA_SC_WINDOW_OFFSET] = 0x00000000; @@ -903,22 +977,14 @@ static struct radeon_state *r600_scissor(struct r600_context *rctx) rstate->states[R600_SCISSOR__PA_SC_GENERIC_SCISSOR_BR] = br; rstate->states[R600_SCISSOR__PA_SC_VPORT_SCISSOR_0_TL] = tl; rstate->states[R600_SCISSOR__PA_SC_VPORT_SCISSOR_0_BR] = br; - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; - } - return rstate; + radeon_state_pm4(rstate); } -static struct radeon_state *r600_viewport(struct r600_context *rctx) +static void r600_viewport(struct r600_context *rctx, struct radeon_state *rstate, const struct pipe_viewport_state *state) { - const struct pipe_viewport_state *state = &rctx->viewport->state.viewport; struct r600_screen *rscreen = rctx->screen; - struct radeon_state *rstate; - rstate = radeon_state(rscreen->rw, R600_VIEWPORT_TYPE, R600_VIEWPORT); - if (rstate == NULL) - return NULL; + radeon_state_init(rstate, rscreen->rw, R600_STATE_VIEWPORT, 0, 0); rstate->states[R600_VIEWPORT__PA_SC_VPORT_ZMIN_0] = 0x00000000; rstate->states[R600_VIEWPORT__PA_SC_VPORT_ZMAX_0] = 0x3F800000; rstate->states[R600_VIEWPORT__PA_CL_VPORT_XSCALE_0] = fui(state->scale[0]); @@ -928,29 +994,28 @@ static struct radeon_state *r600_viewport(struct r600_context *rctx) rstate->states[R600_VIEWPORT__PA_CL_VPORT_YOFFSET_0] = fui(state->translate[1]); rstate->states[R600_VIEWPORT__PA_CL_VPORT_ZOFFSET_0] = fui(state->translate[2]); rstate->states[R600_VIEWPORT__PA_CL_VTE_CNTL] = 0x0000043F; - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; - } - return rstate; + radeon_state_pm4(rstate); } -static struct radeon_state *r600_dsa(struct r600_context *rctx) +static void r600_dsa(struct r600_context *rctx, struct radeon_state *rstate) { const struct pipe_depth_stencil_alpha_state *state = &rctx->dsa->state.dsa; const struct pipe_stencil_ref *stencil_ref = &rctx->stencil_ref->state.stencil_ref; struct r600_screen *rscreen = rctx->screen; unsigned db_depth_control, alpha_test_control, alpha_ref, db_shader_control; unsigned stencil_ref_mask, stencil_ref_mask_bf; - struct r600_shader *rshader = &rctx->ps_shader->shader; - struct radeon_state *rstate; + struct r600_shader *rshader; int i; - rstate = radeon_state(rscreen->rw, R600_DSA_TYPE, R600_DSA); - if (rstate == NULL) - return NULL; + if (rctx->ps_shader == NULL) { + return; + } + radeon_state_init(rstate, rscreen->rw, R600_STATE_DSA, 0, 0); db_shader_control = 0x210; + rshader = &rctx->ps_shader->shader; + if (rshader->uses_kill) + db_shader_control |= (1 << 6); for (i = 0; i < rshader->noutput; i++) { if (rshader->output[i].name == TGSI_SEMANTIC_POSITION) db_shader_control |= 1; @@ -1008,11 +1073,7 @@ static struct radeon_state *r600_dsa(struct r600_context *rctx) rstate->states[R600_DSA__DB_SRESULTS_COMPARE_STATE1] = 0x00000000; rstate->states[R600_DSA__DB_PRELOAD_CONTROL] = 0x00000000; rstate->states[R600_DSA__DB_ALPHA_TO_MASK] = 0x0000AA00; - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; - } - return rstate; + radeon_state_pm4(rstate); } static inline unsigned r600_tex_wrap(unsigned wrap) @@ -1090,16 +1151,12 @@ static INLINE u32 S_FIXED(float value, u32 frac_bits) return value * (1 << frac_bits); } -static struct radeon_state *r600_sampler(struct r600_context *rctx, - const struct pipe_sampler_state *state, - unsigned id) +static void r600_sampler(struct r600_context *rctx, struct radeon_state *rstate, + const struct pipe_sampler_state *state, unsigned id) { struct r600_screen *rscreen = rctx->screen; - struct radeon_state *rstate; - rstate = radeon_state(rscreen->rw, R600_PS_SAMPLER_TYPE, id); - if (rstate == NULL) - return NULL; + radeon_state_init(rstate, rscreen->rw, R600_STATE_SAMPLER, id, R600_SHADER_PS); rstate->states[R600_PS_SAMPLER__SQ_TEX_SAMPLER_WORD0_0] = S_03C000_CLAMP_X(r600_tex_wrap(state->wrap_s)) | S_03C000_CLAMP_Y(r600_tex_wrap(state->wrap_t)) | @@ -1114,11 +1171,7 @@ static struct radeon_state *r600_sampler(struct r600_context *rctx, S_03C004_MAX_LOD(S_FIXED(CLAMP(state->max_lod, 0, 15), 6)) | S_03C004_LOD_BIAS(S_FIXED(CLAMP(state->lod_bias, -16, 16), 6)); rstate->states[R600_PS_SAMPLER__SQ_TEX_SAMPLER_WORD2_0] = S_03C008_TYPE(1); - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; - } - return rstate; + radeon_state_pm4(rstate); } static inline unsigned r600_tex_swizzle(unsigned swizzle) @@ -1160,6 +1213,7 @@ static inline unsigned r600_tex_dim(unsigned dim) case PIPE_TEXTURE_1D: return V_038000_SQ_TEX_DIM_1D; case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: return V_038000_SQ_TEX_DIM_2D; case PIPE_TEXTURE_3D: return V_038000_SQ_TEX_DIM_3D; @@ -1168,19 +1222,20 @@ static inline unsigned r600_tex_dim(unsigned dim) } } -static struct radeon_state *r600_resource(struct r600_context *rctx, - const struct pipe_sampler_view *view, - unsigned id) +static void r600_resource(struct pipe_context *ctx, struct radeon_state *rstate, + const struct pipe_sampler_view *view, unsigned id) { + struct r600_context *rctx = r600_context(ctx); struct r600_screen *rscreen = rctx->screen; const struct util_format_description *desc; struct r600_resource_texture *tmp; struct r600_resource *rbuffer; - struct radeon_state *rstate; unsigned format; - uint32_t word4 = 0, yuv_format = 0; - unsigned char swizzle[4]; + uint32_t word4 = 0, yuv_format = 0, pitch = 0; + unsigned char swizzle[4], array_mode = 0, tile_type = 0; + int r; + rstate->cpm4 = 0; swizzle[0] = view->swizzle_r; swizzle[1] = view->swizzle_g; swizzle[2] = view->swizzle_b; @@ -1188,37 +1243,49 @@ static struct radeon_state *r600_resource(struct r600_context *rctx, format = r600_translate_texformat(view->texture->format, swizzle, &word4, &yuv_format); - if (format == ~0) - return NULL; + if (format == ~0) { + return; + } desc = util_format_description(view->texture->format); if (desc == NULL) { R600_ERR("unknow format %d\n", view->texture->format); - return NULL; - } - rstate = radeon_state(rscreen->rw, R600_PS_RESOURCE_TYPE, id); - if (rstate == NULL) { - return NULL; + return; } + radeon_state_init(rstate, rscreen->rw, R600_STATE_RESOURCE, id, R600_SHADER_PS); tmp = (struct r600_resource_texture*)view->texture; rbuffer = &tmp->resource; - rstate->bo[0] = radeon_bo_incref(rscreen->rw, rbuffer->bo); - rstate->bo[1] = radeon_bo_incref(rscreen->rw, rbuffer->bo); + if (tmp->depth) { + r = r600_texture_from_depth(ctx, tmp, view->first_level); + if (r) { + return; + } + rstate->bo[0] = radeon_bo_incref(rscreen->rw, tmp->uncompressed); + rstate->bo[1] = radeon_bo_incref(rscreen->rw, tmp->uncompressed); + } else { + rstate->bo[0] = radeon_bo_incref(rscreen->rw, rbuffer->bo); + rstate->bo[1] = radeon_bo_incref(rscreen->rw, rbuffer->bo); + } rstate->nbo = 2; rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; rstate->placement[1] = RADEON_GEM_DOMAIN_GTT; rstate->placement[2] = RADEON_GEM_DOMAIN_GTT; rstate->placement[3] = RADEON_GEM_DOMAIN_GTT; + pitch = (tmp->pitch[0] / tmp->bpt); + pitch = (pitch + 0x7) & ~0x7; + /* FIXME properly handle first level != 0 */ rstate->states[R600_PS_RESOURCE__RESOURCE0_WORD0] = S_038000_DIM(r600_tex_dim(view->texture->target)) | - S_038000_PITCH(((tmp->pitch[0] / tmp->bpt) / 8) - 1) | + S_038000_TILE_MODE(array_mode) | + S_038000_TILE_TYPE(tile_type) | + S_038000_PITCH((pitch / 8) - 1) | S_038000_TEX_WIDTH(view->texture->width0 - 1); rstate->states[R600_PS_RESOURCE__RESOURCE0_WORD1] = S_038004_TEX_HEIGHT(view->texture->height0 - 1) | S_038004_TEX_DEPTH(view->texture->depth0 - 1) | S_038004_DATA_FORMAT(format); - rstate->states[R600_PS_RESOURCE__RESOURCE0_WORD2] = 0; + rstate->states[R600_PS_RESOURCE__RESOURCE0_WORD2] = tmp->offset[0] >> 8; rstate->states[R600_PS_RESOURCE__RESOURCE0_WORD3] = tmp->offset[1] >> 8; rstate->states[R600_PS_RESOURCE__RESOURCE0_WORD4] = word4 | @@ -1232,17 +1299,12 @@ static struct radeon_state *r600_resource(struct r600_context *rctx, S_038014_LAST_ARRAY(0); rstate->states[R600_PS_RESOURCE__RESOURCE0_WORD6] = S_038018_TYPE(V_038010_SQ_TEX_VTX_VALID_TEXTURE); - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; - } - return rstate; + radeon_state_pm4(rstate); } -static struct radeon_state *r600_cb_cntl(struct r600_context *rctx) +static void r600_cb_cntl(struct r600_context *rctx, struct radeon_state *rstate) { struct r600_screen *rscreen = rctx->screen; - struct radeon_state *rstate; const struct pipe_blend_state *pbs = &rctx->blend->state.blend; int nr_cbufs = rctx->framebuffer->state.framebuffer.nr_cbufs; uint32_t color_control, target_mask, shader_mask; @@ -1257,7 +1319,7 @@ static struct radeon_state *r600_cb_cntl(struct r600_context *rctx) } if (pbs->logicop_enable) { - color_control |= (pbs->logicop_func) << 16; + color_control |= (pbs->logicop_func << 16) | (pbs->logicop_func << 20); } else { color_control |= (0xcc << 16); } @@ -1277,7 +1339,7 @@ static struct radeon_state *r600_cb_cntl(struct r600_context *rctx) target_mask |= (pbs->rt[0].colormask << (4 * i)); } } - rstate = radeon_state(rscreen->rw, R600_CB_CNTL_TYPE, R600_CB_CNTL); + radeon_state_init(rstate, rscreen->rw, R600_STATE_CB_CNTL, 0, 0); rstate->states[R600_CB_CNTL__CB_SHADER_MASK] = shader_mask; rstate->states[R600_CB_CNTL__CB_TARGET_MASK] = target_mask; rstate->states[R600_CB_CNTL__CB_COLOR_CONTROL] = color_control; @@ -1289,115 +1351,51 @@ static struct radeon_state *r600_cb_cntl(struct r600_context *rctx) rstate->states[R600_CB_CNTL__CB_CLRCMP_DST] = 0x000000FF; rstate->states[R600_CB_CNTL__CB_CLRCMP_MSK] = 0xFFFFFFFF; rstate->states[R600_CB_CNTL__PA_SC_AA_MASK] = 0xFFFFFFFF; - if (radeon_state_pm4(rstate)) { - radeon_state_decref(rstate); - return NULL; - } - return rstate; + radeon_state_pm4(rstate); } -int r600_context_hw_states(struct r600_context *rctx) +int r600_context_hw_states(struct pipe_context *ctx) { + struct r600_context *rctx = r600_context(ctx); unsigned i; - int r; - int nr_cbufs = rctx->framebuffer->state.framebuffer.nr_cbufs; - /* free previous TODO determine what need to be updated, what - * doesn't - */ - //radeon_state_decref(rctx->hw_states.config); - rctx->hw_states.cb_cntl = radeon_state_decref(rctx->hw_states.cb_cntl); - rctx->hw_states.db = radeon_state_decref(rctx->hw_states.db); - rctx->hw_states.rasterizer = radeon_state_decref(rctx->hw_states.rasterizer); - rctx->hw_states.scissor = radeon_state_decref(rctx->hw_states.scissor); - rctx->hw_states.dsa = radeon_state_decref(rctx->hw_states.dsa); - rctx->hw_states.blend = radeon_state_decref(rctx->hw_states.blend); - rctx->hw_states.viewport = radeon_state_decref(rctx->hw_states.viewport); - for (i = 0; i < 8; i++) { - rctx->hw_states.cb[i] = radeon_state_decref(rctx->hw_states.cb[i]); + /* build new states */ + r600_rasterizer(rctx, &rctx->hw_states.rasterizer); + r600_scissor(rctx, &rctx->hw_states.scissor); + r600_dsa(rctx, &rctx->hw_states.dsa); + r600_cb_cntl(rctx, &rctx->hw_states.cb_cntl); + + /* bind states */ + radeon_draw_bind(&rctx->draw, &rctx->hw_states.rasterizer); + radeon_draw_bind(&rctx->draw, &rctx->hw_states.scissor); + radeon_draw_bind(&rctx->draw, &rctx->hw_states.dsa); + radeon_draw_bind(&rctx->draw, &rctx->hw_states.cb_cntl); + + radeon_draw_bind(&rctx->draw, &rctx->config); + + if (rctx->viewport) { + radeon_draw_bind(&rctx->draw, &rctx->viewport->rstate[0]); } - for (i = 0; i < rctx->hw_states.ps_nresource; i++) { - radeon_state_decref(rctx->hw_states.ps_resource[i]); - rctx->hw_states.ps_resource[i] = NULL; + if (rctx->blend) { + radeon_draw_bind(&rctx->draw, &rctx->blend->rstate[0]); } - rctx->hw_states.ps_nresource = 0; - for (i = 0; i < rctx->hw_states.ps_nsampler; i++) { - radeon_state_decref(rctx->hw_states.ps_sampler[i]); - rctx->hw_states.ps_sampler[i] = NULL; + if (rctx->clip) { + radeon_draw_bind(&rctx->draw, &rctx->clip->rstate[0]); } - rctx->hw_states.ps_nsampler = 0; - - /* build new states */ - rctx->hw_states.rasterizer = r600_rasterizer(rctx); - rctx->hw_states.scissor = r600_scissor(rctx); - rctx->hw_states.dsa = r600_dsa(rctx); - rctx->hw_states.blend = r600_blend(rctx); - rctx->hw_states.viewport = r600_viewport(rctx); - for (i = 0; i < nr_cbufs; i++) { - rctx->hw_states.cb[i] = r600_cb(rctx, i); + for (i = 0; i < rctx->framebuffer->state.framebuffer.nr_cbufs; i++) { + radeon_draw_bind(&rctx->draw, &rctx->framebuffer->rstate[i+1]); + } + if (rctx->framebuffer->state.framebuffer.zsbuf) { + radeon_draw_bind(&rctx->draw, &rctx->framebuffer->rstate[0]); } - rctx->hw_states.db = r600_db(rctx); - rctx->hw_states.cb_cntl = r600_cb_cntl(rctx); - for (i = 0; i < rctx->ps_nsampler; i++) { if (rctx->ps_sampler[i]) { - rctx->hw_states.ps_sampler[i] = r600_sampler(rctx, - &rctx->ps_sampler[i]->state.sampler, - R600_PS_SAMPLER + i); + radeon_draw_bind(&rctx->draw, rctx->ps_sampler[i]); } } - rctx->hw_states.ps_nsampler = rctx->ps_nsampler; for (i = 0; i < rctx->ps_nsampler_view; i++) { if (rctx->ps_sampler_view[i]) { - rctx->hw_states.ps_resource[i] = r600_resource(rctx, - &rctx->ps_sampler_view[i]->state.sampler_view, - R600_PS_RESOURCE + i); - } - } - rctx->hw_states.ps_nresource = rctx->ps_nsampler_view; - - /* bind states */ - r = radeon_draw_set(rctx->draw, rctx->hw_states.db); - if (r) - return r; - r = radeon_draw_set(rctx->draw, rctx->hw_states.rasterizer); - if (r) - return r; - r = radeon_draw_set(rctx->draw, rctx->hw_states.scissor); - if (r) - return r; - r = radeon_draw_set(rctx->draw, rctx->hw_states.dsa); - if (r) - return r; - r = radeon_draw_set(rctx->draw, rctx->hw_states.blend); - if (r) - return r; - r = radeon_draw_set(rctx->draw, rctx->hw_states.viewport); - if (r) - return r; - for (i = 0; i < nr_cbufs; i++) { - r = radeon_draw_set(rctx->draw, rctx->hw_states.cb[i]); - if (r) - return r; - } - r = radeon_draw_set(rctx->draw, rctx->hw_states.config); - if (r) - return r; - r = radeon_draw_set(rctx->draw, rctx->hw_states.cb_cntl); - if (r) - return r; - for (i = 0; i < rctx->hw_states.ps_nresource; i++) { - if (rctx->hw_states.ps_resource[i]) { - r = radeon_draw_set(rctx->draw, rctx->hw_states.ps_resource[i]); - if (r) - return r; - } - } - for (i = 0; i < rctx->hw_states.ps_nsampler; i++) { - if (rctx->hw_states.ps_sampler[i]) { - r = radeon_draw_set(rctx->draw, rctx->hw_states.ps_sampler[i]); - if (r) - return r; + radeon_draw_bind(&rctx->draw, rctx->ps_sampler_view[i]); } } return 0; diff --git a/src/gallium/drivers/r600/r600_state_inlines.h b/src/gallium/drivers/r600/r600_state_inlines.h index f93c20da35..84866825aa 100644 --- a/src/gallium/drivers/r600/r600_state_inlines.h +++ b/src/gallium/drivers/r600/r600_state_inlines.h @@ -252,6 +252,7 @@ static INLINE uint32_t r600_translate_colorformat(enum pipe_format format) case PIPE_FORMAT_R8SG8SB8UX8U_NORM: case PIPE_FORMAT_X8B8G8R8_UNORM: case PIPE_FORMAT_X8R8G8B8_UNORM: + case PIPE_FORMAT_R8G8B8_UNORM: return V_0280A0_COLOR_8_8_8_8; case PIPE_FORMAT_R10G10B10A2_UNORM: @@ -262,7 +263,10 @@ static INLINE uint32_t r600_translate_colorformat(enum pipe_format format) case PIPE_FORMAT_Z24X8_UNORM: case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - return V_0280A0_COLOR_24_8; + return V_0280A0_COLOR_8_24; + + case PIPE_FORMAT_R32_FLOAT: + return V_0280A0_COLOR_32_FLOAT; /* 64-bit buffers. */ case PIPE_FORMAT_R16G16B16A16_UNORM: @@ -275,6 +279,7 @@ static INLINE uint32_t r600_translate_colorformat(enum pipe_format format) /* 128-bit buffers. */ case PIPE_FORMAT_R32G32B32_FLOAT: + return V_0280A0_COLOR_32_32_32_FLOAT; case PIPE_FORMAT_R32G32B32A32_FLOAT: return V_0280A0_COLOR_32_32_32_32_FLOAT; diff --git a/src/gallium/drivers/r600/r600_texture.c b/src/gallium/drivers/r600/r600_texture.c index 30d79ebdd6..b6698e3885 100644 --- a/src/gallium/drivers/r600/r600_texture.c +++ b/src/gallium/drivers/r600/r600_texture.c @@ -24,6 +24,7 @@ * Jerome Glisse * Corbin Simpson */ +#include <errno.h> #include <pipe/p_screen.h> #include <util/u_format.h> #include <util/u_math.h> @@ -33,10 +34,26 @@ #include "r600_screen.h" #include "r600_context.h" #include "r600_resource.h" +#include "r600_state_inlines.h" #include "r600d.h" extern struct u_resource_vtbl r600_texture_vtbl; +/* Copy from a tiled texture to a detiled one. */ +static void r600_copy_from_tiled_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) +{ + struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; + struct pipe_resource *texture = transfer->resource; + struct pipe_subresource subdst; + + subdst.face = 0; + subdst.level = 0; + ctx->resource_copy_region(ctx, rtransfer->linear_texture, + subdst, 0, 0, 0, texture, transfer->sr, + transfer->box.x, transfer->box.y, transfer->box.z, + transfer->box.width, transfer->box.height); +} + static unsigned long r600_texture_get_offset(struct r600_resource_texture *rtex, unsigned level, unsigned zslice, unsigned face) @@ -65,7 +82,9 @@ static void r600_setup_miptree(struct r600_screen *rscreen, struct r600_resource for (i = 0, offset = 0; i <= ptex->last_level; i++) { w = u_minify(ptex->width0, i); h = u_minify(ptex->height0, i); + h = util_next_power_of_two(h); pitch = util_format_get_stride(ptex->format, align(w, 64)); + pitch = align(pitch, 256); layer_size = pitch * h; if (ptex->target == PIPE_TEXTURE_CUBE) size = layer_size * 6; @@ -74,6 +93,8 @@ static void r600_setup_miptree(struct r600_screen *rscreen, struct r600_resource rtex->offset[i] = offset; rtex->layer_size[i] = layer_size; rtex->pitch[i] = pitch; + rtex->width[i] = w; + rtex->height[i] = h; offset += size; } rtex->size = offset; @@ -104,10 +125,22 @@ struct pipe_resource *r600_texture_create(struct pipe_screen *screen, FREE(rtex); return NULL; } - return &resource->base.b; } +static void r600_texture_destroy_state(struct pipe_resource *ptexture) +{ + struct r600_resource_texture *rtexture = (struct r600_resource_texture*)ptexture; + + for (int i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++) { + radeon_state_fini(&rtexture->scissor[i]); + radeon_state_fini(&rtexture->db[i]); + for (int j = 0; j < 8; j++) { + radeon_state_fini(&rtexture->cb[j][i]); + } + } +} + static void r600_texture_destroy(struct pipe_screen *screen, struct pipe_resource *ptex) { @@ -118,6 +151,10 @@ static void r600_texture_destroy(struct pipe_screen *screen, if (resource->bo) { radeon_bo_decref(rscreen->rw, resource->bo); } + if (rtex->uncompressed) { + radeon_bo_decref(rscreen->rw, rtex->uncompressed); + } + r600_texture_destroy_state(ptex); FREE(rtex); } @@ -168,7 +205,8 @@ struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, } /* Support only 2D textures without mipmaps */ - if (templ->target != PIPE_TEXTURE_2D || templ->depth0 != 1 || templ->last_level != 0) + if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) || + templ->depth0 != 1 || templ->last_level != 0) return NULL; rtex = CALLOC_STRUCT(r600_resource_texture); @@ -181,9 +219,12 @@ struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, pipe_reference_init(&resource->base.b.reference, 1); resource->base.b.screen = screen; resource->bo = bo; + rtex->depth = 0; rtex->pitch_override = whandle->stride; rtex->bpt = util_format_get_blocksize(templ->format); rtex->pitch[0] = whandle->stride; + rtex->width[0] = templ->width0; + rtex->height[0] = templ->height0; rtex->offset[0] = 0; rtex->size = align(rtex->pitch[0] * templ->height0, 64); @@ -205,6 +246,7 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, const struct pipe_box *box) { struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; + struct pipe_resource resource; struct r600_transfer *trans; trans = CALLOC_STRUCT(r600_transfer); @@ -216,48 +258,117 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, trans->transfer.box = *box; trans->transfer.stride = rtex->pitch[sr.level]; trans->offset = r600_texture_get_offset(rtex, sr.level, box->z, sr.face); + if (rtex->tilled && !rtex->depth) { + resource.target = PIPE_TEXTURE_2D; + resource.format = texture->format; + resource.width0 = box->width; + resource.height0 = box->height; + resource.depth0 = 0; + resource.last_level = 0; + resource.nr_samples = 0; + resource.usage = PIPE_USAGE_DYNAMIC; + resource.bind = 0; + resource.flags = 0; + /* For texture reading, the temporary (detiled) texture is used as + * a render target when blitting from a tiled texture. */ + if (usage & PIPE_TRANSFER_READ) { + resource.bind |= PIPE_BIND_RENDER_TARGET; + } + /* For texture writing, the temporary texture is used as a sampler + * when blitting into a tiled texture. */ + if (usage & PIPE_TRANSFER_WRITE) { + resource.bind |= PIPE_BIND_SAMPLER_VIEW; + } + /* Create the temporary texture. */ + trans->linear_texture = ctx->screen->resource_create(ctx->screen, &resource); + if (trans->linear_texture == NULL) { + R600_ERR("failed to create temporary texture to hold untiled copy\n"); + pipe_resource_reference(&trans->transfer.resource, NULL); + FREE(trans); + return NULL; + } + if (usage & PIPE_TRANSFER_READ) { + /* We cannot map a tiled texture directly because the data is + * in a different order, therefore we do detiling using a blit. */ + r600_copy_from_tiled_texture(ctx, trans); + /* Always referenced in the blit. */ + ctx->flush(ctx, 0, NULL); + } + } return &trans->transfer; } void r600_texture_transfer_destroy(struct pipe_context *ctx, - struct pipe_transfer *trans) + struct pipe_transfer *transfer) { - pipe_resource_reference(&trans->resource, NULL); - FREE(trans); + struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; + + if (rtransfer->linear_texture) { + pipe_resource_reference(&rtransfer->linear_texture, NULL); + } + pipe_resource_reference(&transfer->resource, NULL); + FREE(transfer); } void* r600_texture_transfer_map(struct pipe_context *ctx, struct pipe_transfer* transfer) { struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; - struct r600_resource *resource; + struct radeon_bo *bo; enum pipe_format format = transfer->resource->format; struct r600_screen *rscreen = r600_screen(ctx->screen); + struct r600_resource_texture *rtex; + unsigned long offset = 0; char *map; + int r; r600_flush(ctx, 0, NULL); - - resource = (struct r600_resource *)transfer->resource; - if (radeon_bo_map(rscreen->rw, resource->bo)) { + if (rtransfer->linear_texture) { + bo = ((struct r600_resource *)rtransfer->linear_texture)->bo; + } else { + rtex = (struct r600_resource_texture*)transfer->resource; + if (rtex->depth) { + r = r600_texture_from_depth(ctx, rtex, transfer->sr.level); + if (r) { + return NULL; + } + r600_flush(ctx, 0, NULL); + bo = rtex->uncompressed; + } else { + bo = ((struct r600_resource *)transfer->resource)->bo; + } + offset = rtransfer->offset + + transfer->box.y / util_format_get_blockheight(format) * transfer->stride + + transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); + } + if (radeon_bo_map(rscreen->rw, bo)) { return NULL; } - radeon_bo_wait(rscreen->rw, resource->bo); - - map = resource->bo->data; + radeon_bo_wait(rscreen->rw, bo); - return map + rtransfer->offset + - transfer->box.y / util_format_get_blockheight(format) * transfer->stride + - transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); + map = bo->data; + return map + offset; } void r600_texture_transfer_unmap(struct pipe_context *ctx, struct pipe_transfer* transfer) { + struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; struct r600_screen *rscreen = r600_screen(ctx->screen); - struct r600_resource *resource; - - resource = (struct r600_resource *)transfer->resource; - radeon_bo_unmap(rscreen->rw, resource->bo); + struct r600_resource_texture *rtex; + struct radeon_bo *bo; + + if (rtransfer->linear_texture) { + bo = ((struct r600_resource *)rtransfer->linear_texture)->bo; + } else { + rtex = (struct r600_resource_texture*)transfer->resource; + if (rtex->depth) { + bo = rtex->uncompressed; + } else { + bo = ((struct r600_resource *)transfer->resource)->bo; + } + } + radeon_bo_unmap(rscreen->rw, bo); } struct u_resource_vtbl r600_texture_vtbl = @@ -280,51 +391,51 @@ void r600_init_screen_texture_functions(struct pipe_screen *screen) } static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format, - const unsigned char *swizzle_view) + const unsigned char *swizzle_view) { - unsigned i; - unsigned char swizzle[4]; - unsigned result = 0; - const uint32_t swizzle_shift[4] = { - 16, 19, 22, 25, - }; - const uint32_t swizzle_bit[4] = { - 0, 1, 2, 3, - }; - - if (swizzle_view) { - /* Combine two sets of swizzles. */ - for (i = 0; i < 4; i++) { - swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ? - swizzle_format[swizzle_view[i]] : swizzle_view[i]; - } - } else { - memcpy(swizzle, swizzle_format, 4); - } - - /* Get swizzle. */ - for (i = 0; i < 4; i++) { - switch (swizzle[i]) { - case UTIL_FORMAT_SWIZZLE_Y: - result |= swizzle_bit[1] << swizzle_shift[i]; - break; - case UTIL_FORMAT_SWIZZLE_Z: - result |= swizzle_bit[2] << swizzle_shift[i]; - break; - case UTIL_FORMAT_SWIZZLE_W: - result |= swizzle_bit[3] << swizzle_shift[i]; - break; - case UTIL_FORMAT_SWIZZLE_0: - result |= V_038010_SQ_SEL_0 << swizzle_shift[i]; - break; - case UTIL_FORMAT_SWIZZLE_1: - result |= V_038010_SQ_SEL_1 << swizzle_shift[i]; - break; - default: /* UTIL_FORMAT_SWIZZLE_X */ - result |= swizzle_bit[0] << swizzle_shift[i]; - } - } - return result; + unsigned i; + unsigned char swizzle[4]; + unsigned result = 0; + const uint32_t swizzle_shift[4] = { + 16, 19, 22, 25, + }; + const uint32_t swizzle_bit[4] = { + 0, 1, 2, 3, + }; + + if (swizzle_view) { + /* Combine two sets of swizzles. */ + for (i = 0; i < 4; i++) { + swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ? + swizzle_format[swizzle_view[i]] : swizzle_view[i]; + } + } else { + memcpy(swizzle, swizzle_format, 4); + } + + /* Get swizzle. */ + for (i = 0; i < 4; i++) { + switch (swizzle[i]) { + case UTIL_FORMAT_SWIZZLE_Y: + result |= swizzle_bit[1] << swizzle_shift[i]; + break; + case UTIL_FORMAT_SWIZZLE_Z: + result |= swizzle_bit[2] << swizzle_shift[i]; + break; + case UTIL_FORMAT_SWIZZLE_W: + result |= swizzle_bit[3] << swizzle_shift[i]; + break; + case UTIL_FORMAT_SWIZZLE_0: + result |= V_038010_SQ_SEL_0 << swizzle_shift[i]; + break; + case UTIL_FORMAT_SWIZZLE_1: + result |= V_038010_SQ_SEL_1 << swizzle_shift[i]; + break; + default: /* UTIL_FORMAT_SWIZZLE_X */ + result |= swizzle_bit[0] << swizzle_shift[i]; + } + } + return result; } /* texture format translate */ @@ -344,19 +455,21 @@ uint32_t r600_translate_texformat(enum pipe_format format, }; desc = util_format_description(format); + word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view); + /* Colorspace (return non-RGB formats directly). */ switch (desc->colorspace) { /* Depth stencil formats */ case UTIL_FORMAT_COLORSPACE_ZS: switch (format) { case PIPE_FORMAT_Z16_UNORM: - result = V_028010_DEPTH_16; + result = V_0280A0_COLOR_16; goto out_word4; case PIPE_FORMAT_Z24X8_UNORM: - result = V_028010_DEPTH_X8_24; + result = V_0280A0_COLOR_8_24; goto out_word4; case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - result = V_028010_DEPTH_8_24; + result = V_0280A0_COLOR_8_24; goto out_word4; default: goto out_unknown; @@ -382,8 +495,6 @@ uint32_t r600_translate_texformat(enum pipe_format format, break; } - word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view); - /* S3TC formats. TODO */ if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { goto out_unknown; @@ -519,9 +630,221 @@ out_word4: *word4_p = word4; if (yuv_format_p) *yuv_format_p = yuv_format; -// fprintf(stderr,"returning %08x %08x %08x\n", result, word4, yuv_format); return result; out_unknown: // R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format)); return ~0; } + +int r600_texture_from_depth(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level) +{ + struct r600_screen *rscreen = r600_screen(ctx->screen); + int r; + + if (!rtexture->depth) { + /* This shouldn't happen maybe print a warning */ + return 0; + } + if (rtexture->uncompressed && !rtexture->dirty) { + /* Uncompressed bo already in good state */ + return 0; + } + + /* allocate uncompressed texture */ + if (rtexture->uncompressed == NULL) { + rtexture->uncompressed = radeon_bo(rscreen->rw, 0, rtexture->size, 4096, NULL); + if (rtexture->uncompressed == NULL) { + return -ENOMEM; + } + } + + /* render a rectangle covering whole buffer to uncompress depth */ + r = r600_blit_uncompress_depth(ctx, rtexture, level); + if (r) { + return r; + } + + rtexture->dirty = 0; + return 0; +} + +static void r600_texture_state_scissor(struct r600_screen *rscreen, + struct r600_resource_texture *rtexture, + unsigned level) +{ + struct radeon_state *rstate = &rtexture->scissor[level]; + + radeon_state_init(rstate, rscreen->rw, R600_STATE_SCISSOR, 0, 0); + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_SCISSOR__PA_SC_CLIPRECT_0_BR] = S_028244_BR_X(rtexture->width[level]) | S_028244_BR_Y(rtexture->height[level]); + rstate->states[R600_SCISSOR__PA_SC_CLIPRECT_0_TL] = 0x80000000; + rstate->states[R600_SCISSOR__PA_SC_CLIPRECT_1_BR] = S_028244_BR_X(rtexture->width[level]) | S_028244_BR_Y(rtexture->height[level]); + rstate->states[R600_SCISSOR__PA_SC_CLIPRECT_1_TL] = 0x80000000; + rstate->states[R600_SCISSOR__PA_SC_CLIPRECT_2_BR] = S_028244_BR_X(rtexture->width[level]) | S_028244_BR_Y(rtexture->height[level]); + rstate->states[R600_SCISSOR__PA_SC_CLIPRECT_2_TL] = 0x80000000; + rstate->states[R600_SCISSOR__PA_SC_CLIPRECT_3_BR] = S_028244_BR_X(rtexture->width[level]) | S_028244_BR_Y(rtexture->height[level]); + rstate->states[R600_SCISSOR__PA_SC_CLIPRECT_3_TL] = 0x80000000; + rstate->states[R600_SCISSOR__PA_SC_CLIPRECT_RULE] = 0x0000FFFF; + rstate->states[R600_SCISSOR__PA_SC_EDGERULE] = 0xAAAAAAAA; + rstate->states[R600_SCISSOR__PA_SC_GENERIC_SCISSOR_BR] = S_028244_BR_X(rtexture->width[level]) | S_028244_BR_Y(rtexture->height[level]); + rstate->states[R600_SCISSOR__PA_SC_GENERIC_SCISSOR_TL] = 0x80000000; + rstate->states[R600_SCISSOR__PA_SC_SCREEN_SCISSOR_BR] = S_028244_BR_X(rtexture->width[level]) | S_028244_BR_Y(rtexture->height[level]); + rstate->states[R600_SCISSOR__PA_SC_SCREEN_SCISSOR_TL] = 0x80000000; + rstate->states[R600_SCISSOR__PA_SC_VPORT_SCISSOR_0_BR] = S_028244_BR_X(rtexture->width[level]) | S_028244_BR_Y(rtexture->height[level]); + rstate->states[R600_SCISSOR__PA_SC_VPORT_SCISSOR_0_TL] = 0x80000000; + rstate->states[R600_SCISSOR__PA_SC_WINDOW_SCISSOR_BR] = S_028244_BR_X(rtexture->width[level]) | S_028244_BR_Y(rtexture->height[level]); + rstate->states[R600_SCISSOR__PA_SC_WINDOW_SCISSOR_TL] = 0x80000000; + + radeon_state_pm4(rstate); +} + +static void r600_texture_state_cb(struct r600_screen *rscreen, struct r600_resource_texture *rtexture, unsigned cb, unsigned level) +{ + struct radeon_state *rstate; + struct r600_resource *rbuffer; + unsigned pitch, slice; + unsigned color_info; + unsigned format, swap, ntype; + const struct util_format_description *desc; + + rstate = &rtexture->cb[cb][level]; + radeon_state_init(rstate, rscreen->rw, R600_STATE_CB0 + cb, 0, 0); + rbuffer = &rtexture->resource; + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + pitch = (rtexture->pitch[level] / rtexture->bpt) / 8 - 1; + slice = (rtexture->pitch[level] / rtexture->bpt) * rtexture->height[level] / 64 - 1; + ntype = 0; + desc = util_format_description(rbuffer->base.b.format); + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) + ntype = V_0280A0_NUMBER_SRGB; + format = r600_translate_colorformat(rtexture->resource.base.b.format); + swap = r600_translate_colorswap(rtexture->resource.base.b.format); + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) { + rstate->bo[0] = radeon_bo_incref(rscreen->rw, rtexture->uncompressed); + rstate->bo[1] = radeon_bo_incref(rscreen->rw, rtexture->uncompressed); + rstate->bo[2] = radeon_bo_incref(rscreen->rw, rtexture->uncompressed); + rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + rstate->placement[2] = RADEON_GEM_DOMAIN_GTT; + rstate->placement[4] = RADEON_GEM_DOMAIN_GTT; + rstate->nbo = 3; + color_info = 0; + } else { + rstate->bo[0] = radeon_bo_incref(rscreen->rw, rbuffer->bo); + rstate->bo[1] = radeon_bo_incref(rscreen->rw, rbuffer->bo); + rstate->bo[2] = radeon_bo_incref(rscreen->rw, rbuffer->bo); + rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + rstate->placement[2] = RADEON_GEM_DOMAIN_GTT; + rstate->placement[4] = RADEON_GEM_DOMAIN_GTT; + rstate->nbo = 3; + color_info = S_0280A0_SOURCE_FORMAT(1); + } + color_info |= S_0280A0_FORMAT(format) | + S_0280A0_COMP_SWAP(swap) | + S_0280A0_BLEND_CLAMP(1) | + S_0280A0_NUMBER_TYPE(ntype); + rstate->states[R600_CB0__CB_COLOR0_BASE] = rtexture->offset[level] >> 8; + rstate->states[R600_CB0__CB_COLOR0_INFO] = color_info; + rstate->states[R600_CB0__CB_COLOR0_SIZE] = S_028060_PITCH_TILE_MAX(pitch) | + S_028060_SLICE_TILE_MAX(slice); + + radeon_state_pm4(rstate); +} + +static void r600_texture_state_db(struct r600_screen *rscreen, struct r600_resource_texture *rtexture, unsigned level) +{ + struct radeon_state *rstate = &rtexture->db[level]; + struct r600_resource *rbuffer; + unsigned pitch, slice, format; + + radeon_state_init(rstate, rscreen->rw, R600_STATE_DB, 0, 0); + rbuffer = &rtexture->resource; + rtexture->tilled = 1; + rtexture->array_mode = 2; + rtexture->tile_type = 1; + rtexture->depth = 1; + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + pitch = (rtexture->pitch[level] / rtexture->bpt) / 8 - 1; + slice = (rtexture->pitch[level] / rtexture->bpt) * rtexture->height[level] / 64 - 1; + format = r600_translate_dbformat(rbuffer->base.b.format); + rstate->states[R600_DB__DB_DEPTH_BASE] = rtexture->offset[level] >> 8; + rstate->states[R600_DB__DB_DEPTH_INFO] = S_028010_ARRAY_MODE(rtexture->array_mode) | + S_028010_FORMAT(format); + rstate->states[R600_DB__DB_DEPTH_VIEW] = 0x00000000; + rstate->states[R600_DB__DB_PREFETCH_LIMIT] = (rtexture->height[level] / 8) -1; + rstate->states[R600_DB__DB_DEPTH_SIZE] = S_028000_PITCH_TILE_MAX(pitch) | + S_028000_SLICE_TILE_MAX(slice); + rstate->bo[0] = radeon_bo_incref(rscreen->rw, rbuffer->bo); + rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; + rstate->nbo = 1; + + radeon_state_pm4(rstate); +} + +int r600_texture_scissor(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level) +{ + struct r600_screen *rscreen = r600_screen(ctx->screen); + + if (!rtexture->scissor[level].cpm4) { + r600_texture_state_scissor(rscreen, rtexture, level); + } + return 0; +} + +static void r600_texture_state_viewport(struct r600_screen *rscreen, struct r600_resource_texture *rtexture, unsigned level) +{ + struct radeon_state *rstate = &rtexture->viewport[level]; + + radeon_state_init(rstate, rscreen->rw, R600_STATE_VIEWPORT, 0, 0); + + /* set states (most default value are 0 and struct already + * initialized to 0, thus avoid resetting them) + */ + rstate->states[R600_VIEWPORT__PA_CL_VPORT_XOFFSET_0] = fui((float)rtexture->width[level]/2.0); + rstate->states[R600_VIEWPORT__PA_CL_VPORT_XSCALE_0] = fui((float)rtexture->width[level]/2.0); + rstate->states[R600_VIEWPORT__PA_CL_VPORT_YOFFSET_0] = fui((float)rtexture->height[level]/2.0); + rstate->states[R600_VIEWPORT__PA_CL_VPORT_YSCALE_0] = fui((float)-rtexture->height[level]/2.0); + rstate->states[R600_VIEWPORT__PA_CL_VPORT_ZOFFSET_0] = 0x3F000000; + rstate->states[R600_VIEWPORT__PA_CL_VPORT_ZSCALE_0] = 0x3F000000; + rstate->states[R600_VIEWPORT__PA_CL_VTE_CNTL] = 0x0000043F; + rstate->states[R600_VIEWPORT__PA_SC_VPORT_ZMAX_0] = 0x3F800000; + + radeon_state_pm4(rstate); +} + +int r600_texture_cb(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned cb, unsigned level) +{ + struct r600_screen *rscreen = r600_screen(ctx->screen); + + if (!rtexture->cb[cb][level].cpm4) { + r600_texture_state_cb(rscreen, rtexture, cb, level); + } + return 0; +} + +int r600_texture_db(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level) +{ + struct r600_screen *rscreen = r600_screen(ctx->screen); + + if (!rtexture->db[level].cpm4) { + r600_texture_state_db(rscreen, rtexture, level); + } + return 0; +} + +int r600_texture_viewport(struct pipe_context *ctx, struct r600_resource_texture *rtexture, unsigned level) +{ + struct r600_screen *rscreen = r600_screen(ctx->screen); + + if (!rtexture->viewport[level].cpm4) { + r600_texture_state_viewport(rscreen, rtexture, level); + } + return 0; +} diff --git a/src/gallium/drivers/r600/r600d.h b/src/gallium/drivers/r600/r600d.h index 53388f822e..7b9a983d53 100644 --- a/src/gallium/drivers/r600/r600d.h +++ b/src/gallium/drivers/r600/r600d.h @@ -199,6 +199,7 @@ #define V_0280A0_COLOR_16_16_16_16_FLOAT 0x00000020 #define V_0280A0_COLOR_32_32_32_32 0x00000022 #define V_0280A0_COLOR_32_32_32_32_FLOAT 0x00000023 +#define V_0280A0_COLOR_32_32_32_FLOAT 0x00000030 #define S_0280A0_ARRAY_MODE(x) (((x) & 0xF) << 8) #define G_0280A0_ARRAY_MODE(x) (((x) >> 8) & 0xF) #define C_0280A0_ARRAY_MODE 0xFFFFF0FF @@ -1316,4 +1317,11 @@ #define G_0286D4_PNT_SPRITE_TOP_1(x) (((x) >> 14) & 0x1) #define C_0286D4_PNT_SPRITE_TOP_1 0xFFFFBFFF +#define SQ_TEX_INST_LD 0x03 +#define SQ_TEX_INST_GET_GRADIENTS_H 0x7 +#define SQ_TEX_INST_GET_GRADIENTS_V 0x8 + +#define SQ_TEX_INST_SAMPLE 0x10 +#define SQ_TEX_INST_SAMPLE_L 0x11 +#define SQ_TEX_INST_SAMPLE_C 0x18 #endif diff --git a/src/gallium/drivers/r600/radeon.h b/src/gallium/drivers/r600/radeon.h index 8f00a4895a..aaac8de528 100644 --- a/src/gallium/drivers/r600/radeon.h +++ b/src/gallium/drivers/r600/radeon.h @@ -77,6 +77,14 @@ enum radeon_family { CHIP_LAST, }; +enum { + R600_SHADER_PS = 1, + R600_SHADER_VS, + R600_SHADER_GS, + R600_SHADER_FS, + R600_SHADER_MAX = R600_SHADER_FS, +}; + enum radeon_family radeon_get_family(struct radeon *rw); /* @@ -98,22 +106,23 @@ struct radeon_bo *radeon_bo_incref(struct radeon *radeon, struct radeon_bo *bo); struct radeon_bo *radeon_bo_decref(struct radeon *radeon, struct radeon_bo *bo); int radeon_bo_wait(struct radeon *radeon, struct radeon_bo *bo); +struct radeon_stype_info; /* * states functions */ struct radeon_state { struct radeon *radeon; unsigned refcount; - unsigned type; + struct radeon_stype_info *stype; + unsigned state_id; unsigned id; + unsigned shader_index; unsigned nstates; - u32 *states; + u32 states[64]; unsigned npm4; unsigned cpm4; u32 pm4_crc; - u32 *pm4; - u32 nimmd; - u32 *immd; + u32 pm4[128]; unsigned nbo; struct radeon_bo *bo[4]; unsigned nreloc; @@ -123,38 +132,22 @@ struct radeon_state { unsigned bo_dirty[4]; }; -struct radeon_state *radeon_state(struct radeon *radeon, u32 type, u32 id); -struct radeon_state *radeon_state_incref(struct radeon_state *state); -struct radeon_state *radeon_state_decref(struct radeon_state *state); +int radeon_state_init(struct radeon_state *rstate, struct radeon *radeon, u32 type, u32 id, u32 shader_class); +void radeon_state_fini(struct radeon_state *state); int radeon_state_pm4(struct radeon_state *state); +int radeon_state_convert(struct radeon_state *state, u32 stype, u32 id, u32 shader_type); /* * draw functions */ struct radeon_draw { - unsigned refcount; struct radeon *radeon; - unsigned nstate; struct radeon_state **state; - unsigned cpm4; }; -struct radeon_draw *radeon_draw(struct radeon *radeon); -struct radeon_draw *radeon_draw_duplicate(struct radeon_draw *draw); -struct radeon_draw *radeon_draw_incref(struct radeon_draw *draw); -struct radeon_draw *radeon_draw_decref(struct radeon_draw *draw); -int radeon_draw_set(struct radeon_draw *draw, struct radeon_state *state); -int radeon_draw_set_new(struct radeon_draw *draw, struct radeon_state *state); -int radeon_draw_check(struct radeon_draw *draw); - -struct radeon_ctx *radeon_ctx(struct radeon *radeon); -struct radeon_ctx *radeon_ctx_decref(struct radeon_ctx *ctx); -struct radeon_ctx *radeon_ctx_incref(struct radeon_ctx *ctx); -int radeon_ctx_set_draw(struct radeon_ctx *ctx, struct radeon_draw *draw); -int radeon_ctx_set_draw_new(struct radeon_ctx *ctx, struct radeon_draw *draw); -int radeon_ctx_pm4(struct radeon_ctx *ctx); -int radeon_ctx_submit(struct radeon_ctx *ctx); -void radeon_ctx_dump_bof(struct radeon_ctx *ctx, const char *file); +int radeon_draw_init(struct radeon_draw *draw, struct radeon *radeon); +void radeon_draw_bind(struct radeon_draw *draw, struct radeon_state *state); +void radeon_draw_unbind(struct radeon_draw *draw, struct radeon_state *state); /* * radeon context functions @@ -169,95 +162,57 @@ struct radeon_cs_reloc { #pragma pack() struct radeon_ctx { - int refcount; struct radeon *radeon; u32 *pm4; - u32 cpm4; - u32 draw_cpm4; - unsigned id; - unsigned next_id; + int cdwords; + int ndwords; unsigned nreloc; struct radeon_cs_reloc *reloc; unsigned nbo; struct radeon_bo **bo; - unsigned ndraw; - struct radeon_draw *cdraw; - struct radeon_draw **draw; - unsigned nstate; - struct radeon_state **state; }; +int radeon_ctx_init(struct radeon_ctx *ctx, struct radeon *radeon); +void radeon_ctx_fini(struct radeon_ctx *ctx); +void radeon_ctx_clear(struct radeon_ctx *ctx); +int radeon_ctx_set_draw(struct radeon_ctx *ctx, struct radeon_draw *draw); +int radeon_ctx_submit(struct radeon_ctx *ctx); +void radeon_ctx_dump_bof(struct radeon_ctx *ctx, const char *file); +int radeon_ctx_set_query_state(struct radeon_ctx *ctx, struct radeon_state *state); + /* * R600/R700 */ -#define R600_NSTATE 1280 -#define R600_NTYPE 32 +enum r600_stype { + R600_STATE_CONFIG, + R600_STATE_CB_CNTL, + R600_STATE_RASTERIZER, + R600_STATE_VIEWPORT, + R600_STATE_SCISSOR, + R600_STATE_BLEND, + R600_STATE_DSA, + R600_STATE_SHADER, /* has PS,VS,GS,FS variants */ + R600_STATE_CONSTANT, /* has PS,VS,GS,FS variants */ + R600_STATE_RESOURCE, /* has PS,VS,GS,FS variants */ + R600_STATE_SAMPLER, /* has PS,VS,GS,FS variants */ + R600_STATE_SAMPLER_BORDER, /* has PS,VS,GS,FS variants */ + R600_STATE_CB0, + R600_STATE_CB1, + R600_STATE_CB2, + R600_STATE_CB3, + R600_STATE_CB4, + R600_STATE_CB5, + R600_STATE_CB6, + R600_STATE_CB7, + R600_STATE_DB, + R600_STATE_QUERY_BEGIN, + R600_STATE_QUERY_END, + R600_STATE_UCP, + R600_STATE_VGT, + R600_STATE_DRAW, +}; -#define R600_CONFIG 0 -#define R600_CONFIG_TYPE 0 -#define R600_CB_CNTL 1 -#define R600_CB_CNTL_TYPE 1 -#define R600_RASTERIZER 2 -#define R600_RASTERIZER_TYPE 2 -#define R600_VIEWPORT 3 -#define R600_VIEWPORT_TYPE 3 -#define R600_SCISSOR 4 -#define R600_SCISSOR_TYPE 4 -#define R600_BLEND 5 -#define R600_BLEND_TYPE 5 -#define R600_DSA 6 -#define R600_DSA_TYPE 6 -#define R600_VS_SHADER 7 -#define R600_VS_SHADER_TYPE 7 -#define R600_PS_SHADER 8 -#define R600_PS_SHADER_TYPE 8 -#define R600_PS_CONSTANT 9 -#define R600_PS_CONSTANT_TYPE 9 -#define R600_VS_CONSTANT 265 -#define R600_VS_CONSTANT_TYPE 10 -#define R600_PS_RESOURCE 521 -#define R600_PS_RESOURCE_TYPE 11 -#define R600_VS_RESOURCE 681 -#define R600_VS_RESOURCE_TYPE 12 -#define R600_FS_RESOURCE 841 -#define R600_FS_RESOURCE_TYPE 13 -#define R600_GS_RESOURCE 1001 -#define R600_GS_RESOURCE_TYPE 14 -#define R600_PS_SAMPLER 1161 -#define R600_PS_SAMPLER_TYPE 15 -#define R600_VS_SAMPLER 1179 -#define R600_VS_SAMPLER_TYPE 16 -#define R600_GS_SAMPLER 1197 -#define R600_GS_SAMPLER_TYPE 17 -#define R600_PS_SAMPLER_BORDER 1215 -#define R600_PS_SAMPLER_BORDER_TYPE 18 -#define R600_VS_SAMPLER_BORDER 1233 -#define R600_VS_SAMPLER_BORDER_TYPE 19 -#define R600_GS_SAMPLER_BORDER 1251 -#define R600_GS_SAMPLER_BORDER_TYPE 20 -#define R600_CB0 1269 -#define R600_CB0_TYPE 21 -#define R600_CB1 1270 -#define R600_CB1_TYPE 22 -#define R600_CB2 1271 -#define R600_CB2_TYPE 23 -#define R600_CB3 1272 -#define R600_CB3_TYPE 24 -#define R600_CB4 1273 -#define R600_CB4_TYPE 25 -#define R600_CB5 1274 -#define R600_CB5_TYPE 26 -#define R600_CB6 1275 -#define R600_CB6_TYPE 27 -#define R600_CB7 1276 -#define R600_CB7_TYPE 28 -#define R600_DB 1277 -#define R600_DB_TYPE 29 -#define R600_VGT 1278 -#define R600_VGT_TYPE 30 -#define R600_DRAW 1279 -#define R600_DRAW_TYPE 31 /* R600_CONFIG */ #define R600_CONFIG__SQ_CONFIG 0 #define R600_CONFIG__SQ_GPR_RESOURCE_MGMT_1 1 @@ -639,9 +594,40 @@ struct radeon_ctx { /* R600_DRAW */ #define R600_DRAW__VGT_NUM_INDICES 0 #define R600_DRAW__VGT_DMA_BASE_HI 1 -#define R600_DRAW__VGT_DMA_BASE 2 +#define R600_DRAW__VGT_DMA_BASE 2 #define R600_DRAW__VGT_DRAW_INITIATOR 3 -#define R600_DRAW_SIZE 4 -#define R600_DRAW_PM4 128 +#define R600_DRAW_SIZE 4 +#define R600_DRAW_PM4 128 +/* R600_CLIP */ +#define R600_CLIP__PA_CL_UCP_X_0 0 +#define R600_CLIP__PA_CL_UCP_Y_0 1 +#define R600_CLIP__PA_CL_UCP_Z_0 2 +#define R600_CLIP__PA_CL_UCP_W_0 3 +#define R600_CLIP__PA_CL_UCP_X_1 4 +#define R600_CLIP__PA_CL_UCP_Y_1 5 +#define R600_CLIP__PA_CL_UCP_Z_1 6 +#define R600_CLIP__PA_CL_UCP_W_1 7 +#define R600_CLIP__PA_CL_UCP_X_2 8 +#define R600_CLIP__PA_CL_UCP_Y_2 9 +#define R600_CLIP__PA_CL_UCP_Z_2 10 +#define R600_CLIP__PA_CL_UCP_W_2 11 +#define R600_CLIP__PA_CL_UCP_X_3 12 +#define R600_CLIP__PA_CL_UCP_Y_3 13 +#define R600_CLIP__PA_CL_UCP_Z_3 14 +#define R600_CLIP__PA_CL_UCP_W_3 15 +#define R600_CLIP__PA_CL_UCP_X_4 16 +#define R600_CLIP__PA_CL_UCP_Y_4 17 +#define R600_CLIP__PA_CL_UCP_Z_4 18 +#define R600_CLIP__PA_CL_UCP_W_4 19 +#define R600_CLIP__PA_CL_UCP_X_5 20 +#define R600_CLIP__PA_CL_UCP_Y_5 21 +#define R600_CLIP__PA_CL_UCP_Z_5 22 +#define R600_CLIP__PA_CL_UCP_W_5 23 +#define R600_CLIP_SIZE 24 +#define R600_CLIP_PM4 128 +/* R600 QUERY BEGIN/END */ +#define R600_QUERY__OFFSET 0 +#define R600_QUERY_SIZE 1 +#define R600_QUERY_PM4 128 #endif diff --git a/src/gallium/drivers/softpipe/sp_draw_arrays.c b/src/gallium/drivers/softpipe/sp_draw_arrays.c index 386c8acb8c..01b4ca985d 100644 --- a/src/gallium/drivers/softpipe/sp_draw_arrays.c +++ b/src/gallium/drivers/softpipe/sp_draw_arrays.c @@ -75,14 +75,10 @@ softpipe_draw_stream_output(struct pipe_context *pipe, unsigned mode) buf = (void*)((int32_t*)buf + offset); draw_set_mapped_vertex_buffer(draw, 0, buf); - draw_set_mapped_element_buffer_range(draw, - 0, 0, - start, - start + count - 1, - NULL); + draw_set_mapped_index_buffer(draw, NULL); /* draw! */ - draw_arrays_instanced(draw, mode, start, count, 0, 1); + draw_arrays(draw, mode, start, count); /* unmap vertex/index buffers - will cause draw module to flush */ draw_set_mapped_vertex_buffer(draw, 0, NULL); @@ -138,28 +134,20 @@ softpipe_draw_vbo(struct pipe_context *pipe, } /* Map index buffer, if present */ - if (info->indexed && sp->index_buffer.buffer) { - char *indices = (char *) softpipe_resource(sp->index_buffer.buffer)->data; - mapped_indices = (void *) (indices + sp->index_buffer.offset); - } + if (info->indexed && sp->index_buffer.buffer) + mapped_indices = softpipe_resource(sp->index_buffer.buffer)->data; - draw_set_mapped_element_buffer_range(draw, (mapped_indices) ? - sp->index_buffer.index_size : 0, - info->index_bias, - info->min_index, - info->max_index, - mapped_indices); + draw_set_mapped_index_buffer(draw, mapped_indices); /* draw! */ - draw_arrays_instanced(draw, info->mode, info->start, info->count, - info->start_instance, info->instance_count); + draw_vbo(draw, info); /* unmap vertex/index buffers - will cause draw module to flush */ for (i = 0; i < sp->num_vertex_buffers; i++) { draw_set_mapped_vertex_buffer(draw, i, NULL); } if (mapped_indices) { - draw_set_mapped_element_buffer(draw, 0, 0, NULL); + draw_set_mapped_index_buffer(draw, NULL); } /* diff --git a/src/gallium/drivers/softpipe/sp_flush.c b/src/gallium/drivers/softpipe/sp_flush.c index 4a53ef048f..1071011db0 100644 --- a/src/gallium/drivers/softpipe/sp_flush.c +++ b/src/gallium/drivers/softpipe/sp_flush.c @@ -31,6 +31,7 @@ #include "pipe/p_defines.h" +#include "pipe/p_screen.h" #include "draw/draw_context.h" #include "sp_flush.h" #include "sp_context.h" diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c index 93af6ee5b0..73ae2dea56 100644 --- a/src/gallium/drivers/softpipe/sp_screen.c +++ b/src/gallium/drivers/softpipe/sp_screen.c @@ -199,6 +199,7 @@ softpipe_is_format_supported( struct pipe_screen *screen, assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_2D || + target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE); diff --git a/src/gallium/drivers/softpipe/sp_state_vertex.c b/src/gallium/drivers/softpipe/sp_state_vertex.c index 880a7c7cd2..b650fcaea5 100644 --- a/src/gallium/drivers/softpipe/sp_state_vertex.c +++ b/src/gallium/drivers/softpipe/sp_state_vertex.c @@ -100,5 +100,5 @@ softpipe_set_index_buffer(struct pipe_context *pipe, else memset(&softpipe->index_buffer, 0, sizeof(softpipe->index_buffer)); - /* TODO make this more like a state */ + draw_set_index_buffer(softpipe->draw, ib); } diff --git a/src/gallium/drivers/softpipe/sp_tex_sample.c b/src/gallium/drivers/softpipe/sp_tex_sample.c index cf7ab81405..e654bb77c2 100644 --- a/src/gallium/drivers/softpipe/sp_tex_sample.c +++ b/src/gallium/drivers/softpipe/sp_tex_sample.c @@ -1785,6 +1785,7 @@ get_lambda_func(const union sp_sampler_key key) case PIPE_TEXTURE_1D: return compute_lambda_1d; case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_CUBE: return compute_lambda_2d; case PIPE_TEXTURE_3D: @@ -1809,6 +1810,7 @@ get_img_filter(const union sp_sampler_key key, return img_filter_1d_linear; break; case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: /* Try for fast path: */ if (key.bits.is_pot && diff --git a/src/gallium/drivers/svga/svga_cmd.c b/src/gallium/drivers/svga/svga_cmd.c index 7b2dfe2549..e975f3b02f 100644 --- a/src/gallium/drivers/svga/svga_cmd.c +++ b/src/gallium/drivers/svga/svga_cmd.c @@ -67,7 +67,7 @@ void surface_to_surfaceid(struct svga_winsys_context *swc, // IN id->mipmap = s->real_level; } else { - id->sid = SVGA3D_INVALID_ID; + swc->surface_relocation(swc, &id->sid, NULL, flags); id->face = 0; id->mipmap = 0; } diff --git a/src/gallium/drivers/svga/svga_context.c b/src/gallium/drivers/svga/svga_context.c index 3b30b9e341..cd3f6b8982 100644 --- a/src/gallium/drivers/svga/svga_context.c +++ b/src/gallium/drivers/svga/svga_context.c @@ -214,6 +214,11 @@ void svga_context_flush( struct svga_context *svga, svga_screen_cache_flush(svgascreen, fence); + /* To force the reemission of rendertargets and texture bindings at + * the beginning of every command buffer. + */ + svga->dirty |= SVGA_NEW_COMMAND_BUFFER; + if (SVGA_DEBUG & DEBUG_SYNC) { if (fence) svga->pipe.screen->fence_finish( svga->pipe.screen, fence, 0); diff --git a/src/gallium/drivers/svga/svga_context.h b/src/gallium/drivers/svga/svga_context.h index 67a7614c8a..1fb5a04887 100644 --- a/src/gallium/drivers/svga/svga_context.h +++ b/src/gallium/drivers/svga/svga_context.h @@ -382,6 +382,7 @@ struct svga_context #define SVGA_NEW_ZERO_STRIDE 0x2000000 #define SVGA_NEW_TEXTURE_FLAGS 0x4000000 #define SVGA_NEW_STENCIL_REF 0x8000000 +#define SVGA_NEW_COMMAND_BUFFER 0x10000000 diff --git a/src/gallium/drivers/svga/svga_pipe_draw.c b/src/gallium/drivers/svga/svga_pipe_draw.c index de08bc5e56..001ec3616c 100644 --- a/src/gallium/drivers/svga/svga_pipe_draw.c +++ b/src/gallium/drivers/svga/svga_pipe_draw.c @@ -146,23 +146,15 @@ retry: } - - - static void -svga_draw_range_elements( struct pipe_context *pipe, - struct pipe_resource *index_buffer, - unsigned index_size, - int index_bias, - unsigned min_index, - unsigned max_index, - unsigned prim, unsigned start, unsigned count) +svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct svga_context *svga = svga_context( pipe ); - unsigned reduced_prim = u_reduced_prim(prim); + unsigned reduced_prim = u_reduced_prim( info->mode ); + unsigned count = info->count; enum pipe_error ret = 0; - if (!u_trim_pipe_prim( prim, &count )) + if (!u_trim_pipe_prim( info->mode, &count )) return; /* @@ -187,34 +179,32 @@ svga_draw_range_elements( struct pipe_context *pipe, return; #endif - if (svga->state.sw.need_swtnl) - { - ret = svga_swtnl_draw_range_elements( svga, - index_buffer, - index_size, - index_bias, - min_index, max_index, - prim, - start, count ); + if (svga->state.sw.need_swtnl) { + ret = svga_swtnl_draw_vbo( svga, info ); } else { - if (index_buffer) { + if (info->indexed && svga->curr.ib.buffer) { + unsigned offset; + + assert(svga->curr.ib.offset % svga->curr.ib.index_size == 0); + offset = svga->curr.ib.offset / svga->curr.ib.index_size; + ret = retry_draw_range_elements( svga, - index_buffer, - index_size, - index_bias, - min_index, - max_index, - prim, - start, - count, + svga->curr.ib.buffer, + svga->curr.ib.index_size, + info->index_bias, + info->min_index, + info->max_index, + info->mode, + info->start + offset, + info->count, TRUE ); } else { - ret = retry_draw_arrays( svga, - prim, - start, - count, + ret = retry_draw_arrays( svga, + info->mode, + info->start, + info->count, TRUE ); } } @@ -226,30 +216,6 @@ svga_draw_range_elements( struct pipe_context *pipe, } -static void -svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) -{ - struct svga_context *svga = svga_context(pipe); - - if (info->indexed && svga->curr.ib.buffer) { - unsigned offset; - - assert(svga->curr.ib.offset % svga->curr.ib.index_size == 0); - offset = svga->curr.ib.offset / svga->curr.ib.index_size; - - svga_draw_range_elements(pipe, svga->curr.ib.buffer, - svga->curr.ib.index_size, info->index_bias, - info->min_index, info->max_index, - info->mode, info->start + offset, info->count); - } - else { - svga_draw_range_elements(pipe, NULL, 0, 0, - info->min_index, info->max_index, - info->mode, info->start, info->count); - } -} - - void svga_init_draw_functions( struct svga_context *svga ) { svga->pipe.draw_vbo = svga_draw_vbo; diff --git a/src/gallium/drivers/svga/svga_resource_texture.c b/src/gallium/drivers/svga/svga_resource_texture.c index ff83c750aa..26eb03a895 100644 --- a/src/gallium/drivers/svga/svga_resource_texture.c +++ b/src/gallium/drivers/svga/svga_resource_texture.c @@ -583,7 +583,8 @@ svga_texture_from_handle(struct pipe_screen *screen, assert(screen); /* Only supports one type */ - if (template->target != PIPE_TEXTURE_2D || + if ((template->target != PIPE_TEXTURE_2D && + template->target != PIPE_TEXTURE_RECT) || template->last_level != 0 || template->depth0 != 1) { return NULL; diff --git a/src/gallium/drivers/svga/svga_state_framebuffer.c b/src/gallium/drivers/svga/svga_state_framebuffer.c index bd92f00343..fcbb35e797 100644 --- a/src/gallium/drivers/svga/svga_state_framebuffer.c +++ b/src/gallium/drivers/svga/svga_state_framebuffer.c @@ -43,15 +43,18 @@ static int emit_framebuffer( struct svga_context *svga, { const struct pipe_framebuffer_state *curr = &svga->curr.framebuffer; struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; + boolean reemit = !!(dirty & SVGA_NEW_COMMAND_BUFFER); unsigned i; enum pipe_error ret; - /* XXX: Need shadow state in svga->hw to eliminate redundant - * uploads, especially of NULL buffers. + /* + * We need to reemit non-null surface bindings, even when they are not + * dirty, to ensure that the resources are paged in. */ for(i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) { - if (curr->cbufs[i] != hw->cbufs[i]) { + if (curr->cbufs[i] != hw->cbufs[i] || + (reemit && hw->cbufs[i])) { if (svga->curr.nr_fbs++ > 8) return PIPE_ERROR_OUT_OF_MEMORY; @@ -64,7 +67,8 @@ static int emit_framebuffer( struct svga_context *svga, } - if (curr->zsbuf != hw->zsbuf) { + if (curr->zsbuf != hw->zsbuf || + (reemit && hw->zsbuf)) { ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, curr->zsbuf); if (ret != PIPE_OK) return ret; @@ -92,7 +96,8 @@ static int emit_framebuffer( struct svga_context *svga, struct svga_tracked_state svga_hw_framebuffer = { "hw framebuffer state", - SVGA_NEW_FRAME_BUFFER, + SVGA_NEW_FRAME_BUFFER | + SVGA_NEW_COMMAND_BUFFER, emit_framebuffer }; diff --git a/src/gallium/drivers/svga/svga_state_tss.c b/src/gallium/drivers/svga/svga_state_tss.c index 76a2dae143..4a50b19474 100644 --- a/src/gallium/drivers/svga/svga_state_tss.c +++ b/src/gallium/drivers/svga/svga_state_tss.c @@ -56,6 +56,7 @@ static int update_tss_binding(struct svga_context *svga, unsigned dirty ) { + boolean reemit = !!(dirty & SVGA_NEW_COMMAND_BUFFER); unsigned i; unsigned count = MAX2( svga->curr.num_sampler_views, svga->state.hw_draw.num_views ); @@ -107,12 +108,18 @@ update_tss_binding(struct svga_context *svga, max_lod); } - if (view->dirty) { + /* + * We need to reemit non-null texture bindings, even when they are not + * dirty, to ensure that the resources are paged in. + */ + + if (view->dirty || + (reemit && view->v)) { queue.bind[queue.bind_count].unit = i; queue.bind[queue.bind_count].view = view; queue.bind_count++; } - else if (view->v) { + if (!view->dirty && view->v) { svga_validate_sampler_view(svga, view->v); } } @@ -128,18 +135,21 @@ update_tss_binding(struct svga_context *svga, goto fail; for (i = 0; i < queue.bind_count; i++) { + struct svga_winsys_surface *handle; + ts[i].stage = queue.bind[i].unit; ts[i].name = SVGA3D_TS_BIND_TEXTURE; if (queue.bind[i].view->v) { - svga->swc->surface_relocation(svga->swc, - &ts[i].value, - queue.bind[i].view->v->handle, - SVGA_RELOC_READ); + handle = queue.bind[i].view->v->handle; } else { - ts[i].value = SVGA3D_INVALID_ID; + handle = NULL; } + svga->swc->surface_relocation(svga->swc, + &ts[i].value, + handle, + SVGA_RELOC_READ); queue.bind[i].view->dirty = FALSE; } @@ -157,7 +167,8 @@ fail: struct svga_tracked_state svga_hw_tss_binding = { "texture binding emit", SVGA_NEW_TEXTURE_BINDING | - SVGA_NEW_SAMPLER, + SVGA_NEW_SAMPLER | + SVGA_NEW_COMMAND_BUFFER, update_tss_binding }; diff --git a/src/gallium/drivers/svga/svga_swtnl.h b/src/gallium/drivers/svga/svga_swtnl.h index 65c675f99c..fc094e5142 100644 --- a/src/gallium/drivers/svga/svga_swtnl.h +++ b/src/gallium/drivers/svga/svga_swtnl.h @@ -38,15 +38,8 @@ void svga_destroy_swtnl( struct svga_context *svga ); enum pipe_error -svga_swtnl_draw_range_elements(struct svga_context *svga, - struct pipe_resource *indexBuffer, - unsigned indexSize, - int indexBias, - unsigned min_index, - unsigned max_index, - unsigned prim, - unsigned start, - unsigned count); +svga_swtnl_draw_vbo(struct svga_context *svga, + const struct pipe_draw_info *info); #endif diff --git a/src/gallium/drivers/svga/svga_swtnl_draw.c b/src/gallium/drivers/svga/svga_swtnl_draw.c index eb71c23195..814e8edd70 100644 --- a/src/gallium/drivers/svga/svga_swtnl_draw.c +++ b/src/gallium/drivers/svga/svga_swtnl_draw.c @@ -36,13 +36,8 @@ enum pipe_error -svga_swtnl_draw_range_elements(struct svga_context *svga, - struct pipe_resource *indexBuffer, - unsigned indexSize, - int indexBias, - unsigned min_index, - unsigned max_index, - unsigned prim, unsigned start, unsigned count) +svga_swtnl_draw_vbo(struct svga_context *svga, + const struct pipe_draw_info *info) { struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; struct pipe_transfer *ib_transfer = NULL; @@ -76,19 +71,18 @@ svga_swtnl_draw_range_elements(struct svga_context *svga, draw_set_mapped_vertex_buffer(draw, i, map); } + /* TODO move this to update_swtnl_draw */ + draw_set_index_buffer(draw, &svga->curr.ib); + /* Map index buffer, if present */ - if (indexBuffer) { - map = pipe_buffer_map(&svga->pipe, indexBuffer, + map = NULL; + if (info->indexed && svga->curr.ib.buffer) { + map = pipe_buffer_map(&svga->pipe, svga->curr.ib.buffer, PIPE_TRANSFER_READ, - &ib_transfer); - - draw_set_mapped_element_buffer_range(draw, - indexSize, indexBias, - min_index, - max_index, - map); + &ib_transfer); } - + draw_set_mapped_index_buffer(draw, map); + if (svga->curr.cb[PIPE_SHADER_VERTEX]) { map = pipe_buffer_map(&svga->pipe, svga->curr.cb[PIPE_SHADER_VERTEX], @@ -101,7 +95,7 @@ svga_swtnl_draw_range_elements(struct svga_context *svga, svga->curr.cb[PIPE_SHADER_VERTEX]->width0); } - draw_arrays(svga->swtnl.draw, prim, start, count); + draw_vbo(draw, info); draw_flush(svga->swtnl.draw); @@ -117,9 +111,9 @@ svga_swtnl_draw_range_elements(struct svga_context *svga, draw_set_mapped_vertex_buffer(draw, i, NULL); } - if (indexBuffer) { - pipe_buffer_unmap(&svga->pipe, indexBuffer, ib_transfer); - draw_set_mapped_element_buffer(draw, 0, 0, NULL); + if (ib_transfer) { + pipe_buffer_unmap(&svga->pipe, svga->curr.ib.buffer, ib_transfer); + draw_set_mapped_index_buffer(draw, NULL); } if (svga->curr.cb[PIPE_SHADER_VERTEX]) { @@ -157,7 +151,8 @@ boolean svga_init_swtnl( struct svga_context *svga ) draw_install_aapoint_stage(svga->swtnl.draw, &svga->pipe); draw_install_pstipple_stage(svga->swtnl.draw, &svga->pipe); - draw_set_driver_clipping(svga->swtnl.draw, debug_get_bool_option("SVGA_SWTNL_FSE", FALSE)); + if (debug_get_bool_option("SVGA_SWTNL_FSE", FALSE)) + draw_set_driver_clipping(svga->swtnl.draw, TRUE, TRUE); return TRUE; diff --git a/src/gallium/drivers/svga/svga_tgsi_emit.h b/src/gallium/drivers/svga/svga_tgsi_emit.h index 48eced2ece..b4e90a957d 100644 --- a/src/gallium/drivers/svga/svga_tgsi_emit.h +++ b/src/gallium/drivers/svga/svga_tgsi_emit.h @@ -353,6 +353,7 @@ static INLINE ubyte svga_tgsi_sampler_type( struct svga_shader_emitter *emit, case PIPE_TEXTURE_1D: return SVGA3DSAMP_2D; case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: return SVGA3DSAMP_2D; case PIPE_TEXTURE_3D: return SVGA3DSAMP_VOLUME; diff --git a/src/gallium/drivers/svga/svga_tgsi_insn.c b/src/gallium/drivers/svga/svga_tgsi_insn.c index 67e1f22a70..72dccdf150 100644 --- a/src/gallium/drivers/svga/svga_tgsi_insn.c +++ b/src/gallium/drivers/svga/svga_tgsi_insn.c @@ -806,6 +806,20 @@ static boolean emit_cmp(struct svga_shader_emitter *emit, const struct src_register src2 = translate_src_register( emit, &insn->Src[2] ); + if (emit->unit == PIPE_SHADER_VERTEX) { + SVGA3dShaderDestToken temp = get_temp(emit); + struct src_register zero = scalar(get_zero_immediate(emit), TGSI_SWIZZLE_X); + + /* Since vertex shaders don't support the CMP instruction, + * simulate it with SLT and LRP instructions. + * SLT TMP, SRC0, 0.0 + * LRP DST, TMP, SRC1, SRC2 + */ + if (!submit_op2(emit, inst_token(SVGA3DOP_SLT), temp, src0, zero)) + return FALSE; + return submit_op3(emit, inst_token(SVGA3DOP_LRP), dst, src(temp), src1, src2); + } + /* CMP DST, SRC0, SRC2, SRC1 */ return submit_op3( emit, inst_token( SVGA3DOP_CMP ), dst, src0, src2, src1); } @@ -2682,6 +2696,11 @@ needs_to_create_zero( struct svga_shader_emitter *emit ) return TRUE; } + if (emit->unit == PIPE_SHADER_VERTEX) { + if (emit->info.opcode_count[TGSI_OPCODE_CMP] >= 1) + return TRUE; + } + if (emit->info.opcode_count[TGSI_OPCODE_IF] >= 1 || emit->info.opcode_count[TGSI_OPCODE_BGNLOOP] >= 1 || emit->info.opcode_count[TGSI_OPCODE_DDX] >= 1 || diff --git a/src/gallium/drivers/trace/tr_context.c b/src/gallium/drivers/trace/tr_context.c index 84e5a6a824..271cd4aff5 100644 --- a/src/gallium/drivers/trace/tr_context.c +++ b/src/gallium/drivers/trace/tr_context.c @@ -885,7 +885,7 @@ trace_sampler_view_destroy(struct pipe_context *_pipe, trace_dump_arg(ptr, pipe); trace_dump_arg(ptr, view); - pipe->sampler_view_destroy(pipe, view); + pipe_sampler_view_reference(&tr_view->sampler_view, NULL); trace_dump_call_end(); @@ -1002,7 +1002,7 @@ trace_context_set_index_buffer(struct pipe_context *_pipe, trace_dump_call_begin("pipe_context", "set_index_buffer"); trace_dump_arg(ptr, pipe); - trace_dump_arg(index_buffer, ib); + trace_dump_arg(index_buffer, _ib); pipe->set_index_buffer(pipe, ib); @@ -1063,7 +1063,10 @@ trace_context_clear(struct pipe_context *_pipe, trace_dump_arg(ptr, pipe); trace_dump_arg(uint, buffers); - trace_dump_arg_array(float, rgba, 4); + if (rgba) + trace_dump_arg_array(float, rgba, 4); + else + trace_dump_null(); trace_dump_arg(float, depth); trace_dump_arg(uint, stencil); diff --git a/src/gallium/include/pipe/p_compiler.h b/src/gallium/include/pipe/p_compiler.h index 1fa3ec8300..0a5be43f6b 100644 --- a/src/gallium/include/pipe/p_compiler.h +++ b/src/gallium/include/pipe/p_compiler.h @@ -79,6 +79,14 @@ typedef unsigned char boolean; #define FALSE false #endif +#ifndef va_copy +#ifdef __va_copy +#define va_copy(dest, src) __va_copy((dest), (src)) +#else +#define va_copy(dest, src) (dest) = (src) +#endif +#endif + /* Function inlining */ #ifndef INLINE # ifdef __cplusplus diff --git a/src/gallium/include/pipe/p_context.h b/src/gallium/include/pipe/p_context.h index 0579962ec6..0e53aef6d2 100644 --- a/src/gallium/include/pipe/p_context.h +++ b/src/gallium/include/pipe/p_context.h @@ -28,19 +28,37 @@ #ifndef PIPE_CONTEXT_H #define PIPE_CONTEXT_H -#include "p_state.h" - +#include "p_compiler.h" #ifdef __cplusplus extern "C" { #endif - -struct pipe_screen; + +struct pipe_blend_color; +struct pipe_blend_state; +struct pipe_box; +struct pipe_clip_state; +struct pipe_depth_stencil_alpha_state; +struct pipe_draw_info; struct pipe_fence_handle; -struct pipe_state_cache; +struct pipe_framebuffer_state; +struct pipe_index_buffer; struct pipe_query; -struct pipe_winsys; +struct pipe_poly_stipple; +struct pipe_rasterizer_state; +struct pipe_resource; +struct pipe_sampler_state; +struct pipe_sampler_view; +struct pipe_scissor_state; +struct pipe_shader_state; +struct pipe_stencil_ref; +struct pipe_stream_output_state; +struct pipe_subresource; +struct pipe_surface; +struct pipe_vertex_buffer; +struct pipe_vertex_element; +struct pipe_viewport_state; /** * Gallium rendering context. Basically: diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h index 00aa2076ed..627b5ae538 100644 --- a/src/gallium/include/pipe/p_defines.h +++ b/src/gallium/include/pipe/p_defines.h @@ -28,7 +28,7 @@ #ifndef PIPE_DEFINES_H #define PIPE_DEFINES_H -#include "p_format.h" +#include "p_compiler.h" #ifdef __cplusplus extern "C" { @@ -135,13 +135,15 @@ enum pipe_error { #define PIPE_STENCIL_OP_DECR_WRAP 6 #define PIPE_STENCIL_OP_INVERT 7 -/** Texture types */ +/** Texture types. + * See the documentation for info on PIPE_TEXTURE_RECT vs PIPE_TEXTURE_2D */ enum pipe_texture_target { PIPE_BUFFER = 0, PIPE_TEXTURE_1D = 1, PIPE_TEXTURE_2D = 2, PIPE_TEXTURE_3D = 3, PIPE_TEXTURE_CUBE = 4, + PIPE_TEXTURE_RECT = 5, PIPE_MAX_TEXTURE_TYPES }; diff --git a/src/gallium/include/pipe/p_format.h b/src/gallium/include/pipe/p_format.h index 436c3f627a..06412f4894 100644 --- a/src/gallium/include/pipe/p_format.h +++ b/src/gallium/include/pipe/p_format.h @@ -29,8 +29,6 @@ #ifndef PIPE_FORMAT_H #define PIPE_FORMAT_H -#include "p_compiler.h" - #ifdef __cplusplus extern "C" { #endif diff --git a/src/gallium/include/pipe/p_shader_tokens.h b/src/gallium/include/pipe/p_shader_tokens.h index 9df20ea858..c4bd17e92b 100644 --- a/src/gallium/include/pipe/p_shader_tokens.h +++ b/src/gallium/include/pipe/p_shader_tokens.h @@ -33,8 +33,6 @@ extern "C" { #endif -#include "p_compiler.h" - struct tgsi_header { diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h index 0f1a44cde4..9a2b31da50 100644 --- a/src/gallium/include/pipe/p_state.h +++ b/src/gallium/include/pipe/p_state.h @@ -43,7 +43,6 @@ #include "p_compiler.h" #include "p_defines.h" #include "p_format.h" -#include "p_screen.h" #ifdef __cplusplus diff --git a/src/gallium/include/state_tracker/graw.h b/src/gallium/include/state_tracker/graw.h index 59b0e337c9..6a99b234aa 100644 --- a/src/gallium/include/state_tracker/graw.h +++ b/src/gallium/include/state_tracker/graw.h @@ -1,3 +1,30 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #ifndef GALLIUM_RAW_H #define GALLIUM_RAW_H @@ -14,6 +41,7 @@ * those for parsing text representations of TGSI shaders. */ +#include "pipe/p_compiler.h" #include "pipe/p_format.h" struct pipe_screen; diff --git a/src/gallium/state_trackers/dri/common/dri_context.h b/src/gallium/state_trackers/dri/common/dri_context.h index 692c49d7cd..35b870a8a3 100644 --- a/src/gallium/state_trackers/dri/common/dri_context.h +++ b/src/gallium/state_trackers/dri/common/dri_context.h @@ -34,7 +34,6 @@ #include "pipe/p_compiler.h" #include "dri_wrapper.h" -#include "main/mtypes.h" struct pipe_context; struct pipe_fence; diff --git a/src/gallium/state_trackers/dri/common/dri_screen.c b/src/gallium/state_trackers/dri/common/dri_screen.c index 6ad2c7da4d..0ab4dd1893 100644 --- a/src/gallium/state_trackers/dri/common/dri_screen.c +++ b/src/gallium/state_trackers/dri/common/dri_screen.c @@ -383,6 +383,11 @@ dri_init_screen_helper(struct dri_screen *screen, if (!screen->st_api) return NULL; + if(pscreen->get_param(pscreen, PIPE_CAP_NPOT_TEXTURES)) + screen->target = PIPE_TEXTURE_2D; + else + screen->target = PIPE_TEXTURE_RECT; + driParseOptionInfo(&screen->optionCache, __driConfigOptions, __driNConfigOptions); diff --git a/src/gallium/state_trackers/dri/common/dri_screen.h b/src/gallium/state_trackers/dri/common/dri_screen.h index 53ccce145b..849f399b2f 100644 --- a/src/gallium/state_trackers/dri/common/dri_screen.h +++ b/src/gallium/state_trackers/dri/common/dri_screen.h @@ -68,6 +68,7 @@ struct dri_screen boolean d_depth_bits_last; boolean sd_depth_bits_last; boolean auto_fake_front; + enum pipe_texture_target target; }; /** cast wrapper */ diff --git a/src/gallium/state_trackers/dri/drm/dri2.c b/src/gallium/state_trackers/dri/drm/dri2.c index 47005c17e2..93f910a26d 100644 --- a/src/gallium/state_trackers/dri/drm/dri2.c +++ b/src/gallium/state_trackers/dri/drm/dri2.c @@ -195,7 +195,7 @@ dri2_drawable_process_buffers(struct dri_drawable *drawable, pipe_resource_reference(&drawable->textures[i], NULL); memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; + templ.target = screen->target; templ.last_level = 0; templ.width0 = dri_drawable->w; templ.height0 = dri_drawable->h; @@ -342,7 +342,7 @@ dri2_create_image_from_name(__DRIcontext *context, memset(&templ, 0, sizeof(templ)); templ.bind = tex_usage; templ.format = pf; - templ.target = PIPE_TEXTURE_2D; + templ.target = screen->target; templ.last_level = 0; templ.width0 = width; templ.height0 = height; diff --git a/src/gallium/state_trackers/dri/sw/drisw.c b/src/gallium/state_trackers/dri/sw/drisw.c index 249ccd7fcf..04bba631ae 100644 --- a/src/gallium/state_trackers/dri/sw/drisw.c +++ b/src/gallium/state_trackers/dri/sw/drisw.c @@ -216,7 +216,7 @@ drisw_allocate_textures(struct dri_drawable *drawable, } memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; + templ.target = screen->target; templ.width0 = width; templ.height0 = height; templ.depth0 = 1; diff --git a/src/gallium/state_trackers/egl/Makefile b/src/gallium/state_trackers/egl/Makefile index 9e9e479e7e..4199d7c6ba 100644 --- a/src/gallium/state_trackers/egl/Makefile +++ b/src/gallium/state_trackers/egl/Makefile @@ -24,7 +24,7 @@ x11_SOURCES = $(wildcard x11/*.c) \ x11_OBJECTS = $(x11_SOURCES:.c=.o) -kms_INCLUDES = $(shell pkg-config --cflags-only-I libdrm) +kms_INCLUDES = -I$(TOP)/src/gallium/winsys $(shell pkg-config --cflags-only-I libdrm) kms_SOURCES = $(wildcard kms/*.c) kms_OBJECTS = $(kms_SOURCES:.c=.o) diff --git a/src/gallium/state_trackers/egl/SConscript b/src/gallium/state_trackers/egl/SConscript index e71aec35b7..efcce25e31 100644 --- a/src/gallium/state_trackers/egl/SConscript +++ b/src/gallium/state_trackers/egl/SConscript @@ -21,6 +21,7 @@ if 'egl' in env['statetrackers']: 'common/egl_g3d_api.c', 'common/egl_g3d_image.c', 'common/egl_g3d_st.c', + 'common/egl_g3d_sync.c', 'common/native_helper.c', ] diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.c b/src/gallium/state_trackers/egl/common/egl_g3d.c index 56d575ffe0..4e653bdf3b 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d.c @@ -530,6 +530,18 @@ egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy, if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER)) dpy->Extensions.KHR_image_pixmap = EGL_TRUE; + dpy->Extensions.KHR_reusable_sync = EGL_TRUE; + dpy->Extensions.KHR_fence_sync = EGL_TRUE; + + dpy->Extensions.KHR_surfaceless_gles1 = EGL_TRUE; + dpy->Extensions.KHR_surfaceless_gles2 = EGL_TRUE; + dpy->Extensions.KHR_surfaceless_opengl = EGL_TRUE; + + if (dpy->Platform == _EGL_PLATFORM_DRM) { + dpy->Extensions.MESA_drm_display = EGL_TRUE; + dpy->Extensions.MESA_drm_image = EGL_TRUE; + } + if (egl_g3d_add_configs(drv, dpy, 1) == 1) { _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)"); goto fail; diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.h b/src/gallium/state_trackers/egl/common/egl_g3d.h index f33dc91cf9..be450bbede 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d.h +++ b/src/gallium/state_trackers/egl/common/egl_g3d.h @@ -30,12 +30,14 @@ #include "pipe/p_screen.h" #include "pipe/p_context.h" #include "pipe/p_format.h" +#include "os/os_thread.h" #include "egldriver.h" #include "egldisplay.h" #include "eglcontext.h" #include "eglsurface.h" #include "eglconfig.h" #include "eglimage.h" +#include "eglsync.h" #include "eglscreen.h" #include "eglmode.h" @@ -99,6 +101,24 @@ struct egl_g3d_image { _EGL_DRIVER_STANDARD_TYPECASTS(egl_g3d) _EGL_DRIVER_TYPECAST(egl_g3d_image, _EGLImage, obj) +#ifdef EGL_KHR_reusable_sync + +struct egl_g3d_sync { + _EGLSync base; + + int refs; + + /* the mutex protects only the condvar, not the struct */ + pipe_mutex mutex; + pipe_condvar condvar; + + /* for fence sync */ + struct pipe_fence_handle *fence; +}; +_EGL_DRIVER_TYPECAST(egl_g3d_sync, _EGLSync, obj) + +#endif /* EGL_KHR_reusable_sync */ + #ifdef EGL_MESA_screen_surface struct egl_g3d_screen { diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_api.c b/src/gallium/state_trackers/egl/common/egl_g3d_api.c index edac72a822..3ec53653f4 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_api.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d_api.c @@ -34,6 +34,7 @@ #include "egl_g3d.h" #include "egl_g3d_api.h" #include "egl_g3d_image.h" +#include "egl_g3d_sync.h" #include "egl_g3d_st.h" #include "egl_g3d_loader.h" #include "native.h" @@ -103,7 +104,7 @@ egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, } gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi, - &gconf->stvis, (gshare) ? gshare->stctxi : NULL); + (gconf) ? &gconf->stvis : NULL, (gshare) ? gshare->stctxi : NULL); if (!gctx->stctxi) { FREE(gctx); return NULL; @@ -437,16 +438,19 @@ egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy, ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi, (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL); if (ok) { - gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gdraw->stfbi); - if (gread != gdraw) { + if (gdraw) { gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, - gread->stfbi); - } + gdraw->stfbi); - if (gdraw->base.Type == EGL_WINDOW_BIT) { - gctx->base.WindowRenderBuffer = - (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ? - EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; + if (gdraw->base.Type == EGL_WINDOW_BIT) { + gctx->base.WindowRenderBuffer = + (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ? + EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; + } + } + if (gread && gread != gdraw) { + gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, + gread->stfbi); } } } @@ -805,6 +809,17 @@ egl_g3d_init_driver_api(_EGLDriver *drv) drv->API.CreateImageKHR = egl_g3d_create_image; drv->API.DestroyImageKHR = egl_g3d_destroy_image; +#ifdef EGL_MESA_drm_image + drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image; + drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image; +#endif + +#ifdef EGL_KHR_reusable_sync + drv->API.CreateSyncKHR = egl_g3d_create_sync; + drv->API.DestroySyncKHR = egl_g3d_destroy_sync; + drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync; + drv->API.SignalSyncKHR = egl_g3d_signal_sync; +#endif #ifdef EGL_MESA_screen_surface drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface; diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_image.c b/src/gallium/state_trackers/egl/common/egl_g3d_image.c index 1e13cfcf7e..558638e72f 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_image.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d_image.c @@ -31,12 +31,16 @@ #include "util/u_rect.h" #include "util/u_inlines.h" #include "eglcurrent.h" +#include "egllog.h" #include "native.h" #include "egl_g3d.h" #include "egl_g3d_api.h" #include "egl_g3d_image.h" +/* move this to native display? */ +#include "state_tracker/drm_driver.h" + /** * Reference and return the front left buffer of the native pixmap. */ @@ -67,6 +71,165 @@ egl_g3d_reference_native_pixmap(_EGLDisplay *dpy, EGLNativePixmapType pix) return textures[natt]; } +#ifdef EGL_MESA_drm_image + +static struct pipe_resource * +egl_g3d_create_drm_buffer(_EGLDisplay *dpy, const EGLint *attribs) +{ + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct pipe_screen *screen = gdpy->native->screen; + struct pipe_resource templ; + EGLint width = 0, height = 0, format = 0, use = 0; + EGLint valid_use; + EGLint i, err = EGL_SUCCESS; + + for (i = 0; attribs[i] != EGL_NONE; i++) { + EGLint attr = attribs[i++]; + EGLint val = attribs[i]; + + switch (attr) { + case EGL_WIDTH: + width = val; + break; + case EGL_HEIGHT: + height = val; + break; + case EGL_DRM_BUFFER_FORMAT_MESA: + format = val; + break; + case EGL_DRM_BUFFER_USE_MESA: + use = val; + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_DEBUG, "bad image attribute 0x%04x", attr); + return NULL; + } + } + + if (width <= 0 || height <= 0) { + _eglLog(_EGL_DEBUG, "bad width or height (%dx%d)", width, height); + return NULL; + } + + switch (format) { + case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: + format = PIPE_FORMAT_B8G8R8A8_UNORM; + break; + default: + _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", format); + return NULL; + break; + } + + valid_use = EGL_DRM_BUFFER_USE_SCANOUT_MESA | + EGL_DRM_BUFFER_USE_SHARE_MESA; + if (use & ~valid_use) { + _eglLog(_EGL_DEBUG, "bad image use bit 0x%04x", use); + return NULL; + } + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.format = format; + templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + + /* + * XXX fix apps (e.g. wayland) and pipe drivers (e.g. i915) and remove the + * size check + */ + if ((use & EGL_DRM_BUFFER_USE_SCANOUT_MESA) && + width >= 640 && height >= 480) + templ.bind |= PIPE_BIND_SCANOUT; + if (use & EGL_DRM_BUFFER_USE_SHARE_MESA) + templ.bind |= PIPE_BIND_SHARED; + + return screen->resource_create(screen, &templ); +} + +static struct pipe_resource * +egl_g3d_reference_drm_buffer(_EGLDisplay *dpy, EGLint name, + const EGLint *attribs) +{ + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct pipe_screen *screen = gdpy->native->screen; + struct pipe_resource templ; + struct winsys_handle wsh; + EGLint width = 0, height = 0, format = 0, stride = 0; + EGLint i, err = EGL_SUCCESS; + + /* winsys_handle is in theory platform-specific */ + if (dpy->Platform != _EGL_PLATFORM_DRM) + return NULL; + + for (i = 0; attribs[i] != EGL_NONE; i++) { + EGLint attr = attribs[i++]; + EGLint val = attribs[i]; + + switch (attr) { + case EGL_WIDTH: + width = val; + break; + case EGL_HEIGHT: + height = val; + break; + case EGL_DRM_BUFFER_FORMAT_MESA: + format = val; + break; + case EGL_DRM_BUFFER_STRIDE_MESA: + stride = val; + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_DEBUG, "bad image attribute 0x%04x", attr); + return NULL; + } + } + + if (width <= 0 || height <= 0 || stride <= 0) { + _eglLog(_EGL_DEBUG, "bad width, height, or stride (%dx%dx%d)", + width, height, stride); + return NULL; + } + + switch (format) { + case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: + format = PIPE_FORMAT_B8G8R8A8_UNORM; + break; + default: + _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", format); + return NULL; + break; + } + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.format = format; + templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + + memset(&wsh, 0, sizeof(wsh)); + wsh.handle = (unsigned) name; + wsh.stride = stride; + + return screen->resource_from_handle(screen, &templ, &wsh); +} + +#endif /* EGL_MESA_drm_image */ + _EGLImage * egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLenum target, EGLClientBuffer buffer, @@ -92,6 +255,11 @@ egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, ptex = egl_g3d_reference_native_pixmap(dpy, (EGLNativePixmapType) buffer); break; +#ifdef EGL_MESA_drm_image + case EGL_DRM_BUFFER_MESA: + ptex = egl_g3d_reference_drm_buffer(dpy, (EGLint) buffer, attribs); + break; +#endif default: ptex = NULL; break; @@ -134,3 +302,80 @@ egl_g3d_destroy_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img) return EGL_TRUE; } + +_EGLImage * +egl_g3d_create_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, + const EGLint *attribs) +{ + struct egl_g3d_image *gimg; + struct pipe_resource *ptex; + + gimg = CALLOC_STRUCT(egl_g3d_image); + if (!gimg) { + _eglError(EGL_BAD_ALLOC, "eglCreateDRMImageKHR"); + return NULL; + } + + if (!_eglInitImage(&gimg->base, dpy, attribs)) { + FREE(gimg); + return NULL; + } + +#ifdef EGL_MESA_drm_image + ptex = egl_g3d_create_drm_buffer(dpy, attribs); +#else + ptex = NULL; +#endif + if (!ptex) { + FREE(gimg); + return NULL; + } + + /* transfer the ownership to the image */ + gimg->texture = ptex; + gimg->face = 0; + gimg->level = 0; + gimg->zslice = 0; + + return &gimg->base; +} + +EGLBoolean +egl_g3d_export_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img, + EGLint *name, EGLint *handle, EGLint *stride) +{ + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct egl_g3d_image *gimg = egl_g3d_image(img); + struct pipe_screen *screen = gdpy->native->screen; + struct winsys_handle wsh; + + /* winsys_handle is in theory platform-specific */ + if (dpy->Platform != _EGL_PLATFORM_DRM) + return EGL_FALSE; + + /* get shared handle */ + if (name) { + memset(&handle, 0, sizeof(handle)); + wsh.type = DRM_API_HANDLE_TYPE_SHARED; + if (!screen->resource_get_handle(screen, gimg->texture, &wsh)) { + return EGL_FALSE; + } + + *name = wsh.handle; + } + + /* get KMS handle */ + if (handle || stride) { + memset(&wsh, 0, sizeof(wsh)); + wsh.type = DRM_API_HANDLE_TYPE_KMS; + if (!screen->resource_get_handle(screen, gimg->texture, &wsh)) + return EGL_FALSE; + + if (handle) + *handle = wsh.handle; + if (stride) + *stride = wsh.stride; + } + + return EGL_TRUE; +} diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_image.h b/src/gallium/state_trackers/egl/common/egl_g3d_image.h index adda933371..f051da8283 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_image.h +++ b/src/gallium/state_trackers/egl/common/egl_g3d_image.h @@ -39,4 +39,12 @@ egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLBoolean egl_g3d_destroy_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *image); +_EGLImage * +egl_g3d_create_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, + const EGLint *attribs); + +EGLBoolean +egl_g3d_export_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img, + EGLint *name, EGLint *handle, EGLint *stride); + #endif /* _EGL_G3D_IMAGE_H_ */ diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_sync.c b/src/gallium/state_trackers/egl/common/egl_g3d_sync.c new file mode 100644 index 0000000000..ec74e9eb94 --- /dev/null +++ b/src/gallium/state_trackers/egl/common/egl_g3d_sync.c @@ -0,0 +1,284 @@ +/* + * Mesa 3-D graphics library + * Version: 7.9 + * + * Copyright (C) 2010 LunarG Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Chia-I Wu <olv@lunarg.com> + */ + +#include "util/u_memory.h" +#include "util/u_atomic.h" +#include "os/os_thread.h" +#include "eglsync.h" +#include "eglcurrent.h" + +#include "egl_g3d.h" +#include "egl_g3d_sync.h" + +#ifdef EGL_KHR_reusable_sync + +/** + * Wait for the conditional variable. + */ +static EGLint +egl_g3d_wait_sync_condvar(struct egl_g3d_sync *gsync, EGLTimeKHR timeout) +{ + _EGLDisplay *dpy = gsync->base.Resource.Display; + + pipe_mutex_lock(gsync->mutex); + + /* unlock display lock just before waiting */ + _eglUnlockMutex(&dpy->Mutex); + + /* No timed wait. Always treat timeout as EGL_FOREVER_KHR */ + pipe_condvar_wait(gsync->condvar, gsync->mutex); + + _eglLockMutex(&dpy->Mutex); + + pipe_mutex_unlock(gsync->mutex); + + return EGL_CONDITION_SATISFIED_KHR; +} + +/** + * Signal the conditional variable. + */ +static void +egl_g3d_signal_sync_condvar(struct egl_g3d_sync *gsync) +{ + pipe_mutex_lock(gsync->mutex); + pipe_condvar_broadcast(gsync->condvar); + pipe_mutex_unlock(gsync->mutex); +} + +/** + * Insert a fence command to the command stream of the current context. + */ +static EGLint +egl_g3d_insert_fence_sync(struct egl_g3d_sync *gsync) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + struct egl_g3d_context *gctx = egl_g3d_context(ctx); + + /* already checked in egl_g3d_create_sync */ + assert(gctx); + + /* insert the fence command */ + gctx->stctxi->flush(gctx->stctxi, 0x0, &gsync->fence); + if (!gsync->fence) + gsync->base.SyncStatus = EGL_SIGNALED_KHR; + + return EGL_SUCCESS; +} + +/** + * Wait for the fence sync to be signaled. + */ +static EGLint +egl_g3d_wait_fence_sync(struct egl_g3d_sync *gsync, EGLTimeKHR timeout) +{ + EGLint ret; + + if (gsync->fence) { + _EGLDisplay *dpy = gsync->base.Resource.Display; + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct pipe_screen *screen = gdpy->native->screen; + struct pipe_fence_handle *fence = gsync->fence; + + gsync->fence = NULL; + + _eglUnlockMutex(&dpy->Mutex); + /* no timed finish? */ + screen->fence_finish(screen, fence, 0x0); + ret = EGL_CONDITION_SATISFIED_KHR; + _eglLockMutex(&dpy->Mutex); + + gsync->base.SyncStatus = EGL_SIGNALED_KHR; + + screen->fence_reference(screen, &fence, NULL); + egl_g3d_signal_sync_condvar(gsync); + } + else { + ret = egl_g3d_wait_sync_condvar(gsync, timeout); + } + + return ret; +} + +static INLINE void +egl_g3d_ref_sync(struct egl_g3d_sync *gsync) +{ + p_atomic_inc(&gsync->refs); +} + +static INLINE void +egl_g3d_unref_sync(struct egl_g3d_sync *gsync) +{ + if (p_atomic_dec_zero(&gsync->refs)) { + pipe_condvar_destroy(gsync->condvar); + pipe_mutex_destroy(gsync->mutex); + + if (gsync->fence) { + struct egl_g3d_display *gdpy = + egl_g3d_display(gsync->base.Resource.Display); + struct pipe_screen *screen = gdpy->native->screen; + + screen->fence_reference(screen, &gsync->fence, NULL); + } + + FREE(gsync); + } +} + +_EGLSync * +egl_g3d_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, + EGLenum type, const EGLint *attrib_list) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + struct egl_g3d_sync *gsync; + EGLint err; + + if (!ctx || ctx->Resource.Display != dpy) { + _eglError(EGL_BAD_MATCH, "eglCreateSyncKHR"); + return NULL; + } + + gsync = CALLOC_STRUCT(egl_g3d_sync); + if (!gsync) { + _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR"); + return NULL; + } + + if (!_eglInitSync(&gsync->base, dpy, type, attrib_list)) { + FREE(gsync); + return NULL; + } + + switch (type) { + case EGL_SYNC_REUSABLE_KHR: + err = EGL_SUCCESS; + break; + case EGL_SYNC_FENCE_KHR: + err = egl_g3d_insert_fence_sync(gsync); + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglError(err, "eglCreateSyncKHR"); + FREE(gsync); + return NULL; + } + + pipe_mutex_init(gsync->mutex); + pipe_condvar_init(gsync->condvar); + p_atomic_set(&gsync->refs, 1); + + return &gsync->base; +} + +EGLBoolean +egl_g3d_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) +{ + struct egl_g3d_sync *gsync = egl_g3d_sync(sync); + + switch (gsync->base.Type) { + case EGL_SYNC_REUSABLE_KHR: + /* signal the waiters */ + if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) { + gsync->base.SyncStatus = EGL_SIGNALED_KHR; + egl_g3d_signal_sync_condvar(gsync); + } + break; + default: + break; + } + + egl_g3d_unref_sync(gsync); + + return EGL_TRUE; +} + +EGLint +egl_g3d_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLint flags, EGLTimeKHR timeout) +{ + struct egl_g3d_sync *gsync = egl_g3d_sync(sync); + EGLint ret = EGL_CONDITION_SATISFIED_KHR; + + if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) { + /* flush if there is a current context */ + if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) { + _EGLContext *ctx = _eglGetCurrentContext(); + struct egl_g3d_context *gctx = egl_g3d_context(ctx); + + if (gctx) + gctx->stctxi->flush(gctx->stctxi, PIPE_FLUSH_RENDER_CACHE , NULL); + } + + if (timeout) { + /* reference the sync object in case it is destroyed while waiting */ + egl_g3d_ref_sync(gsync); + + switch (gsync->base.Type) { + case EGL_SYNC_REUSABLE_KHR: + ret = egl_g3d_wait_sync_condvar(gsync, timeout); + break; + case EGL_SYNC_FENCE_KHR: + ret = egl_g3d_wait_fence_sync(gsync, timeout); + default: + break; + } + + egl_g3d_unref_sync(gsync); + } + else { + ret = EGL_TIMEOUT_EXPIRED_KHR; + } + } + + return ret; +} + +EGLBoolean +egl_g3d_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLenum mode) +{ + struct egl_g3d_sync *gsync = egl_g3d_sync(sync); + + /* only for reusable sync */ + if (sync->Type != EGL_SYNC_REUSABLE_KHR) + return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR"); + + if (gsync->base.SyncStatus != mode) { + gsync->base.SyncStatus = mode; + if (mode == EGL_SIGNALED_KHR) + egl_g3d_signal_sync_condvar(gsync); + } + + return EGL_TRUE; +} + +#endif /* EGL_KHR_reusable_sync */ diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_sync.h b/src/gallium/state_trackers/egl/common/egl_g3d_sync.h new file mode 100644 index 0000000000..3179ca04e1 --- /dev/null +++ b/src/gallium/state_trackers/egl/common/egl_g3d_sync.h @@ -0,0 +1,53 @@ +/* + * Mesa 3-D graphics library + * Version: 7.9 + * + * Copyright (C) 2010 LunarG Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Chia-I Wu <olv@lunarg.com> + */ + +#ifndef _EGL_G3D_SYNC_H_ +#define _EGL_G3D_SYNC_H_ + +#include "egl_g3d.h" + +#ifdef EGL_KHR_reusable_sync + +_EGLSync * +egl_g3d_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, + EGLenum type, const EGLint *attrib_list); + +EGLBoolean +egl_g3d_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync); + +EGLint +egl_g3d_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLint flags, EGLTimeKHR timeout); + +EGLBoolean +egl_g3d_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLenum mode); + +#endif /* EGL_KHR_reusable_sync */ + +#endif /* _EGL_G3D_SYNC_H_ */ diff --git a/src/gallium/state_trackers/egl/kms/native_kms.c b/src/gallium/state_trackers/egl/kms/native_kms.c index d4e8fbc913..208f73306c 100644 --- a/src/gallium/state_trackers/egl/kms/native_kms.c +++ b/src/gallium/state_trackers/egl/kms/native_kms.c @@ -38,6 +38,10 @@ #include "native_kms.h" +/* see get_drm_screen_name */ +#include <radeon_drm.h> +#include "radeon/drm/radeon_drm.h" + static boolean kms_surface_validate(struct native_surface *nsurf, uint attachment_mask, unsigned int *seq_num, struct pipe_resource **textures, @@ -584,7 +588,9 @@ kms_display_get_configs(struct native_display *ndpy, int *num_configs) nconf->color_format = format; - nconf->scanout_bit = TRUE; + /* support KMS */ + if (kdpy->resources) + nconf->scanout_bit = TRUE; } configs = MALLOC(sizeof(*configs)); @@ -664,6 +670,27 @@ kms_display_destroy(struct native_display *ndpy) FREE(kdpy); } +static const char * +get_drm_screen_name(int fd, drmVersionPtr version) +{ + const char *name = version->name; + + if (name && !strcmp(name, "radeon")) { + int chip_id; + struct drm_radeon_info info; + + memset(&info, 0, sizeof(info)); + info.request = RADEON_INFO_DEVICE_ID; + info.value = pointer_to_intptr(&chip_id); + if (drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)) != 0) + return NULL; + + name = is_r3xx(chip_id) ? "r300" : "r600"; + } + + return name; +} + /** * Initialize KMS and pipe screen. */ @@ -672,6 +699,7 @@ kms_display_init_screen(struct native_display *ndpy) { struct kms_display *kdpy = kms_display(ndpy); drmVersionPtr version; + const char *name; version = drmGetVersion(kdpy->fd); if (!version) { @@ -679,8 +707,11 @@ kms_display_init_screen(struct native_display *ndpy) return FALSE; } - kdpy->base.screen = kdpy->event_handler->new_drm_screen(&kdpy->base, - version->name, kdpy->fd);; + name = get_drm_screen_name(kdpy->fd, version); + if (name) { + kdpy->base.screen = + kdpy->event_handler->new_drm_screen(&kdpy->base, name, kdpy->fd); + } drmFreeVersion(version); if (!kdpy->base.screen) { @@ -717,32 +748,32 @@ kms_create_display(int fd, struct native_event_handler *event_handler, return NULL; } + kdpy->base.destroy = kms_display_destroy; + kdpy->base.get_param = kms_display_get_param; + kdpy->base.get_configs = kms_display_get_configs; + /* resources are fixed, unlike crtc, connector, or encoder */ kdpy->resources = drmModeGetResources(kdpy->fd); - if (!kdpy->resources) { - kms_display_destroy(&kdpy->base); - return NULL; - } + if (kdpy->resources) { + kdpy->saved_crtcs = + CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->saved_crtcs)); + if (!kdpy->saved_crtcs) { + kms_display_destroy(&kdpy->base); + return NULL; + } - kdpy->saved_crtcs = - CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->saved_crtcs)); - if (!kdpy->saved_crtcs) { - kms_display_destroy(&kdpy->base); - return NULL; - } + kdpy->shown_surfaces = + CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->shown_surfaces)); + if (!kdpy->shown_surfaces) { + kms_display_destroy(&kdpy->base); + return NULL; + } - kdpy->shown_surfaces = - CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->shown_surfaces)); - if (!kdpy->shown_surfaces) { - kms_display_destroy(&kdpy->base); - return NULL; + kdpy->base.modeset = &kms_display_modeset; + } + else { + _eglLog(_EGL_DEBUG, "Failed to get KMS resources. Disable modeset."); } - - kdpy->base.destroy = kms_display_destroy; - kdpy->base.get_param = kms_display_get_param; - kdpy->base.get_configs = kms_display_get_configs; - - kdpy->base.modeset = &kms_display_modeset; return &kdpy->base; } diff --git a/src/gallium/state_trackers/glx/xlib/glx_api.c b/src/gallium/state_trackers/glx/xlib/glx_api.c index eb8d6a1933..dcd50e19d7 100644 --- a/src/gallium/state_trackers/glx/xlib/glx_api.c +++ b/src/gallium/state_trackers/glx/xlib/glx_api.c @@ -34,10 +34,6 @@ #include "GL/glx.h" #include "xm_api.h" -#include "main/context.h" -#include "main/macros.h" -#include "main/imports.h" -#include "main/version.h" /* This indicates the client-side GLX API and GLX encoder version. */ @@ -603,8 +599,8 @@ destroy_visuals_on_display(Display *dpy) static int close_display_callback(Display *dpy, XExtCodes *codes) { - destroy_visuals_on_display(dpy); xmesa_destroy_buffers_on_display(dpy); + destroy_visuals_on_display(dpy); return 0; } @@ -1299,7 +1295,7 @@ glXCopyContext( Display *dpy, GLXContext src, GLXContext dst, XMesaContext xm_dst = dst->xmesaContext; (void) dpy; if (MakeCurrent_PrevContext == src) { - _mesa_Flush(); + glFlush(); } XMesaCopyContext(xm_src, xm_dst, mask); } diff --git a/src/gallium/state_trackers/glx/xlib/glx_usefont.c b/src/gallium/state_trackers/glx/xlib/glx_usefont.c index 8903b0e6cb..0aa37e150b 100644 --- a/src/gallium/state_trackers/glx/xlib/glx_usefont.c +++ b/src/gallium/state_trackers/glx/xlib/glx_usefont.c @@ -30,8 +30,7 @@ */ -#include "main/context.h" -#include "main/imports.h" +#include "main/core.h" #include <GL/glx.h> diff --git a/src/gallium/state_trackers/glx/xlib/xm_api.c b/src/gallium/state_trackers/glx/xlib/xm_api.c index c0c418306f..eb4ce74266 100644 --- a/src/gallium/state_trackers/glx/xlib/xm_api.c +++ b/src/gallium/state_trackers/glx/xlib/xm_api.c @@ -56,7 +56,6 @@ #include "xm_api.h" #include "xm_st.h" -#include "main/context.h" #include "pipe/p_defines.h" #include "pipe/p_screen.h" #include "pipe/p_context.h" @@ -72,10 +71,35 @@ static struct xm_driver driver; static struct st_api *stapi; +/* Default strict invalidate to false. This means we will not call + * XGetGeometry after every swapbuffers, which allows swapbuffers to + * remain asynchronous. For apps running at 100fps with synchronous + * swapping, a 10% boost is typical. For gears, I see closer to 20% + * speedup. + * + * Note that the work of copying data on swapbuffers doesn't disappear + * - this change just allows the X server to execute the PutImage + * asynchronously without us effectively blocked until its completion. + * + * This speeds up even llvmpipe's threaded rasterization as the + * swapbuffers operation was a large part of the serial component of + * an llvmpipe frame. + * + * The downside of this is correctness - applications which don't call + * glViewport on window resizes will get incorrect rendering. A + * better solution would be to have per-frame but asynchronous + * invalidation. Xcb almost looks as if it could provide this, but + * the API doesn't seem to quite be there. + */ +boolean xmesa_strict_invalidate = FALSE; + void xmesa_set_driver( const struct xm_driver *templ ) { driver = *templ; stapi = driver.create_st_api(); + + xmesa_strict_invalidate = + debug_get_bool_option("XMESA_STRICT_INVALIDATE", FALSE); } @@ -91,7 +115,12 @@ static int xmesa_get_param(struct st_manager *smapi, enum st_manager_param param) { - return 0; + switch(param) { + case ST_MANAGER_BROKEN_INVALIDATE: + return !xmesa_strict_invalidate; + default: + return 0; + } } static XMesaDisplay @@ -263,7 +292,6 @@ xmesa_get_window_size(Display *dpy, XMesaBuffer b, Status stat; pipe_mutex_lock(xmdpy->mutex); - XSync(b->xm_visual->display, 0); /* added for Chromium */ stat = get_drawable_size(dpy, b->ws.drawable, width, height); pipe_mutex_unlock(xmdpy->mutex); @@ -726,15 +754,39 @@ XMesaVisual XMesaCreateVisual( Display *display, alpha_bits = v->mesa_visual.alphaBits; } - _mesa_initialize_visual( &v->mesa_visual, - db_flag, stereo_flag, - red_bits, green_bits, - blue_bits, alpha_bits, - depth_size, - stencil_size, - accum_red_size, accum_green_size, - accum_blue_size, accum_alpha_size, - 0 ); + /* initialize visual */ + { + __GLcontextModes *vis = &v->mesa_visual; + + vis->rgbMode = GL_TRUE; + vis->doubleBufferMode = db_flag; + vis->stereoMode = stereo_flag; + + vis->redBits = red_bits; + vis->greenBits = green_bits; + vis->blueBits = blue_bits; + vis->alphaBits = alpha_bits; + vis->rgbBits = red_bits + green_bits + blue_bits; + + vis->indexBits = 0; + vis->depthBits = depth_size; + vis->stencilBits = stencil_size; + + vis->accumRedBits = accum_red_size; + vis->accumGreenBits = accum_green_size; + vis->accumBlueBits = accum_blue_size; + vis->accumAlphaBits = accum_alpha_size; + + vis->haveAccumBuffer = accum_red_size > 0; + vis->haveDepthBuffer = depth_size > 0; + vis->haveStencilBuffer = stencil_size > 0; + + vis->numAuxBuffers = 0; + vis->level = 0; + vis->pixmapMode = 0; + vis->sampleBuffers = 0; + vis->samples = 0; + } v->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK; if (db_flag) @@ -1154,7 +1206,7 @@ void XMesaFlush( XMesaContext c ) xmdpy->screen->fence_finish(xmdpy->screen, fence, 0); xmdpy->screen->fence_reference(xmdpy->screen, &fence, NULL); } - XSync( c->xm_visual->display, False ); + XFlush( c->xm_visual->display ); } } diff --git a/src/gallium/state_trackers/glx/xlib/xm_api.h b/src/gallium/state_trackers/glx/xlib/xm_api.h index 4f2c8a6e6a..f209b14ea1 100644 --- a/src/gallium/state_trackers/glx/xlib/xm_api.h +++ b/src/gallium/state_trackers/glx/xlib/xm_api.h @@ -57,7 +57,7 @@ and create a window, you must do the following to use the X/Mesa interface: #define XMESA_H -#include "main/mtypes.h" +#include "main/core.h" /* for GLvisual and MESA_VERSION_STRING */ #include "state_tracker/st_api.h" #include "os/os_thread.h" @@ -378,6 +378,6 @@ xmesa_buffer_height(XMesaBuffer b) return b->height; } - +extern boolean xmesa_strict_invalidate; #endif diff --git a/src/gallium/state_trackers/glx/xlib/xm_st.c b/src/gallium/state_trackers/glx/xlib/xm_st.c index c62eb8bfbd..0f74b3f7aa 100644 --- a/src/gallium/state_trackers/glx/xlib/xm_st.c +++ b/src/gallium/state_trackers/glx/xlib/xm_st.c @@ -26,18 +26,18 @@ * Chia-I Wu <olv@lunarg.com> */ -#include "util/u_memory.h" -#include "util/u_inlines.h" - #include "xm_api.h" #include "xm_st.h" +#include "util/u_inlines.h" + struct xmesa_st_framebuffer { XMesaDisplay display; XMesaBuffer buffer; struct pipe_screen *screen; struct st_visual stvis; + enum pipe_texture_target target; unsigned texture_width, texture_height, texture_mask; struct pipe_resource *textures[ST_ATTACHMENT_COUNT]; @@ -139,7 +139,7 @@ xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi, } memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; + templ.target = xstfb->target; templ.width0 = width; templ.height0 = height; templ.depth0 = 1; @@ -210,6 +210,12 @@ xmesa_st_framebuffer_validate(struct st_framebuffer_iface *stfbi, /* record newly allocated textures */ new_mask = statt_mask & ~xstfb->texture_mask; + /* If xmesa_strict_invalidate is not set, we will not yet have + * called XGetGeometry(). Do so here: + */ + if (!xmesa_strict_invalidate) + xmesa_check_buffer_size(xstfb->buffer); + resized = (xstfb->buffer->width != xstfb->texture_width || xstfb->buffer->height != xstfb->texture_height); @@ -251,7 +257,8 @@ xmesa_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi, boolean ret; ret = xmesa_st_framebuffer_display(stfbi, statt); - if (ret) + + if (ret && xmesa_strict_invalidate) xmesa_check_buffer_size(xstfb->buffer); return ret; @@ -279,6 +286,10 @@ xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b) xstfb->buffer = b; xstfb->screen = xmdpy->screen; xstfb->stvis = b->xm_visual->stvis; + if(xstfb->screen->get_param(xstfb->screen, PIPE_CAP_NPOT_TEXTURES)) + xstfb->target = PIPE_TEXTURE_2D; + else + xstfb->target = PIPE_TEXTURE_RECT; stfbi->visual = &xstfb->stvis; stfbi->flush_front = xmesa_st_framebuffer_flush_front; @@ -322,7 +333,8 @@ xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi) *back = tmp; } - xmesa_check_buffer_size(xstfb->buffer); + if (xmesa_strict_invalidate) + xmesa_check_buffer_size(xstfb->buffer); } } diff --git a/src/gallium/state_trackers/wgl/stw_context.c b/src/gallium/state_trackers/wgl/stw_context.c index 0fb7cd8306..a0e14b9601 100644 --- a/src/gallium/state_trackers/wgl/stw_context.c +++ b/src/gallium/state_trackers/wgl/stw_context.c @@ -33,7 +33,7 @@ /* for _mesa_share_state */ #include "state_tracker/st_context.h" -#include "main/context.h" +#include "main/core.h" #include "stw_icd.h" #include "stw_device.h" diff --git a/src/gallium/state_trackers/wgl/stw_device.c b/src/gallium/state_trackers/wgl/stw_device.c index a107c71bda..37809d084c 100644 --- a/src/gallium/state_trackers/wgl/stw_device.c +++ b/src/gallium/state_trackers/wgl/stw_device.c @@ -27,7 +27,7 @@ #include <windows.h> -#include "glapi/glthread.h" +#include "glapi/glapi.h" #include "util/u_debug.h" #include "util/u_math.h" #include "util/u_memory.h" diff --git a/src/gallium/state_trackers/wgl/stw_pixelformat.c b/src/gallium/state_trackers/wgl/stw_pixelformat.c index e606477e97..18ac482369 100644 --- a/src/gallium/state_trackers/wgl/stw_pixelformat.c +++ b/src/gallium/state_trackers/wgl/stw_pixelformat.c @@ -25,15 +25,13 @@ * **************************************************************************/ -#include "main/mtypes.h" -#include "main/context.h" - #include "pipe/p_format.h" #include "pipe/p_defines.h" #include "pipe/p_screen.h" #include "util/u_format.h" #include "util/u_debug.h" +#include "util/u_memory.h" #include "stw_icd.h" #include "stw_device.h" diff --git a/src/gallium/state_trackers/wgl/stw_pixelformat.h b/src/gallium/state_trackers/wgl/stw_pixelformat.h index d405172773..282c9f643c 100644 --- a/src/gallium/state_trackers/wgl/stw_pixelformat.h +++ b/src/gallium/state_trackers/wgl/stw_pixelformat.h @@ -34,8 +34,6 @@ #define PFD_SUPPORT_COMPOSITION 0x00008000 #endif -#include "main/mtypes.h" - #include "pipe/p_compiler.h" #include "pipe/p_format.h" #include "state_tracker/st_api.h" diff --git a/src/gallium/targets/Makefile.dri b/src/gallium/targets/Makefile.dri index de05f96d23..59961e982a 100644 --- a/src/gallium/targets/Makefile.dri +++ b/src/gallium/targets/Makefile.dri @@ -1,11 +1,12 @@ # -*-makefile-*- + ifeq ($(MESA_LLVM),1) PIPE_DRIVERS += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a LDFLAGS += $(LLVM_LDFLAGS) -LD = g++ DRIVER_EXTRAS = $(LLVM_LIBS) -USE_CXX=1 +else +LDFLAGS += -lstdc++ endif MESA_MODULES = \ @@ -75,15 +76,11 @@ default: depend symlinks $(TOP)/$(LIB_DIR)/gallium $(LIBNAME) $(LIBNAME_STAGING) $(LIBNAME): $(OBJECTS) $(MESA_MODULES) $(PIPE_DRIVERS) Makefile \ $(TOP)/src/mesa/drivers/dri/Makefile.template $(TOP)/src/mesa/drivers/dri/common/dri_test.o - $(MKLIB) -o $@.tmp -noprefix -linker '$(CC)' -ldflags '$(LDFLAGS)' \ + $(MKLIB) -o $@.tmp -noprefix -linker '$(CXX)' -ldflags '$(LDFLAGS)' \ $(OBJECTS) $(PIPE_DRIVERS) \ -Wl,--start-group $(MESA_MODULES) -Wl,--end-group \ $(DRI_LIB_DEPS) $(DRIVER_EXTRAS) - if [ "x${USE_CXX}" == "x" ]; then \ - $(CC) $(CFLAGS) -o $@.test $(TOP)/src/mesa/drivers/dri/common/dri_test.o $@.tmp $(DRI_LIB_DEPS); \ - else \ - $(CXX) $(CFLAGS) -o $@.test $(TOP)/src/mesa/drivers/dri/common/dri_test.o $@.tmp $(DRI_LIB_DEPS); \ - fi + $(CXX) $(CFLAGS) -o $@.test $(TOP)/src/mesa/drivers/dri/common/dri_test.o $@.tmp $(DRI_LIB_DEPS); @rm -f $@.test mv -f $@.tmp $@ diff --git a/src/gallium/targets/SConscript b/src/gallium/targets/SConscript index f8276b1555..e447d09361 100644 --- a/src/gallium/targets/SConscript +++ b/src/gallium/targets/SConscript @@ -1,18 +1,13 @@ import os Import('*') - + # Compatibility with old build scripts: # if 'mesa' in env['statetrackers']: - if 'xlib' in env['winsys']: - SConscript([ - 'libgl-xlib/SConscript', - ]) - - if 'gdi' in env['winsys']: - SConscript([ - 'libgl-gdi/SConscript', - ]) + if 'xlib' in env['winsys'] and 'libgl-xlib' not in env['targets']: + env['targets'].append('libgl-xlib') + if 'gdi' in env['winsys'] and 'libgl-gdi' not in env['targets']: + env['targets'].append('libgl-gdi') if not 'graw-xlib' in env['targets'] and not 'graw-null' in env['targets'] and not env['msvc']: # XXX: disable until MSVC can link correctly diff --git a/src/gallium/targets/dri-radeong/Makefile b/src/gallium/targets/dri-r300/Makefile index 3f9ec36166..9afbb13276 100644 --- a/src/gallium/targets/dri-radeong/Makefile +++ b/src/gallium/targets/dri-r300/Makefile @@ -1,7 +1,7 @@ TOP = ../../../.. include $(TOP)/configs/current -LIBNAME = radeong_dri.so +LIBNAME = r300_dri.so PIPE_DRIVERS = \ $(TOP)/src/gallium/state_trackers/dri/drm/libdridrm.a \ diff --git a/src/gallium/targets/dri-radeong/SConscript b/src/gallium/targets/dri-r300/SConscript index 1402c3bd12..33a458f2e6 100644 --- a/src/gallium/targets/dri-radeong/SConscript +++ b/src/gallium/targets/dri-r300/SConscript @@ -1,7 +1,7 @@ Import('*') if not 'r300' in env['drivers']: - print 'warning: r300 pipe driver not built skipping radeong_dri.so' + print 'warning: r300 pipe driver not built skipping r300_dri.so' Return() env = drienv.Clone() @@ -24,7 +24,7 @@ env.Prepend(LIBS = [ ]) env.SharedLibrary( - target ='radeon_dri.so', + target ='r300_dri.so', source = 'target.c', SHLIBPREFIX = '', ) diff --git a/src/gallium/targets/dri-radeong/target.c b/src/gallium/targets/dri-r300/target.c index 5a0a8dc573..2ecf3457a7 100644 --- a/src/gallium/targets/dri-radeong/target.c +++ b/src/gallium/targets/dri-r300/target.c @@ -23,4 +23,4 @@ create_screen(int fd) return screen; } -DRM_DRIVER_DESCRIPTOR("radeon", "radeon", create_screen) +DRM_DRIVER_DESCRIPTOR("r300", "radeon", create_screen) diff --git a/src/gallium/targets/dri-r600/Makefile b/src/gallium/targets/dri-r600/Makefile index 932303d194..661283de6a 100644 --- a/src/gallium/targets/dri-r600/Makefile +++ b/src/gallium/targets/dri-r600/Makefile @@ -4,12 +4,12 @@ include $(TOP)/configs/current LIBNAME = r600_dri.so PIPE_DRIVERS = \ + $(TOP)/src/gallium/drivers/r600/libr600.a \ $(TOP)/src/gallium/state_trackers/dri/drm/libdridrm.a \ $(TOP)/src/gallium/winsys/r600/drm/libr600winsys.a \ $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \ $(TOP)/src/gallium/drivers/trace/libtrace.a \ - $(TOP)/src/gallium/drivers/rbug/librbug.a \ - $(TOP)/src/gallium/drivers/r600/libr600.a + $(TOP)/src/gallium/drivers/rbug/librbug.a C_SOURCES = \ target.c \ @@ -21,6 +21,6 @@ DRIVER_DEFINES = \ include ../Makefile.dri -DRI_LIB_DEPS += -ldrm_radeon +DRI_LIB_DEPS += symlinks: diff --git a/src/gallium/targets/egl-gdi/egl-static.c b/src/gallium/targets/egl-gdi/egl-static.c index ec2f865c31..4655d79117 100644 --- a/src/gallium/targets/egl-gdi/egl-static.c +++ b/src/gallium/targets/egl-gdi/egl-static.c @@ -33,6 +33,8 @@ #include "target-helpers/inline_debug_helper.h" #include "egldriver.h" +static struct st_api *stapis[ST_API_COUNT]; + static uint get_api_mask(void) { @@ -57,7 +59,11 @@ get_api_mask(void) static struct st_api * get_st_api(enum st_api_type api) { - struct st_api *stapi = NULL; + struct st_api *stapi; + + stapi = stapis[api]; + if (stapi) + return stapi; switch (api) { #if FEATURE_GL @@ -84,13 +90,33 @@ get_st_api(enum st_api_type api) break; } + stapis[api] = stapi; + return stapi; } static struct st_api * guess_gl_api(void) { - return NULL; + struct st_api *stapi = NULL; + +#if FEATURE_GL + stapi = get_st_api(ST_API_OPENGL); + if (stapi) + return stapi; +#endif +#if FEATURE_ES1 + stapi = get_st_api(ST_API_OPENGL_ES1); + if (stapi) + return stapi; +#endif +#if FEATURE_ES2 + stapi = get_st_api(ST_API_OPENGL_ES2); + if (stapi) + return stapi; +#endif + + return stapi; } static struct pipe_screen * @@ -127,7 +153,16 @@ init_loader(struct egl_g3d_loader *loader) static void egl_g3d_unload(_EGLDriver *drv) { + int i; + egl_g3d_destroy_driver(drv); + + for (i = 0; i < ST_API_COUNT; i++) { + if (stapis[i]) { + stapis[i]->destroy(stapis[i]); + stapis[i] = NULL; + } + } } static struct egl_g3d_loader loader; diff --git a/src/gallium/targets/egl/Makefile b/src/gallium/targets/egl/Makefile index 1e4bb4d94c..2784fd0d10 100644 --- a/src/gallium/targets/egl/Makefile +++ b/src/gallium/targets/egl/Makefile @@ -90,13 +90,20 @@ nouveau_LIBS := \ $(TOP)/src/gallium/drivers/nv50/libnv50.a \ $(TOP)/src/gallium/drivers/nouveau/libnouveau.a -# radeon pipe driver -radeon_CPPFLAGS := -radeon_SYS := -ldrm -ldrm_radeon -radeon_LIBS := \ +# r300 pipe driver +r300_CPPFLAGS := +r300_SYS := -ldrm -ldrm_radeon +r300_LIBS := \ $(TOP)/src/gallium/winsys/radeon/drm/libradeonwinsys.a \ $(TOP)/src/gallium/drivers/r300/libr300.a +# r600 pipe driver +r600_CPPFLAGS := +r600_SYS := -ldrm -ldrm_radeon +r600_LIBS := \ + $(TOP)/src/gallium/winsys/r600/drm/libr600winsys.a \ + $(TOP)/src/gallium/drivers/r600/libr600.a + # vmwgfx pipe driver vmwgfx_CPPFLAGS := vmwgfx_SYS := @@ -119,17 +126,17 @@ endif # OpenGL state tracker GL_CPPFLAGS := -I$(TOP)/src/mesa $(API_DEFINES) -GL_SYS := -lpthread -lm -L$(TOP)/$(LIB_DIR) -l$(GL_LIB) +GL_SYS := $(DRI_LIB_DEPS) -L$(TOP)/$(LIB_DIR) -l$(GL_LIB) GL_LIBS := $(TOP)/src/mesa/libmesagallium.a # OpenGL ES 1.x state tracker GLESv1_CM_CPPFLAGS := -I$(TOP)/src/mesa -GLESv1_CM_SYS := -lpthread -lm -L$(TOP)/$(LIB_DIR) -l$(GLESv1_CM_LIB) +GLESv1_CM_SYS := $(DRI_LIB_DEPS) -L$(TOP)/$(LIB_DIR) -l$(GLESv1_CM_LIB) GLESv1_CM_LIBS := $(TOP)/src/mesa/libes1gallium.a # OpenGL ES 2.x state tracker GLESv2_CPPFLAGS := -I$(TOP)/src/mesa -GLESv2_SYS := -lpthread -lm -L$(TOP)/$(LIB_DIR) -l$(GLESv2_LIB) +GLESv2_SYS := $(DRI_LIB_DEPS) -L$(TOP)/$(LIB_DIR) -l$(GLESv2_LIB) GLESv2_LIBS := $(TOP)/src/mesa/libes2gallium.a # OpenVG state tracker @@ -151,7 +158,10 @@ ifneq ($(findstring nouveau/drm,$(GALLIUM_WINSYS_DIRS)),) OUTPUTS += nouveau endif ifneq ($(findstring radeon/drm,$(GALLIUM_WINSYS_DIRS)),) -OUTPUTS += radeon +OUTPUTS += r300 +endif +ifneq ($(findstring r600/drm,$(GALLIUM_WINSYS_DIRS)),) +OUTPUTS += r600 endif ifneq ($(findstring svga/drm,$(GALLIUM_WINSYS_DIRS)),) OUTPUTS += vmwgfx @@ -188,8 +198,11 @@ $(OUTPUT_PATH)/$(PIPE_PREFIX)i965.so: pipe_i965.o $(i965_LIBS) $(OUTPUT_PATH)/$(PIPE_PREFIX)nouveau.so: pipe_nouveau.o $(nouveau_LIBS) $(call mklib,nouveau) -$(OUTPUT_PATH)/$(PIPE_PREFIX)radeon.so: pipe_radeon.o $(radeon_LIBS) - $(call mklib,radeon) +$(OUTPUT_PATH)/$(PIPE_PREFIX)r300.so: pipe_r300.o $(r300_LIBS) + $(call mklib,r300) + +$(OUTPUT_PATH)/$(PIPE_PREFIX)r600.so: pipe_r600.o $(r600_LIBS) + $(call mklib,r600) $(OUTPUT_PATH)/$(PIPE_PREFIX)vmwgfx.so: pipe_vmwgfx.o $(vmwgfx_LIBS) $(call mklib,vmwgfx) diff --git a/src/gallium/targets/egl/egl.c b/src/gallium/targets/egl/egl.c index d9d89485c3..a573b21217 100644 --- a/src/gallium/targets/egl/egl.c +++ b/src/gallium/targets/egl/egl.c @@ -155,24 +155,23 @@ load_pipe_module(struct pipe_module *pmod, const char *name) if (!pmod->name) return FALSE; + _eglLog(_EGL_DEBUG, "searching for pipe module %s", pmod->name); _eglSearchPathForEach(dlopen_pipe_module_cb, (void *) pmod); if (pmod->lib) { pmod->drmdd = (const struct drm_driver_descriptor *) util_dl_get_proc_address(pmod->lib, "driver_descriptor"); - if (pmod->drmdd) { - if (pmod->drmdd->driver_name) { - /* driver name mismatch */ - if (strcmp(pmod->drmdd->driver_name, pmod->name) != 0) - pmod->drmdd = NULL; - } - else { - /* swrast */ - pmod->swrast_create_screen = - (struct pipe_screen *(*)(struct sw_winsys *)) - util_dl_get_proc_address(pmod->lib, "swrast_create_screen"); - if (!pmod->swrast_create_screen) - pmod->drmdd = NULL; - } + + /* sanity check on the name */ + if (pmod->drmdd && strcmp(pmod->drmdd->name, pmod->name) != 0) + pmod->drmdd = NULL; + + /* swrast */ + if (pmod->drmdd && !pmod->drmdd->driver_name) { + pmod->swrast_create_screen = + (struct pipe_screen *(*)(struct sw_winsys *)) + util_dl_get_proc_address(pmod->lib, "swrast_create_screen"); + if (!pmod->swrast_create_screen) + pmod->drmdd = NULL; } if (!pmod->drmdd) { diff --git a/src/gallium/targets/egl/pipe_radeon.c b/src/gallium/targets/egl/pipe_r300.c index 35550bcb26..d84bb92539 100644 --- a/src/gallium/targets/egl/pipe_radeon.c +++ b/src/gallium/targets/egl/pipe_r300.c @@ -24,4 +24,4 @@ create_screen(int fd) } PUBLIC -DRM_DRIVER_DESCRIPTOR("radeon", "radeon", create_screen) +DRM_DRIVER_DESCRIPTOR("r300", "radeon", create_screen) diff --git a/src/gallium/targets/egl/pipe_r600.c b/src/gallium/targets/egl/pipe_r600.c new file mode 100644 index 0000000000..486a659258 --- /dev/null +++ b/src/gallium/targets/egl/pipe_r600.c @@ -0,0 +1,27 @@ + +#include "state_tracker/drm_driver.h" +#include "target-helpers/inline_debug_helper.h" +#include "r600/drm/r600_drm_public.h" +#include "r600/r600_public.h" + +static struct pipe_screen * +create_screen(int fd) +{ + struct radeon *rw; + struct pipe_screen *screen; + + rw = r600_drm_winsys_create(fd); + if (!rw) + return NULL; + + screen = r600_screen_create(rw); + if (!screen) + return NULL; + + screen = debug_screen_wrap(screen); + + return screen; +} + +PUBLIC +DRM_DRIVER_DESCRIPTOR("r600", "radeon", create_screen) diff --git a/src/gallium/targets/graw-xlib/graw_util.c b/src/gallium/targets/graw-xlib/graw_util.c index 47aca4464d..fc7c9ae6f9 100644 --- a/src/gallium/targets/graw-xlib/graw_util.c +++ b/src/gallium/targets/graw-xlib/graw_util.c @@ -1,6 +1,7 @@ #include "pipe/p_compiler.h" #include "pipe/p_context.h" +#include "pipe/p_state.h" #include "tgsi/tgsi_text.h" #include "util/u_memory.h" #include "state_tracker/graw.h" diff --git a/src/gallium/targets/graw-xlib/graw_xlib.c b/src/gallium/targets/graw-xlib/graw_xlib.c index 41120ba3c7..8b64a0b819 100644 --- a/src/gallium/targets/graw-xlib/graw_xlib.c +++ b/src/gallium/targets/graw-xlib/graw_xlib.c @@ -1,5 +1,6 @@ #include "pipe/p_compiler.h" #include "pipe/p_context.h" +#include "pipe/p_screen.h" #include "util/u_debug.h" #include "util/u_memory.h" #include "target-helpers/wrap_screen.h" diff --git a/src/gallium/targets/libgl-gdi/SConscript b/src/gallium/targets/libgl-gdi/SConscript index 144084f74f..12fe403f62 100644 --- a/src/gallium/targets/libgl-gdi/SConscript +++ b/src/gallium/targets/libgl-gdi/SConscript @@ -17,6 +17,7 @@ if env['platform'] == 'windows': 'user32', 'kernel32', 'ws2_32', + talloc, ]) sources = [] diff --git a/src/gallium/targets/libgl-xlib/Makefile b/src/gallium/targets/libgl-xlib/Makefile index e745023ba5..fe0541543a 100644 --- a/src/gallium/targets/libgl-xlib/Makefile +++ b/src/gallium/targets/libgl-xlib/Makefile @@ -68,8 +68,9 @@ $(TOP)/$(LIB_DIR)/gallium: # Make the libGL.so library $(TOP)/$(LIB_DIR)/gallium/$(GL_LIB_NAME): $(XLIB_TARGET_OBJECTS) $(LIBS) Makefile $(TOP)/bin/mklib -o $(GL_LIB) \ - -linker "$(CC)" \ + -linker "$(CXX)" \ -major $(GL_MAJOR) -minor $(GL_MINOR) -patch $(GL_TINY) \ + -cplusplus \ -install $(TOP)/$(LIB_DIR)/gallium \ $(MKLIB_OPTIONS) $(XLIB_TARGET_OBJECTS) \ -Wl,--start-group $(LIBS) -Wl,--end-group $(GL_LIB_DEPS) diff --git a/src/gallium/targets/libgl-xlib/SConscript b/src/gallium/targets/libgl-xlib/SConscript index 78703fd096..88e216a65b 100644 --- a/src/gallium/targets/libgl-xlib/SConscript +++ b/src/gallium/targets/libgl-xlib/SConscript @@ -35,6 +35,7 @@ env.Prepend(LIBS = [ mesa, glsl, gallium, + 'talloc' ]) sources = [ diff --git a/src/gallium/targets/libgl-xlib/xlib.c b/src/gallium/targets/libgl-xlib/xlib.c index 69b4ddd33f..5a9c80c856 100644 --- a/src/gallium/targets/libgl-xlib/xlib.c +++ b/src/gallium/targets/libgl-xlib/xlib.c @@ -36,6 +36,7 @@ #include "state_tracker/xlib_sw_winsys.h" #include "xm_public.h" +#include "state_tracker/st_api.h" #include "state_tracker/st_gl_api.h" /* piggy back on this libGL for OpenGL support in EGL */ diff --git a/src/gallium/tests/python/tests/texture_blit.py b/src/gallium/tests/python/tests/texture_blit.py index 58706dab93..089d05c623 100755 --- a/src/gallium/tests/python/tests/texture_blit.py +++ b/src/gallium/tests/python/tests/texture_blit.py @@ -55,7 +55,7 @@ def tex_coords(texture, face, level, zslice): [0.0, 1.0], ] - if texture.target == PIPE_TEXTURE_2D: + if texture.target == PIPE_TEXTURE_2D or texture.target == PIPE_TEXTURE_RECT: return [[s, t, 0.0] for s, t in st] elif texture.target == PIPE_TEXTURE_3D: depth = texture.get_depth(level) diff --git a/src/gallium/tools/addr2line.sh b/src/gallium/tools/addr2line.sh new file mode 100755 index 0000000000..34dec14271 --- /dev/null +++ b/src/gallium/tools/addr2line.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# This script processes symbols output by Gallium using glibc to human-readable function names + +lastbin= +i=-1 +dir="$(mktemp -d)" +input="$1" + +# Gather all unique addresses for each binary +sed -nre 's|([^ ]*/[^ ]*)\(\+0x([^)]*).*|\1 \2|p' "$input"|sort|uniq|while read bin addr; do + if test "$lastbin" != "$bin"; then + ((++i)) + lastbin="$bin" + echo "$bin" > "$dir/$i.addrs.bin" + fi + echo "$addr" >> "$dir/$i.addrs" +done + +# Construct a sed script to convert hex address to human readable form, and apply it +for i in "$dir"/*.addrs; do + bin="$(<"$i.bin")" + addr2line -p -e "$bin" -a -f < "$i"|sed -nre 's@^0x0*([^:]*): ([^?]*)$@s|'"$bin"'(+0x\1)|\2|g@gp' + rm -f "$i" "$i.bin" +done|sed -f - "$input" + +rmdir "$dir" diff --git a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c index 660dbd0c33..d4bf124ce6 100644 --- a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c +++ b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c @@ -19,7 +19,8 @@ nouveau_drm_destroy_winsys(struct pipe_winsys *s) { struct nouveau_winsys *nv_winsys = nouveau_winsys(s); struct nouveau_screen *nv_screen= nouveau_screen(nv_winsys->pscreen); - nouveau_device_close(&nv_screen->device); + if (nv_screen) + nouveau_device_close(&nv_screen->device); FREE(nv_winsys); } diff --git a/src/gallium/winsys/r600/drm/r600_state.c b/src/gallium/winsys/r600/drm/r600_state.c index d17d6e7954..71d65f0fea 100644 --- a/src/gallium/winsys/r600/drm/r600_state.c +++ b/src/gallium/winsys/r600/drm/r600_state.c @@ -30,6 +30,8 @@ #include "radeon_priv.h" #include "r600d.h" +#include "util/u_memory.h" + static int r600_state_pm4_resource(struct radeon_state *state); static int r600_state_pm4_cb0(struct radeon_state *state); static int r600_state_pm4_vgt(struct radeon_state *state); @@ -38,24 +40,69 @@ static int r600_state_pm4_shader(struct radeon_state *state); static int r600_state_pm4_draw(struct radeon_state *state); static int r600_state_pm4_config(struct radeon_state *state); static int r600_state_pm4_generic(struct radeon_state *state); +static int r600_state_pm4_query_begin(struct radeon_state *state); +static int r600_state_pm4_query_end(struct radeon_state *state); static int r700_state_pm4_config(struct radeon_state *state); static int r700_state_pm4_cb0(struct radeon_state *state); static int r700_state_pm4_db(struct radeon_state *state); #include "r600_states.h" + +#define SUB_NONE(param) { { 0, R600_names_##param, (sizeof(R600_names_##param)/sizeof(struct radeon_register)) } } +#define SUB_PS(param) { R600_SHADER_PS, R600_names_##param, (sizeof(R600_names_##param)/sizeof(struct radeon_register)) } +#define SUB_VS(param) { R600_SHADER_VS, R600_names_##param, (sizeof(R600_names_##param)/sizeof(struct radeon_register)) } +#define SUB_GS(param) { R600_SHADER_GS, R600_names_##param, (sizeof(R600_names_##param)/sizeof(struct radeon_register)) } +#define SUB_FS(param) { R600_SHADER_FS, R600_names_##param, (sizeof(R600_names_##param)/sizeof(struct radeon_register)) } + +/* some of these are overriden at runtime for R700 */ +struct radeon_stype_info r600_stypes[] = { + { R600_STATE_CONFIG, 1, 0, r600_state_pm4_config, SUB_NONE(CONFIG), }, + { R600_STATE_CB_CNTL, 1, 0, r600_state_pm4_generic, SUB_NONE(CB_CNTL) }, + { R600_STATE_RASTERIZER, 1, 0, r600_state_pm4_generic, SUB_NONE(RASTERIZER) }, + { R600_STATE_VIEWPORT, 1, 0, r600_state_pm4_generic, SUB_NONE(VIEWPORT) }, + { R600_STATE_SCISSOR, 1, 0, r600_state_pm4_generic, SUB_NONE(SCISSOR) }, + { R600_STATE_BLEND, 1, 0, r600_state_pm4_generic, SUB_NONE(BLEND), }, + { R600_STATE_DSA, 1, 0, r600_state_pm4_generic, SUB_NONE(DSA), }, + { R600_STATE_SHADER, 1, 0, r600_state_pm4_shader, { SUB_PS(PS_SHADER), SUB_VS(VS_SHADER) } }, + { R600_STATE_CONSTANT, 256, 0x10, r600_state_pm4_generic, { SUB_PS(PS_CONSTANT), SUB_VS(VS_CONSTANT) } }, + { R600_STATE_RESOURCE, 160, 0x1c, r600_state_pm4_resource, { SUB_PS(PS_RESOURCE), SUB_VS(VS_RESOURCE), SUB_GS(GS_RESOURCE), SUB_FS(FS_RESOURCE)} }, + { R600_STATE_SAMPLER, 18, 0xc, r600_state_pm4_generic, { SUB_PS(PS_SAMPLER), SUB_VS(VS_SAMPLER), SUB_GS(GS_SAMPLER) } }, + { R600_STATE_SAMPLER_BORDER, 18, 0x10, r600_state_pm4_generic, { SUB_PS(PS_SAMPLER_BORDER), SUB_VS(VS_SAMPLER_BORDER), SUB_GS(GS_SAMPLER_BORDER) } }, + { R600_STATE_CB0, 1, 0, r600_state_pm4_cb0, SUB_NONE(CB0) }, + { R600_STATE_CB1, 1, 0, r600_state_pm4_cb0, SUB_NONE(CB1) }, + { R600_STATE_CB2, 1, 0, r600_state_pm4_cb0, SUB_NONE(CB2) }, + { R600_STATE_CB3, 1, 0, r600_state_pm4_cb0, SUB_NONE(CB3) }, + { R600_STATE_CB4, 1, 0, r600_state_pm4_cb0, SUB_NONE(CB4) }, + { R600_STATE_CB5, 1, 0, r600_state_pm4_cb0, SUB_NONE(CB5) }, + { R600_STATE_CB6, 1, 0, r600_state_pm4_cb0, SUB_NONE(CB6) }, + { R600_STATE_CB7, 1, 0, r600_state_pm4_cb0, SUB_NONE(CB7) }, + { R600_STATE_QUERY_BEGIN, 1, 0, r600_state_pm4_query_begin, SUB_NONE(VGT_EVENT) }, + { R600_STATE_QUERY_END, 1, 0, r600_state_pm4_query_end, SUB_NONE(VGT_EVENT) }, + { R600_STATE_DB, 1, 0, r600_state_pm4_db, SUB_NONE(DB) }, + { R600_STATE_UCP, 1, 0, r600_state_pm4_generic, SUB_NONE(UCP) }, + { R600_STATE_VGT, 1, 0, r600_state_pm4_vgt, SUB_NONE(VGT) }, + { R600_STATE_DRAW, 1, 0, r600_state_pm4_draw, SUB_NONE(DRAW) }, +}; +#define STYPES_SIZE Elements(r600_stypes) + +static const struct radeon_register *get_regs(struct radeon_state *state) +{ + return state->stype->reginfo[state->shader_index].regs; +} + /* * r600/r700 state functions */ static int r600_state_pm4_bytecode(struct radeon_state *state, unsigned offset, unsigned id, unsigned nreg) { - const struct radeon_register *regs = state->radeon->type[state->type].regs; + const struct radeon_register *regs = get_regs(state); unsigned i; int r; if (!offset) { fprintf(stderr, "%s invalid register for state %d %d\n", - __func__, state->type, id); + __func__, state->stype->stype, id); return -EINVAL; } if (offset >= R600_CONFIG_REG_OFFSET && offset < R600_CONFIG_REG_END) { @@ -114,19 +161,18 @@ static int r600_state_pm4_bytecode(struct radeon_state *state, unsigned offset, static int r600_state_pm4_generic(struct radeon_state *state) { - struct radeon *radeon = state->radeon; - unsigned i, offset, nreg, type, coffset, loffset, soffset; + const struct radeon_register *regs = get_regs(state); + unsigned i, offset, nreg, coffset, loffset, soffset; unsigned start; int r; if (!state->nstates) return 0; - type = state->type; - soffset = (state->id - radeon->type[type].id) * radeon->type[type].stride; - offset = loffset = radeon->type[type].regs[0].offset + soffset; + soffset = state->id * state->stype->stride; + offset = loffset = regs[0].offset + soffset; start = 0; for (i = 1, nreg = 1; i < state->nstates; i++) { - coffset = radeon->type[type].regs[i].offset + soffset; + coffset = regs[i].offset + soffset; if (coffset == (loffset + 4)) { nreg++; loffset = coffset; @@ -233,20 +279,54 @@ static int r600_state_pm4_config(struct radeon_state *state) state->pm4[state->cpm4++] = 0x80000000; state->pm4[state->cpm4++] = 0x80000000; state->pm4[state->cpm4++] = PKT3(PKT3_EVENT_WRITE, 0); - state->pm4[state->cpm4++] = 0x00000016; + state->pm4[state->cpm4++] = EVENT_TYPE_CACHE_FLUSH_AND_INV_EVENT; state->pm4[state->cpm4++] = PKT3(PKT3_SET_CONFIG_REG, 1); state->pm4[state->cpm4++] = 0x00000010; state->pm4[state->cpm4++] = 0x00028000; return r600_state_pm4_generic(state); } +static int r600_state_pm4_query_begin(struct radeon_state *state) +{ + int r; + + state->cpm4 = 0; + state->pm4[state->cpm4++] = PKT3(PKT3_EVENT_WRITE, 2); + state->pm4[state->cpm4++] = EVENT_TYPE_ZPASS_DONE; + state->pm4[state->cpm4++] = state->states[0]; + state->pm4[state->cpm4++] = 0x0; + state->pm4[state->cpm4++] = PKT3(PKT3_NOP, 0); + r = radeon_state_reloc(state, state->cpm4, 0); + if (r) + return r; + state->pm4[state->cpm4++] = state->bo[0]->handle; + return 0; +} + +static int r600_state_pm4_query_end(struct radeon_state *state) +{ + int r; + + state->cpm4 = 0; + state->pm4[state->cpm4++] = PKT3(PKT3_EVENT_WRITE, 2); + state->pm4[state->cpm4++] = EVENT_TYPE_ZPASS_DONE; + state->pm4[state->cpm4++] = state->states[0]; + state->pm4[state->cpm4++] = 0x0; + state->pm4[state->cpm4++] = PKT3(PKT3_NOP, 0); + r = radeon_state_reloc(state, state->cpm4, 0); + if (r) + return r; + state->pm4[state->cpm4++] = state->bo[0]->handle; + return 0; +} + static int r700_state_pm4_config(struct radeon_state *state) { state->pm4[state->cpm4++] = PKT3(PKT3_CONTEXT_CONTROL, 1); state->pm4[state->cpm4++] = 0x80000000; state->pm4[state->cpm4++] = 0x80000000; state->pm4[state->cpm4++] = PKT3(PKT3_EVENT_WRITE, 0); - state->pm4[state->cpm4++] = 0x00000016; + state->pm4[state->cpm4++] = EVENT_TYPE_CACHE_FLUSH_AND_INV_EVENT; state->pm4[state->cpm4++] = PKT3(PKT3_SET_CONFIG_REG, 1); state->pm4[state->cpm4++] = 0x00000010; state->pm4[state->cpm4++] = 0x00028000; @@ -287,7 +367,6 @@ static int r600_state_pm4_vgt(struct radeon_state *state) static int r600_state_pm4_draw(struct radeon_state *state) { - unsigned i; int r; if (state->nbo) { @@ -301,20 +380,13 @@ static int r600_state_pm4_draw(struct radeon_state *state) if (r) return r; state->pm4[state->cpm4++] = state->bo[0]->handle; - } else if (state->nimmd) { - state->pm4[state->cpm4++] = PKT3(PKT3_DRAW_INDEX_IMMD, state->nimmd + 1); - state->pm4[state->cpm4++] = state->states[R600_DRAW__VGT_NUM_INDICES]; - state->pm4[state->cpm4++] = state->states[R600_DRAW__VGT_DRAW_INITIATOR]; - for (i = 0; i < state->nimmd; i++) { - state->pm4[state->cpm4++] = state->immd[i]; - } } else { state->pm4[state->cpm4++] = PKT3(PKT3_DRAW_INDEX_AUTO, 1); state->pm4[state->cpm4++] = state->states[R600_DRAW__VGT_NUM_INDICES]; state->pm4[state->cpm4++] = state->states[R600_DRAW__VGT_DRAW_INITIATOR]; } state->pm4[state->cpm4++] = PKT3(PKT3_EVENT_WRITE, 0); - state->pm4[state->cpm4++] = 0x00000016; + state->pm4[state->cpm4++] = EVENT_TYPE_CACHE_FLUSH_AND_INV_EVENT; return 0; } @@ -322,8 +394,9 @@ static int r600_state_pm4_resource(struct radeon_state *state) { u32 flags, type, nbo, offset, soffset; int r; + const struct radeon_register *regs = get_regs(state); - soffset = (state->id - state->radeon->type[state->type].id) * state->radeon->type[state->type].stride; + soffset = state->id * state->stype->stride; type = G_038018_TYPE(state->states[6]); switch (type) { case 2: @@ -342,7 +415,7 @@ static int r600_state_pm4_resource(struct radeon_state *state) return -EINVAL; } r600_state_pm4_with_flush(state, flags); - offset = state->radeon->type[state->type].regs[0].offset + soffset; + offset = regs[0].offset + soffset; state->pm4[state->cpm4++] = PKT3(PKT3_SET_RESOURCE, 7); state->pm4[state->cpm4++] = (offset - R_038000_SQ_TEX_RESOURCE_WORD0_0) >> 2; state->pm4[state->cpm4++] = state->states[0]; @@ -367,33 +440,62 @@ static int r600_state_pm4_resource(struct radeon_state *state) return 0; } -int r600_init(struct radeon *radeon) + +static void r600_modify_type_array(struct radeon *radeon) { + int i; switch (radeon->family) { - case CHIP_R600: - case CHIP_RV610: - case CHIP_RV630: - case CHIP_RV670: - case CHIP_RV620: - case CHIP_RV635: - case CHIP_RS780: - case CHIP_RS880: - radeon->ntype = R600_NTYPE; - radeon->nstate = R600_NSTATE; - radeon->type = R600_types; - break; case CHIP_RV770: case CHIP_RV730: case CHIP_RV710: case CHIP_RV740: - radeon->ntype = R600_NTYPE; - radeon->nstate = R600_NSTATE; - radeon->type = R700_types; break; default: - fprintf(stderr, "%s unknown or unsupported chipset 0x%04X\n", - __func__, radeon->device); - return -EINVAL; + return; + } + + /* r700 needs some mods */ + for (i = 0; i < radeon->nstype; i++) { + struct radeon_stype_info *info = &radeon->stype[i]; + + switch(info->stype) { + case R600_STATE_CONFIG: + info->pm4 = r700_state_pm4_config; + break; + case R600_STATE_CB0: + info->pm4 = r700_state_pm4_cb0; + break; + case R600_STATE_DB: + info->pm4 = r700_state_pm4_db; + }; } +} + +static void r600_build_types_array(struct radeon *radeon) +{ + int i, j; + int id = 0; + + for (i = 0; i < STYPES_SIZE; i++) { + r600_stypes[i].base_id = id; + r600_stypes[i].npm4 = 128; + if (r600_stypes[i].reginfo[0].shader_type == 0) { + id += r600_stypes[i].num; + } else { + for (j = 0; j < R600_SHADER_MAX; j++) { + if (r600_stypes[i].reginfo[j].shader_type) + id += r600_stypes[i].num; + } + } + } + radeon->stype = r600_stypes; + radeon->nstype = STYPES_SIZE; + + r600_modify_type_array(radeon); +} + +int r600_init(struct radeon *radeon) +{ + r600_build_types_array(radeon); return 0; } diff --git a/src/gallium/winsys/r600/drm/r600_states.h b/src/gallium/winsys/r600/drm/r600_states.h index e40c77d8f6..09d79d498d 100644 --- a/src/gallium/winsys/r600/drm/r600_states.h +++ b/src/gallium/winsys/r600/drm/r600_states.h @@ -17,7 +17,7 @@ #ifndef R600_STATES_H #define R600_STATES_H -static const struct radeon_register R600_CONFIG_names[] = { +static const struct radeon_register R600_names_CONFIG[] = { {0x00008C00, 0, 0, "SQ_CONFIG"}, {0x00008C04, 0, 0, "SQ_GPR_RESOURCE_MGMT_1"}, {0x00008C08, 0, 0, "SQ_GPR_RESOURCE_MGMT_2"}, @@ -61,7 +61,7 @@ static const struct radeon_register R600_CONFIG_names[] = { {0x00028B20, 0, 0, "VGT_STRMOUT_BUFFER_EN"}, }; -static const struct radeon_register R600_CB_CNTL_names[] = { +static const struct radeon_register R600_names_CB_CNTL[] = { {0x00028120, 0, 0, "CB_CLEAR_RED"}, {0x00028124, 0, 0, "CB_CLEAR_GREEN"}, {0x00028128, 0, 0, "CB_CLEAR_BLUE"}, @@ -82,7 +82,7 @@ static const struct radeon_register R600_CB_CNTL_names[] = { {0x00028C48, 0, 0, "PA_SC_AA_MASK"}, }; -static const struct radeon_register R600_RASTERIZER_names[] = { +static const struct radeon_register R600_names_RASTERIZER[] = { {0x000286D4, 0, 0, "SPI_INTERP_CONTROL_0"}, {0x00028810, 0, 0, "PA_CL_CLIP_CNTL"}, {0x00028814, 0, 0, "PA_SU_SC_MODE_CNTL"}, @@ -106,7 +106,7 @@ static const struct radeon_register R600_RASTERIZER_names[] = { {0x00028E0C, 0, 0, "PA_SU_POLY_OFFSET_BACK_OFFSET"}, }; -static const struct radeon_register R600_VIEWPORT_names[] = { +static const struct radeon_register R600_names_VIEWPORT[] = { {0x000282D0, 0, 0, "PA_SC_VPORT_ZMIN_0"}, {0x000282D4, 0, 0, "PA_SC_VPORT_ZMAX_0"}, {0x0002843C, 0, 0, "PA_CL_VPORT_XSCALE_0"}, @@ -118,7 +118,7 @@ static const struct radeon_register R600_VIEWPORT_names[] = { {0x00028818, 0, 0, "PA_CL_VTE_CNTL"}, }; -static const struct radeon_register R600_SCISSOR_names[] = { +static const struct radeon_register R600_names_SCISSOR[] = { {0x00028030, 0, 0, "PA_SC_SCREEN_SCISSOR_TL"}, {0x00028034, 0, 0, "PA_SC_SCREEN_SCISSOR_BR"}, {0x00028200, 0, 0, "PA_SC_WINDOW_OFFSET"}, @@ -140,7 +140,7 @@ static const struct radeon_register R600_SCISSOR_names[] = { {0x00028254, 0, 0, "PA_SC_VPORT_SCISSOR_0_BR"}, }; -static const struct radeon_register R600_BLEND_names[] = { +static const struct radeon_register R600_names_BLEND[] = { {0x00028414, 0, 0, "CB_BLEND_RED"}, {0x00028418, 0, 0, "CB_BLEND_GREEN"}, {0x0002841C, 0, 0, "CB_BLEND_BLUE"}, @@ -156,7 +156,7 @@ static const struct radeon_register R600_BLEND_names[] = { {0x00028804, 0, 0, "CB_BLEND_CONTROL"}, }; -static const struct radeon_register R600_DSA_names[] = { +static const struct radeon_register R600_names_DSA[] = { {0x00028028, 0, 0, "DB_STENCIL_CLEAR"}, {0x0002802C, 0, 0, "DB_DEPTH_CLEAR"}, {0x00028410, 0, 0, "SX_ALPHA_TEST_CONTROL"}, @@ -175,7 +175,7 @@ static const struct radeon_register R600_DSA_names[] = { {0x00028D44, 0, 0, "DB_ALPHA_TO_MASK"}, }; -static const struct radeon_register R600_VS_SHADER_names[] = { +static const struct radeon_register R600_names_VS_SHADER[] = { {0x00028380, 0, 0, "SQ_VTX_SEMANTIC_0"}, {0x00028384, 0, 0, "SQ_VTX_SEMANTIC_1"}, {0x00028388, 0, 0, "SQ_VTX_SEMANTIC_2"}, @@ -227,7 +227,7 @@ static const struct radeon_register R600_VS_SHADER_names[] = { {0x000288DC, 0, 0, "SQ_PGM_CF_OFFSET_FS"}, }; -static const struct radeon_register R600_PS_SHADER_names[] = { +static const struct radeon_register R600_names_PS_SHADER[] = { {0x00028644, 0, 0, "SPI_PS_INPUT_CNTL_0"}, {0x00028648, 0, 0, "SPI_PS_INPUT_CNTL_1"}, {0x0002864C, 0, 0, "SPI_PS_INPUT_CNTL_2"}, @@ -269,21 +269,48 @@ static const struct radeon_register R600_PS_SHADER_names[] = { {0x000288CC, 0, 0, "SQ_PGM_CF_OFFSET_PS"}, }; -static const struct radeon_register R600_PS_CONSTANT_names[] = { +static const struct radeon_register R600_names_PS_CONSTANT[] = { {0x00030000, 0, 0, "SQ_ALU_CONSTANT0_0"}, {0x00030004, 0, 0, "SQ_ALU_CONSTANT1_0"}, {0x00030008, 0, 0, "SQ_ALU_CONSTANT2_0"}, {0x0003000C, 0, 0, "SQ_ALU_CONSTANT3_0"}, }; -static const struct radeon_register R600_VS_CONSTANT_names[] = { +static const struct radeon_register R600_names_VS_CONSTANT[] = { {0x00031000, 0, 0, "SQ_ALU_CONSTANT0_256"}, {0x00031004, 0, 0, "SQ_ALU_CONSTANT1_256"}, {0x00031008, 0, 0, "SQ_ALU_CONSTANT2_256"}, {0x0003100C, 0, 0, "SQ_ALU_CONSTANT3_256"}, }; -static const struct radeon_register R600_PS_RESOURCE_names[] = { +static const struct radeon_register R600_names_UCP[] = { + {0x00028E20, 0, 0, "PA_CL_UCP0_X"}, + {0x00028E24, 0, 0, "PA_CL_UCP0_Y"}, + {0x00028E28, 0, 0, "PA_CL_UCP0_Z"}, + {0x00028E2C, 0, 0, "PA_CL_UCP0_W"}, + {0x00028E30, 0, 0, "PA_CL_UCP1_X"}, + {0x00028E34, 0, 0, "PA_CL_UCP1_Y"}, + {0x00028E38, 0, 0, "PA_CL_UCP1_Z"}, + {0x00028E3C, 0, 0, "PA_CL_UCP1_W"}, + {0x00028E40, 0, 0, "PA_CL_UCP2_X"}, + {0x00028E44, 0, 0, "PA_CL_UCP2_Y"}, + {0x00028E48, 0, 0, "PA_CL_UCP2_Z"}, + {0x00028E4C, 0, 0, "PA_CL_UCP2_W"}, + {0x00028E50, 0, 0, "PA_CL_UCP3_X"}, + {0x00028E54, 0, 0, "PA_CL_UCP3_Y"}, + {0x00028E58, 0, 0, "PA_CL_UCP3_Z"}, + {0x00028E5C, 0, 0, "PA_CL_UCP3_W"}, + {0x00028E60, 0, 0, "PA_CL_UCP4_X"}, + {0x00028E64, 0, 0, "PA_CL_UCP4_Y"}, + {0x00028E68, 0, 0, "PA_CL_UCP4_Z"}, + {0x00028E6C, 0, 0, "PA_CL_UCP4_W"}, + {0x00028E70, 0, 0, "PA_CL_UCP5_X"}, + {0x00028E74, 0, 0, "PA_CL_UCP5_Y"}, + {0x00028E78, 0, 0, "PA_CL_UCP5_Z"}, + {0x00028E7C, 0, 0, "PA_CL_UCP5_W"}, +}; + +static const struct radeon_register R600_names_PS_RESOURCE[] = { {0x00038000, 0, 0, "RESOURCE0_WORD0"}, {0x00038004, 0, 0, "RESOURCE0_WORD1"}, {0x00038008, 0, 0, "RESOURCE0_WORD2"}, @@ -293,7 +320,7 @@ static const struct radeon_register R600_PS_RESOURCE_names[] = { {0x00038018, 0, 0, "RESOURCE0_WORD6"}, }; -static const struct radeon_register R600_VS_RESOURCE_names[] = { +static const struct radeon_register R600_names_VS_RESOURCE[] = { {0x00039180, 0, 0, "RESOURCE160_WORD0"}, {0x00039184, 0, 0, "RESOURCE160_WORD1"}, {0x00039188, 0, 0, "RESOURCE160_WORD2"}, @@ -303,7 +330,7 @@ static const struct radeon_register R600_VS_RESOURCE_names[] = { {0x00039198, 0, 0, "RESOURCE160_WORD6"}, }; -static const struct radeon_register R600_FS_RESOURCE_names[] = { +static const struct radeon_register R600_names_FS_RESOURCE[] = { {0x0003A300, 0, 0, "RESOURCE320_WORD0"}, {0x0003A304, 0, 0, "RESOURCE320_WORD1"}, {0x0003A308, 0, 0, "RESOURCE320_WORD2"}, @@ -313,7 +340,7 @@ static const struct radeon_register R600_FS_RESOURCE_names[] = { {0x0003A318, 0, 0, "RESOURCE320_WORD6"}, }; -static const struct radeon_register R600_GS_RESOURCE_names[] = { +static const struct radeon_register R600_names_GS_RESOURCE[] = { {0x0003A4C0, 0, 0, "RESOURCE336_WORD0"}, {0x0003A4C4, 0, 0, "RESOURCE336_WORD1"}, {0x0003A4C8, 0, 0, "RESOURCE336_WORD2"}, @@ -323,46 +350,46 @@ static const struct radeon_register R600_GS_RESOURCE_names[] = { {0x0003A4D8, 0, 0, "RESOURCE336_WORD6"}, }; -static const struct radeon_register R600_PS_SAMPLER_names[] = { +static const struct radeon_register R600_names_PS_SAMPLER[] = { {0x0003C000, 0, 0, "SQ_TEX_SAMPLER_WORD0_0"}, {0x0003C004, 0, 0, "SQ_TEX_SAMPLER_WORD1_0"}, {0x0003C008, 0, 0, "SQ_TEX_SAMPLER_WORD2_0"}, }; -static const struct radeon_register R600_VS_SAMPLER_names[] = { +static const struct radeon_register R600_names_VS_SAMPLER[] = { {0x0003C0D8, 0, 0, "SQ_TEX_SAMPLER_WORD0_18"}, {0x0003C0DC, 0, 0, "SQ_TEX_SAMPLER_WORD1_18"}, {0x0003C0E0, 0, 0, "SQ_TEX_SAMPLER_WORD2_18"}, }; -static const struct radeon_register R600_GS_SAMPLER_names[] = { +static const struct radeon_register R600_names_GS_SAMPLER[] = { {0x0003C1B0, 0, 0, "SQ_TEX_SAMPLER_WORD0_36"}, {0x0003C1B4, 0, 0, "SQ_TEX_SAMPLER_WORD1_36"}, {0x0003C1B8, 0, 0, "SQ_TEX_SAMPLER_WORD2_36"}, }; -static const struct radeon_register R600_PS_SAMPLER_BORDER_names[] = { +static const struct radeon_register R600_names_PS_SAMPLER_BORDER[] = { {0x0000A400, 0, 0, "TD_PS_SAMPLER0_BORDER_RED"}, {0x0000A404, 0, 0, "TD_PS_SAMPLER0_BORDER_GREEN"}, {0x0000A408, 0, 0, "TD_PS_SAMPLER0_BORDER_BLUE"}, {0x0000A40C, 0, 0, "TD_PS_SAMPLER0_BORDER_ALPHA"}, }; -static const struct radeon_register R600_VS_SAMPLER_BORDER_names[] = { +static const struct radeon_register R600_names_VS_SAMPLER_BORDER[] = { {0x0000A600, 0, 0, "TD_VS_SAMPLER0_BORDER_RED"}, {0x0000A604, 0, 0, "TD_VS_SAMPLER0_BORDER_GREEN"}, {0x0000A608, 0, 0, "TD_VS_SAMPLER0_BORDER_BLUE"}, {0x0000A60C, 0, 0, "TD_VS_SAMPLER0_BORDER_ALPHA"}, }; -static const struct radeon_register R600_GS_SAMPLER_BORDER_names[] = { +static const struct radeon_register R600_names_GS_SAMPLER_BORDER[] = { {0x0000A800, 0, 0, "TD_GS_SAMPLER0_BORDER_RED"}, {0x0000A804, 0, 0, "TD_GS_SAMPLER0_BORDER_GREEN"}, {0x0000A808, 0, 0, "TD_GS_SAMPLER0_BORDER_BLUE"}, {0x0000A80C, 0, 0, "TD_GS_SAMPLER0_BORDER_ALPHA"}, }; -static const struct radeon_register R600_CB0_names[] = { +static const struct radeon_register R600_names_CB0[] = { {0x00028040, 1, 0, "CB_COLOR0_BASE"}, {0x000280A0, 0, 0, "CB_COLOR0_INFO"}, {0x00028060, 0, 0, "CB_COLOR0_SIZE"}, @@ -372,7 +399,7 @@ static const struct radeon_register R600_CB0_names[] = { {0x00028100, 0, 0, "CB_COLOR0_MASK"}, }; -static const struct radeon_register R600_CB1_names[] = { +static const struct radeon_register R600_names_CB1[] = { {0x00028044, 1, 0, "CB_COLOR1_BASE"}, {0x000280A4, 0, 0, "CB_COLOR1_INFO"}, {0x00028064, 0, 0, "CB_COLOR1_SIZE"}, @@ -382,7 +409,7 @@ static const struct radeon_register R600_CB1_names[] = { {0x00028104, 0, 0, "CB_COLOR1_MASK"}, }; -static const struct radeon_register R600_CB2_names[] = { +static const struct radeon_register R600_names_CB2[] = { {0x00028048, 1, 0, "CB_COLOR2_BASE"}, {0x000280A8, 0, 0, "CB_COLOR2_INFO"}, {0x00028068, 0, 0, "CB_COLOR2_SIZE"}, @@ -392,7 +419,7 @@ static const struct radeon_register R600_CB2_names[] = { {0x00028108, 0, 0, "CB_COLOR2_MASK"}, }; -static const struct radeon_register R600_CB3_names[] = { +static const struct radeon_register R600_names_CB3[] = { {0x0002804C, 1, 0, "CB_COLOR3_BASE"}, {0x000280AC, 0, 0, "CB_COLOR3_INFO"}, {0x0002806C, 0, 0, "CB_COLOR3_SIZE"}, @@ -402,7 +429,7 @@ static const struct radeon_register R600_CB3_names[] = { {0x0002810C, 0, 0, "CB_COLOR3_MASK"}, }; -static const struct radeon_register R600_CB4_names[] = { +static const struct radeon_register R600_names_CB4[] = { {0x00028050, 1, 0, "CB_COLOR4_BASE"}, {0x000280B0, 0, 0, "CB_COLOR4_INFO"}, {0x00028070, 0, 0, "CB_COLOR4_SIZE"}, @@ -412,7 +439,7 @@ static const struct radeon_register R600_CB4_names[] = { {0x00028110, 0, 0, "CB_COLOR4_MASK"}, }; -static const struct radeon_register R600_CB5_names[] = { +static const struct radeon_register R600_names_CB5[] = { {0x00028054, 1, 0, "CB_COLOR5_BASE"}, {0x000280B4, 0, 0, "CB_COLOR5_INFO"}, {0x00028074, 0, 0, "CB_COLOR5_SIZE"}, @@ -422,7 +449,7 @@ static const struct radeon_register R600_CB5_names[] = { {0x00028114, 0, 0, "CB_COLOR5_MASK"}, }; -static const struct radeon_register R600_CB6_names[] = { +static const struct radeon_register R600_names_CB6[] = { {0x00028058, 1, 0, "CB_COLOR6_BASE"}, {0x000280B8, 0, 0, "CB_COLOR6_INFO"}, {0x00028078, 0, 0, "CB_COLOR6_SIZE"}, @@ -432,7 +459,7 @@ static const struct radeon_register R600_CB6_names[] = { {0x00028118, 0, 0, "CB_COLOR6_MASK"}, }; -static const struct radeon_register R600_CB7_names[] = { +static const struct radeon_register R600_names_CB7[] = { {0x0002805C, 1, 0, "CB_COLOR7_BASE"}, {0x000280BC, 0, 0, "CB_COLOR7_INFO"}, {0x0002807C, 0, 0, "CB_COLOR7_SIZE"}, @@ -442,7 +469,7 @@ static const struct radeon_register R600_CB7_names[] = { {0x0002811C, 0, 0, "CB_COLOR7_MASK"}, }; -static const struct radeon_register R600_DB_names[] = { +static const struct radeon_register R600_names_DB[] = { {0x0002800C, 1, 0, "DB_DEPTH_BASE"}, {0x00028000, 0, 0, "DB_DEPTH_SIZE"}, {0x00028004, 0, 0, "DB_DEPTH_VIEW"}, @@ -451,7 +478,7 @@ static const struct radeon_register R600_DB_names[] = { {0x00028D34, 0, 0, "DB_PREFETCH_LIMIT"}, }; -static const struct radeon_register R600_VGT_names[] = { +static const struct radeon_register R600_names_VGT[] = { {0x00008958, 0, 0, "VGT_PRIMITIVE_TYPE"}, {0x00028400, 0, 0, "VGT_MAX_VTX_INDX"}, {0x00028404, 0, 0, "VGT_MIN_VTX_INDX"}, @@ -465,81 +492,15 @@ static const struct radeon_register R600_VGT_names[] = { {0x00028AA4, 0, 0, "VGT_INSTANCE_STEP_RATE_1"}, }; -static const struct radeon_register R600_DRAW_names[] = { +static const struct radeon_register R600_names_DRAW[] = { {0x00008970, 0, 0, "VGT_NUM_INDICES"}, {0x000287E4, 0, 0, "VGT_DMA_BASE_HI"}, {0x000287E8, 1, 0, "VGT_DMA_BASE"}, {0x000287F0, 0, 0, "VGT_DRAW_INITIATOR"}, }; -static struct radeon_type R600_types[] = { - { 128, 0, 0x00000000, 0x00000000, 0x0000, 0, "R600_CONFIG", 41, r600_state_pm4_config, R600_CONFIG_names}, - { 128, 1, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB_CNTL", 18, r600_state_pm4_generic, R600_CB_CNTL_names}, - { 128, 2, 0x00000000, 0x00000000, 0x0000, 0, "R600_RASTERIZER", 21, r600_state_pm4_generic, R600_RASTERIZER_names}, - { 128, 3, 0x00000000, 0x00000000, 0x0000, 0, "R600_VIEWPORT", 9, r600_state_pm4_generic, R600_VIEWPORT_names}, - { 128, 4, 0x00000000, 0x00000000, 0x0000, 0, "R600_SCISSOR", 19, r600_state_pm4_generic, R600_SCISSOR_names}, - { 128, 5, 0x00000000, 0x00000000, 0x0000, 0, "R600_BLEND", 13, r600_state_pm4_generic, R600_BLEND_names}, - { 128, 6, 0x00000000, 0x00000000, 0x0000, 0, "R600_DSA", 16, r600_state_pm4_generic, R600_DSA_names}, - { 128, 7, 0x00000000, 0x00000000, 0x0000, 0, "R600_VS_SHADER", 49, r600_state_pm4_shader, R600_VS_SHADER_names}, - { 128, 8, 0x00000000, 0x00000000, 0x0000, 0, "R600_PS_SHADER", 39, r600_state_pm4_shader, R600_PS_SHADER_names}, - { 128, 9, 0x00030000, 0x00031000, 0x0010, 0, "R600_PS_CONSTANT", 4, r600_state_pm4_generic, R600_PS_CONSTANT_names}, - { 128, 265, 0x00031000, 0x00032000, 0x0010, 0, "R600_VS_CONSTANT", 4, r600_state_pm4_generic, R600_VS_CONSTANT_names}, - { 128, 521, 0x00038000, 0x00039180, 0x001C, 0, "R600_PS_RESOURCE", 7, r600_state_pm4_resource, R600_PS_RESOURCE_names}, - { 128, 681, 0x00039180, 0x0003A300, 0x001C, 0, "R600_VS_RESOURCE", 7, r600_state_pm4_resource, R600_VS_RESOURCE_names}, - { 128, 841, 0x00039180, 0x0003A300, 0x001C, 0, "R600_FS_RESOURCE", 7, r600_state_pm4_resource, R600_FS_RESOURCE_names}, - { 128, 1001, 0x00039180, 0x0003A300, 0x001C, 0, "R600_GS_RESOURCE", 7, r600_state_pm4_resource, R600_GS_RESOURCE_names}, - { 128, 1161, 0x0003C000, 0x0003C0D8, 0x000C, 0, "R600_PS_SAMPLER", 3, r600_state_pm4_generic, R600_PS_SAMPLER_names}, - { 128, 1179, 0x0003C0D8, 0x0003C1B0, 0x000C, 0, "R600_VS_SAMPLER", 3, r600_state_pm4_generic, R600_VS_SAMPLER_names}, - { 128, 1197, 0x0003C1B0, 0x0003C288, 0x000C, 0, "R600_GS_SAMPLER", 3, r600_state_pm4_generic, R600_GS_SAMPLER_names}, - { 128, 1215, 0x0000A400, 0x0000A520, 0x0010, 0, "R600_PS_SAMPLER_BORDER", 4, r600_state_pm4_generic, R600_PS_SAMPLER_BORDER_names}, - { 128, 1233, 0x0000A600, 0x0000A720, 0x0010, 0, "R600_VS_SAMPLER_BORDER", 4, r600_state_pm4_generic, R600_VS_SAMPLER_BORDER_names}, - { 128, 1251, 0x0000A800, 0x0000A920, 0x0010, 0, "R600_GS_SAMPLER_BORDER", 4, r600_state_pm4_generic, R600_GS_SAMPLER_BORDER_names}, - { 128, 1269, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB0", 7, r600_state_pm4_cb0, R600_CB0_names}, - { 128, 1270, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB1", 7, r600_state_pm4_cb0, R600_CB1_names}, - { 128, 1271, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB2", 7, r600_state_pm4_cb0, R600_CB2_names}, - { 128, 1272, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB3", 7, r600_state_pm4_cb0, R600_CB3_names}, - { 128, 1273, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB4", 7, r600_state_pm4_cb0, R600_CB4_names}, - { 128, 1274, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB5", 7, r600_state_pm4_cb0, R600_CB5_names}, - { 128, 1275, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB6", 7, r600_state_pm4_cb0, R600_CB6_names}, - { 128, 1276, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB7", 7, r600_state_pm4_cb0, R600_CB7_names}, - { 128, 1277, 0x00000000, 0x00000000, 0x0000, 0, "R600_DB", 6, r600_state_pm4_db, R600_DB_names}, - { 128, 1278, 0x00000000, 0x00000000, 0x0000, 0, "R600_VGT", 11, r600_state_pm4_vgt, R600_VGT_names}, - { 128, 1279, 0x00000000, 0x00000000, 0x0000, 0, "R600_DRAW", 4, r600_state_pm4_draw, R600_DRAW_names}, -}; - -static struct radeon_type R700_types[] = { - { 128, 0, 0x00000000, 0x00000000, 0x0000, 0, "R600_CONFIG", 41, r700_state_pm4_config, R600_CONFIG_names}, - { 128, 1, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB_CNTL", 18, r600_state_pm4_generic, R600_CB_CNTL_names}, - { 128, 2, 0x00000000, 0x00000000, 0x0000, 0, "R600_RASTERIZER", 21, r600_state_pm4_generic, R600_RASTERIZER_names}, - { 128, 3, 0x00000000, 0x00000000, 0x0000, 0, "R600_VIEWPORT", 9, r600_state_pm4_generic, R600_VIEWPORT_names}, - { 128, 4, 0x00000000, 0x00000000, 0x0000, 0, "R600_SCISSOR", 19, r600_state_pm4_generic, R600_SCISSOR_names}, - { 128, 5, 0x00000000, 0x00000000, 0x0000, 0, "R600_BLEND", 13, r600_state_pm4_generic, R600_BLEND_names}, - { 128, 6, 0x00000000, 0x00000000, 0x0000, 0, "R600_DSA", 16, r600_state_pm4_generic, R600_DSA_names}, - { 128, 7, 0x00000000, 0x00000000, 0x0000, 0, "R600_VS_SHADER", 49, r600_state_pm4_shader, R600_VS_SHADER_names}, - { 128, 8, 0x00000000, 0x00000000, 0x0000, 0, "R600_PS_SHADER", 39, r600_state_pm4_shader, R600_PS_SHADER_names}, - { 128, 9, 0x00030000, 0x00031000, 0x0010, 0, "R600_PS_CONSTANT", 4, r600_state_pm4_generic, R600_PS_CONSTANT_names}, - { 128, 265, 0x00031000, 0x00032000, 0x0010, 0, "R600_VS_CONSTANT", 4, r600_state_pm4_generic, R600_VS_CONSTANT_names}, - { 128, 521, 0x00038000, 0x00039180, 0x001C, 0, "R600_PS_RESOURCE", 7, r600_state_pm4_resource, R600_PS_RESOURCE_names}, - { 128, 681, 0x00039180, 0x0003A300, 0x001C, 0, "R600_VS_RESOURCE", 7, r600_state_pm4_resource, R600_VS_RESOURCE_names}, - { 128, 841, 0x00039180, 0x0003A300, 0x001C, 0, "R600_FS_RESOURCE", 7, r600_state_pm4_resource, R600_FS_RESOURCE_names}, - { 128, 1001, 0x00039180, 0x0003A300, 0x001C, 0, "R600_GS_RESOURCE", 7, r600_state_pm4_resource, R600_GS_RESOURCE_names}, - { 128, 1161, 0x0003C000, 0x0003C0D8, 0x000C, 0, "R600_PS_SAMPLER", 3, r600_state_pm4_generic, R600_PS_SAMPLER_names}, - { 128, 1179, 0x0003C0D8, 0x0003C1B0, 0x000C, 0, "R600_VS_SAMPLER", 3, r600_state_pm4_generic, R600_VS_SAMPLER_names}, - { 128, 1197, 0x0003C1B0, 0x0003C288, 0x000C, 0, "R600_GS_SAMPLER", 3, r600_state_pm4_generic, R600_GS_SAMPLER_names}, - { 128, 1215, 0x0000A400, 0x0000A520, 0x0010, 0, "R600_PS_SAMPLER_BORDER", 4, r600_state_pm4_generic, R600_PS_SAMPLER_BORDER_names}, - { 128, 1233, 0x0000A600, 0x0000A720, 0x0010, 0, "R600_VS_SAMPLER_BORDER", 4, r600_state_pm4_generic, R600_VS_SAMPLER_BORDER_names}, - { 128, 1251, 0x0000A800, 0x0000A920, 0x0010, 0, "R600_GS_SAMPLER_BORDER", 4, r600_state_pm4_generic, R600_GS_SAMPLER_BORDER_names}, - { 128, 1269, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB0", 7, r700_state_pm4_cb0, R600_CB0_names}, - { 128, 1270, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB1", 7, r600_state_pm4_cb0, R600_CB1_names}, - { 128, 1271, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB2", 7, r600_state_pm4_cb0, R600_CB2_names}, - { 128, 1272, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB3", 7, r600_state_pm4_cb0, R600_CB3_names}, - { 128, 1273, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB4", 7, r600_state_pm4_cb0, R600_CB4_names}, - { 128, 1274, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB5", 7, r600_state_pm4_cb0, R600_CB5_names}, - { 128, 1275, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB6", 7, r600_state_pm4_cb0, R600_CB6_names}, - { 128, 1276, 0x00000000, 0x00000000, 0x0000, 0, "R600_CB7", 7, r600_state_pm4_cb0, R600_CB7_names}, - { 128, 1277, 0x00000000, 0x00000000, 0x0000, 0, "R600_DB", 6, r700_state_pm4_db, R600_DB_names}, - { 128, 1278, 0x00000000, 0x00000000, 0x0000, 0, "R600_VGT", 11, r600_state_pm4_vgt, R600_VGT_names}, - { 128, 1279, 0x00000000, 0x00000000, 0x0000, 0, "R600_DRAW", 4, r600_state_pm4_draw, R600_DRAW_names}, +static const struct radeon_register R600_names_VGT_EVENT[] = { + {0x00028A90, 1, 0, "VGT_EVENT_INITIATOR"}, }; #endif diff --git a/src/gallium/winsys/r600/drm/r600d.h b/src/gallium/winsys/r600/drm/r600d.h index 5d13378627..e8c2dc0651 100644 --- a/src/gallium/winsys/r600/drm/r600d.h +++ b/src/gallium/winsys/r600/drm/r600d.h @@ -82,6 +82,9 @@ #define PKT3_SET_CTL_CONST 0x6F #define PKT3_SURFACE_BASE_UPDATE 0x73 +#define EVENT_TYPE_ZPASS_DONE 0x15 +#define EVENT_TYPE_CACHE_FLUSH_AND_INV_EVENT 0x16 + #define PKT_TYPE_S(x) (((x) & 0x3) << 30) #define PKT_TYPE_G(x) (((x) >> 30) & 0x3) #define PKT_TYPE_C 0x3FFFFFFF diff --git a/src/gallium/winsys/r600/drm/radeon.c b/src/gallium/winsys/r600/drm/radeon.c index 80b0a1d397..e2d813ebac 100644 --- a/src/gallium/winsys/r600/drm/radeon.c +++ b/src/gallium/winsys/r600/drm/radeon.c @@ -42,24 +42,13 @@ static int radeon_get_device(struct radeon *radeon) return r; } -/* symbol missing drove me crazy hack to get symbol exported */ -static void fake(void) -{ - struct radeon_ctx *ctx; - struct radeon_draw *draw; - - ctx = radeon_ctx(NULL); - draw = radeon_draw(NULL); -} - struct radeon *radeon_new(int fd, unsigned device) { struct radeon *radeon; - int r; + int r, i, id; radeon = calloc(1, sizeof(*radeon)); if (radeon == NULL) { - fake(); return NULL; } radeon->fd = fd; @@ -131,6 +120,19 @@ struct radeon *radeon_new(int fd, unsigned device) __func__, radeon->device); break; } + radeon->state_type_id = calloc(radeon->nstype, sizeof(unsigned)); + if (radeon->state_type_id == NULL) { + return radeon_decref(radeon); + } + for (i = 0, id = 0; i < radeon->nstype; i++) { + radeon->state_type_id[i] = id; + for (int j = 0; j < radeon->nstype; j++) { + if (radeon->stype[j].stype != i) + continue; + id += radeon->stype[j].num; + } + } + radeon->nstate_per_shader = id; return radeon; } @@ -153,47 +155,3 @@ struct radeon *radeon_decref(struct radeon *radeon) free(radeon); return NULL; } - -int radeon_reg_id(struct radeon *radeon, unsigned offset, unsigned *typeid, unsigned *stateid, unsigned *id) -{ - unsigned i, j; - - for (i = 0; i < radeon->ntype; i++) { - if (radeon->type[i].range_start) { - if (offset >= radeon->type[i].range_start && offset < radeon->type[i].range_end) { - *typeid = i; - j = offset - radeon->type[i].range_start; - j /= radeon->type[i].stride; - *stateid = radeon->type[i].id + j; - *id = (offset - radeon->type[i].range_start - radeon->type[i].stride * j) / 4; - return 0; - } - } else { - for (j = 0; j < radeon->type[i].nstates; j++) { - if (radeon->type[i].regs[j].offset == offset) { - *typeid = i; - *stateid = radeon->type[i].id; - *id = j; - return 0; - } - } - } - } - fprintf(stderr, "%s unknown register 0x%08X\n", __func__, offset); - return -EINVAL; -} - -unsigned radeon_type_from_id(struct radeon *radeon, unsigned id) -{ - unsigned i; - - for (i = 0; i < radeon->ntype - 1; i++) { - if (radeon->type[i].id == id) - return i; - if (id > radeon->type[i].id && id < radeon->type[i + 1].id) - return i; - } - if (radeon->type[i].id == id) - return i; - return -1; -} diff --git a/src/gallium/winsys/r600/drm/radeon_bo.c b/src/gallium/winsys/r600/drm/radeon_bo.c index f259ae7fb5..a1306f6e9d 100644 --- a/src/gallium/winsys/r600/drm/radeon_bo.c +++ b/src/gallium/winsys/r600/drm/radeon_bo.c @@ -145,7 +145,9 @@ struct radeon_bo *radeon_bo_decref(struct radeon *radeon, struct radeon_bo *bo) return NULL; } - munmap(bo->data, bo->size); + if (bo->map_count) { + munmap(bo->data, bo->size); + } memset(&args, 0, sizeof(args)); args.handle = bo->handle; drmIoctl(radeon->fd, DRM_IOCTL_GEM_CLOSE, &args); diff --git a/src/gallium/winsys/r600/drm/radeon_ctx.c b/src/gallium/winsys/r600/drm/radeon_ctx.c index 45b706bb0f..47fca76136 100644 --- a/src/gallium/winsys/r600/drm/radeon_ctx.c +++ b/src/gallium/winsys/r600/drm/radeon_ctx.c @@ -30,21 +30,16 @@ #include "radeon_drm.h" #include "bof.h" -int radeon_ctx_set_bo_new(struct radeon_ctx *ctx, struct radeon_bo *bo) +static int radeon_ctx_set_bo_new(struct radeon_ctx *ctx, struct radeon_bo *bo) { - void *ptr; - - ptr = realloc(ctx->bo, sizeof(struct radeon_bo) * (ctx->nbo + 1)); - if (ptr == NULL) { - return -ENOMEM; - } - ctx->bo = ptr; + if (ctx->nbo >= RADEON_CTX_MAX_PM4) + return -EBUSY; ctx->bo[ctx->nbo] = bo; ctx->nbo++; return 0; } -struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc) +static struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc) { struct radeon_cs_reloc *greloc; unsigned i; @@ -59,7 +54,7 @@ struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc) return NULL; } -void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *placement) +static void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *placement) { struct radeon_cs_reloc *greloc; unsigned i; @@ -76,50 +71,57 @@ void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *place } } -struct radeon_ctx *radeon_ctx(struct radeon *radeon) +void radeon_ctx_clear(struct radeon_ctx *ctx) { - struct radeon_ctx *ctx; - - if (radeon == NULL) - return NULL; - ctx = calloc(1, sizeof(*ctx)); - if (ctx == NULL) - return NULL; - ctx->radeon = radeon_incref(radeon); - return ctx; + for (int i = 0; i < ctx->nbo; i++) { + ctx->bo[i] = radeon_bo_decref(ctx->radeon, ctx->bo[i]); + } + ctx->ndwords = RADEON_CTX_MAX_PM4; + ctx->cdwords = 0; + ctx->nreloc = 0; + ctx->nbo = 0; } -struct radeon_ctx *radeon_ctx_incref(struct radeon_ctx *ctx) +int radeon_ctx_init(struct radeon_ctx *ctx, struct radeon *radeon) { - ctx->refcount++; - return ctx; + if (radeon == NULL) + return -EINVAL; + memset(ctx, 0, sizeof(struct radeon_ctx)); + ctx->radeon = radeon_incref(radeon); + radeon_ctx_clear(ctx); + ctx->pm4 = malloc(RADEON_CTX_MAX_PM4 * 4); + if (ctx->pm4 == NULL) { + radeon_ctx_fini(ctx); + return -ENOMEM; + } + ctx->reloc = malloc(sizeof(struct radeon_cs_reloc) * RADEON_CTX_MAX_PM4); + if (ctx->reloc == NULL) { + radeon_ctx_fini(ctx); + return -ENOMEM; + } + ctx->bo = malloc(sizeof(void *) * RADEON_CTX_MAX_PM4); + if (ctx->bo == NULL) { + radeon_ctx_fini(ctx); + return -ENOMEM; + } + return 0; } -struct radeon_ctx *radeon_ctx_decref(struct radeon_ctx *ctx) +void radeon_ctx_fini(struct radeon_ctx *ctx) { unsigned i; if (ctx == NULL) - return NULL; - if (--ctx->refcount > 0) { - return NULL; - } + return; - for (i = 0; i < ctx->ndraw; i++) { - ctx->draw[i] = radeon_draw_decref(ctx->draw[i]); - } for (i = 0; i < ctx->nbo; i++) { ctx->bo[i] = radeon_bo_decref(ctx->radeon, ctx->bo[i]); } ctx->radeon = radeon_decref(ctx->radeon); - free(ctx->state); - free(ctx->draw); free(ctx->bo); free(ctx->pm4); free(ctx->reloc); - memset(ctx, 0, sizeof(*ctx)); - free(ctx); - return NULL; + memset(ctx, 0, sizeof(struct radeon_ctx)); } static int radeon_ctx_state_bo(struct radeon_ctx *ctx, struct radeon_state *state) @@ -152,17 +154,17 @@ int radeon_ctx_submit(struct radeon_ctx *ctx) uint64_t chunk_array[2]; int r = 0; - if (!ctx->cpm4) + if (!ctx->cdwords) return 0; #if 0 - for (r = 0; r < ctx->cpm4; r++) { + for (r = 0; r < ctx->cdwords; r++) { fprintf(stderr, "0x%08X\n", ctx->pm4[r]); } #endif drmib.num_chunks = 2; drmib.chunks = (uint64_t)(uintptr_t)chunk_array; chunks[0].chunk_id = RADEON_CHUNK_ID_IB; - chunks[0].length_dw = ctx->cpm4; + chunks[0].length_dw = ctx->cdwords; chunks[0].chunk_data = (uint64_t)(uintptr_t)ctx->pm4; chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS; chunks[1].length_dw = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4; @@ -180,7 +182,6 @@ static int radeon_ctx_reloc(struct radeon_ctx *ctx, struct radeon_bo *bo, unsigned id, unsigned *placement) { unsigned i; - struct radeon_cs_reloc *ptr; for (i = 0; i < ctx->nreloc; i++) { if (ctx->reloc[i].handle == bo->handle) { @@ -188,14 +189,13 @@ static int radeon_ctx_reloc(struct radeon_ctx *ctx, struct radeon_bo *bo, return 0; } } - ptr = realloc(ctx->reloc, sizeof(struct radeon_cs_reloc) * (ctx->nreloc + 1)); - if (ptr == NULL) - return -ENOMEM; - ctx->reloc = ptr; - ptr[ctx->nreloc].handle = bo->handle; - ptr[ctx->nreloc].read_domain = placement[0] | placement [1]; - ptr[ctx->nreloc].write_domain = placement[0] | placement [1]; - ptr[ctx->nreloc].flags = 0; + if (ctx->nreloc >= RADEON_CTX_MAX_PM4) { + return -EBUSY; + } + ctx->reloc[ctx->nreloc].handle = bo->handle; + ctx->reloc[ctx->nreloc].read_domain = placement[0] | placement [1]; + ctx->reloc[ctx->nreloc].write_domain = placement[0] | placement [1]; + ctx->reloc[ctx->nreloc].flags = 0; ctx->pm4[id] = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4; ctx->nreloc++; return 0; @@ -208,97 +208,80 @@ static int radeon_ctx_state_schedule(struct radeon_ctx *ctx, struct radeon_state if (state == NULL) return 0; - memcpy(&ctx->pm4[ctx->id], state->pm4, state->cpm4 * 4); + if (state->cpm4 > ctx->ndwords) { + return -EBUSY; + } + memcpy(&ctx->pm4[ctx->cdwords], state->pm4, state->cpm4 * 4); for (i = 0; i < state->nreloc; i++) { rid = state->reloc_pm4_id[i]; bid = state->reloc_bo_id[i]; - cid = ctx->id + rid; + cid = ctx->cdwords + rid; r = radeon_ctx_reloc(ctx, state->bo[bid], cid, &state->placement[bid * 2]); if (r) { - fprintf(stderr, "%s state %d failed to reloc\n", __func__, state->type); + fprintf(stderr, "%s state %d failed to reloc\n", __func__, state->stype->stype); return r; } } - ctx->id += state->cpm4; + ctx->cdwords += state->cpm4; + ctx->ndwords -= state->cpm4; return 0; } -int radeon_ctx_set_draw_new(struct radeon_ctx *ctx, struct radeon_draw *draw) +int radeon_ctx_set_query_state(struct radeon_ctx *ctx, struct radeon_state *state) { - struct radeon_draw *pdraw = NULL; - struct radeon_draw **ndraw; - struct radeon_state *nstate, *ostate; - unsigned cpm4, i, cstate; - void *tmp; int r = 0; - ndraw = realloc(ctx->draw, sizeof(void*) * (ctx->ndraw + 1)); - if (ndraw == NULL) - return -ENOMEM; - ctx->draw = ndraw; - for (i = 0; i < draw->nstate; i++) { - r = radeon_ctx_state_bo(ctx, draw->state[i]); - if (r) - return r; - } - r = radeon_draw_check(draw); + /* !!! ONLY ACCEPT QUERY STATE HERE !!! */ + r = radeon_state_pm4(state); if (r) return r; - if (draw->cpm4 >= RADEON_CTX_MAX_PM4) { - fprintf(stderr, "%s single draw too big %d, max %d\n", - __func__, draw->cpm4, RADEON_CTX_MAX_PM4); + /* BEGIN/END query are balanced in the same cs so account for END + * END query when scheduling BEGIN query + */ + switch (state->stype->stype) { + case R600_STATE_QUERY_BEGIN: + /* is there enough place for begin & end */ + if ((state->cpm4 * 2) > ctx->ndwords) + return -EBUSY; + ctx->ndwords -= state->cpm4; + break; + case R600_STATE_QUERY_END: + ctx->ndwords += state->cpm4; + break; + default: return -EINVAL; } - tmp = realloc(ctx->state, (ctx->nstate + draw->nstate) * sizeof(void*)); - if (tmp == NULL) - return -ENOMEM; - ctx->state = tmp; - pdraw = ctx->cdraw; - for (i = 0, cpm4 = 0, cstate = ctx->nstate; i < draw->nstate - 1; i++) { - nstate = draw->state[i]; - if (nstate) { - if (pdraw && pdraw->state[i]) { - ostate = pdraw->state[i]; - if (ostate->pm4_crc != nstate->pm4_crc) { - ctx->state[cstate++] = nstate; - cpm4 += nstate->cpm4; - } - } else { - ctx->state[cstate++] = nstate; - cpm4 += nstate->cpm4; - } - } - } - /* The last state is the draw state always add it */ - if (draw->state[i] == NULL) { - fprintf(stderr, "%s no draw command\n", __func__); - return -EINVAL; - } - ctx->state[cstate++] = draw->state[i]; - cpm4 += draw->state[i]->cpm4; - if ((ctx->draw_cpm4 + cpm4) > RADEON_CTX_MAX_PM4) { - /* need to flush */ - return -EBUSY; - } - ctx->draw_cpm4 += cpm4; - ctx->nstate = cstate; - ctx->draw[ctx->ndraw++] = draw; - ctx->cdraw = draw; - return 0; + return radeon_ctx_state_schedule(ctx, state); } int radeon_ctx_set_draw(struct radeon_ctx *ctx, struct radeon_draw *draw) { - int r; + unsigned previous_cdwords; + int r = 0; - radeon_draw_incref(draw); - r = radeon_ctx_set_draw_new(ctx, draw); - if (r) - radeon_draw_decref(draw); - return r; + for (int i = 0; i < (ctx->radeon->nstate_per_shader * R600_SHADER_MAX); i++) { + r = radeon_ctx_state_bo(ctx, draw->state[i]); + if (r) + return r; + } + previous_cdwords = ctx->cdwords; + for (int i = 0, id = 0; i < ctx->radeon->nstate_per_shader; i++) { + for (int j = 0; j < R600_SHADER_MAX; j++) { + id = j * ctx->radeon->nstate_per_shader + i; + if (draw->state[id]) { + r = radeon_ctx_state_schedule(ctx, draw->state[id]); + if (r) { + ctx->cdwords = previous_cdwords; + return r; + } + } + } + } + return 0; } +#if 0 int radeon_ctx_pm4(struct radeon_ctx *ctx) { unsigned i; @@ -310,9 +293,6 @@ int radeon_ctx_pm4(struct radeon_ctx *ctx) if (ctx->pm4 == NULL) return -EINVAL; for (i = 0, ctx->id = 0; i < ctx->nstate; i++) { - r = radeon_ctx_state_schedule(ctx, ctx->state[i]); - if (r) - return r; } if (ctx->id != ctx->draw_cpm4) { fprintf(stderr, "%s miss predicted pm4 size %d for %d\n", @@ -322,6 +302,7 @@ int radeon_ctx_pm4(struct radeon_ctx *ctx) ctx->cpm4 = ctx->draw_cpm4; return 0; } +#endif void radeon_ctx_dump_bof(struct radeon_ctx *ctx, const char *file) { @@ -349,8 +330,8 @@ printf("%d relocs\n", ctx->nreloc); bof_decref(blob); blob = NULL; /* dump cs */ -printf("%d pm4\n", ctx->cpm4); - blob = bof_blob(ctx->cpm4 * 4, ctx->pm4); +printf("%d pm4\n", ctx->cdwords); + blob = bof_blob(ctx->cdwords * 4, ctx->pm4); if (blob == NULL) goto out_err; if (bof_object_set(root, "pm4", blob)) @@ -366,7 +347,6 @@ printf("%d pm4\n", ctx->cpm4); if (bo == NULL) goto out_err; size = bof_int32(ctx->bo[i]->size); -printf("[%d] %d bo\n", i, size); if (size == NULL) goto out_err; if (bof_object_set(bo, "size", size)) diff --git a/src/gallium/winsys/r600/drm/radeon_draw.c b/src/gallium/winsys/r600/drm/radeon_draw.c index 4413ed79fb..b992c4a55d 100644 --- a/src/gallium/winsys/r600/drm/radeon_draw.c +++ b/src/gallium/winsys/r600/drm/radeon_draw.c @@ -31,111 +31,27 @@ /* * draw functions */ -struct radeon_draw *radeon_draw(struct radeon *radeon) +int radeon_draw_init(struct radeon_draw *draw, struct radeon *radeon) { - struct radeon_draw *draw; - - draw = calloc(1, sizeof(*draw)); - if (draw == NULL) - return NULL; - draw->nstate = radeon->nstate; draw->radeon = radeon; - draw->refcount = 1; - draw->state = calloc(1, sizeof(void*) * draw->nstate); - if (draw->state == NULL) { - free(draw); - return NULL; - } - return draw; -} - -struct radeon_draw *radeon_draw_incref(struct radeon_draw *draw) -{ - draw->refcount++; - return draw; -} - -struct radeon_draw *radeon_draw_decref(struct radeon_draw *draw) -{ - unsigned i; - - if (draw == NULL) - return NULL; - if (--draw->refcount > 0) - return NULL; - for (i = 0; i < draw->nstate; i++) { - draw->state[i] = radeon_state_decref(draw->state[i]); - } - free(draw->state); - memset(draw, 0, sizeof(*draw)); - free(draw); - return NULL; -} - -int radeon_draw_set_new(struct radeon_draw *draw, struct radeon_state *state) -{ - if (state == NULL) - return 0; - if (state->type >= draw->radeon->ntype) - return -EINVAL; - draw->state[state->id] = radeon_state_decref(draw->state[state->id]); - draw->state[state->id] = state; + draw->state = calloc(radeon->nstate_per_shader * R600_SHADER_MAX, sizeof(void*)); + if (draw->state == NULL) + return -ENOMEM; return 0; } -int radeon_draw_set(struct radeon_draw *draw, struct radeon_state *state) +void radeon_draw_bind(struct radeon_draw *draw, struct radeon_state *state) { if (state == NULL) - return 0; - radeon_state_incref(state); - return radeon_draw_set_new(draw, state); + return; + draw->state[state->state_id] = state; } -int radeon_draw_check(struct radeon_draw *draw) +void radeon_draw_unbind(struct radeon_draw *draw, struct radeon_state *state) { - unsigned i; - int r; - - r = radeon_draw_pm4(draw); - if (r) - return r; - for (i = 0, draw->cpm4 = 0; i < draw->nstate; i++) { - if (draw->state[i]) { - draw->cpm4 += draw->state[i]->cpm4; - } - } - return 0; -} - -struct radeon_draw *radeon_draw_duplicate(struct radeon_draw *draw) -{ - struct radeon_draw *ndraw; - unsigned i; - - if (draw == NULL) - return NULL; - ndraw = radeon_draw(draw->radeon); - if (ndraw == NULL) { - return NULL; - } - for (i = 0; i < draw->nstate; i++) { - if (radeon_draw_set(ndraw, draw->state[i])) { - radeon_draw_decref(ndraw); - return NULL; - } - } - return ndraw; -} - -int radeon_draw_pm4(struct radeon_draw *draw) -{ - unsigned i; - int r; - - for (i = 0; i < draw->nstate; i++) { - r = radeon_state_pm4(draw->state[i]); - if (r) - return r; + if (state == NULL) + return; + if (draw->state[state->state_id] == state) { + draw->state[state->state_id] = NULL; } - return 0; } diff --git a/src/gallium/winsys/r600/drm/radeon_priv.h b/src/gallium/winsys/r600/drm/radeon_priv.h index 96c0d060f7..84e552ba4d 100644 --- a/src/gallium/winsys/r600/drm/radeon_priv.h +++ b/src/gallium/winsys/r600/drm/radeon_priv.h @@ -37,17 +37,20 @@ struct radeon_register { char name[64]; }; -struct radeon_type { - unsigned npm4; - unsigned id; - unsigned range_start; - unsigned range_end; - unsigned stride; - unsigned immediate; - char name[64]; +struct radeon_sub_type { + int shader_type; + const struct radeon_register *regs; unsigned nstates; +}; + +struct radeon_stype_info { + unsigned stype; + unsigned num; + unsigned stride; radeon_state_pm4_t pm4; - const struct radeon_register *regs; + struct radeon_sub_type reginfo[R600_SHADER_MAX]; + unsigned base_id; + unsigned npm4; }; struct radeon { @@ -55,9 +58,10 @@ struct radeon { int refcount; unsigned device; unsigned family; - unsigned nstate; - unsigned ntype; - const struct radeon_type *type; + unsigned nstype; + unsigned nstate_per_shader; + unsigned *state_type_id; + struct radeon_stype_info *stype; }; extern struct radeon *radeon_new(int fd, unsigned device); @@ -65,15 +69,6 @@ extern struct radeon *radeon_incref(struct radeon *radeon); extern struct radeon *radeon_decref(struct radeon *radeon); extern unsigned radeon_family_from_device(unsigned device); extern int radeon_is_family_compatible(unsigned family1, unsigned family2); -extern int radeon_reg_id(struct radeon *radeon, unsigned offset, unsigned *typeid, unsigned *stateid, unsigned *id); -extern unsigned radeon_type_from_id(struct radeon *radeon, unsigned id); - - -int radeon_ctx_set_bo_new(struct radeon_ctx *ctx, struct radeon_bo *bo); -struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc); -void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *placement); -int radeon_ctx_set_draw_new(struct radeon_ctx *ctx, struct radeon_draw *draw); -int radeon_ctx_draw(struct radeon_ctx *ctx); /* * r600/r700 context functions diff --git a/src/gallium/winsys/r600/drm/radeon_state.c b/src/gallium/winsys/r600/drm/radeon_state.c index 308288557a..ac60485b28 100644 --- a/src/gallium/winsys/r600/drm/radeon_state.c +++ b/src/gallium/winsys/r600/drm/radeon_state.c @@ -32,82 +32,116 @@ /* * state core functions */ -struct radeon_state *radeon_state(struct radeon *radeon, u32 type, u32 id) +int radeon_state_init(struct radeon_state *state, struct radeon *radeon, u32 stype, u32 id, u32 shader_type) { - struct radeon_state *state; + struct radeon_stype_info *found = NULL; + int i, j, shader_index = -1; - if (type > radeon->ntype) { - fprintf(stderr, "%s invalid type %d\n", __func__, type); - return NULL; + /* traverse the stype array */ + for (i = 0; i < radeon->nstype; i++) { + /* if the type doesn't match, if the shader doesn't match */ + if (stype != radeon->stype[i].stype) + continue; + if (shader_type) { + for (j = 0; j < 4; j++) { + if (radeon->stype[i].reginfo[j].shader_type == shader_type) { + shader_index = j; + break; + } + } + if (shader_index == -1) + continue; + } else { + if (radeon->stype[i].reginfo[0].shader_type) + continue; + else + shader_index = 0; + } + if (id > radeon->stype[i].num) + continue; + + found = &radeon->stype[i]; + break; } - if (id > radeon->nstate) { - fprintf(stderr, "%s invalid state id %d\n", __func__, id); - return NULL; + + if (!found) { + fprintf(stderr, "%s invalid type %d/id %d/shader class %d\n", __func__, stype, id, shader_type); + return -EINVAL; } - state = calloc(1, sizeof(*state)); - if (state == NULL) - return NULL; + + memset(state, 0, sizeof(struct radeon_state)); + state->state_id = radeon->nstate_per_shader * shader_index + radeon->state_type_id[stype] + id; + state->stype = found; state->radeon = radeon; - state->type = type; state->id = id; + state->shader_index = shader_index; state->refcount = 1; - state->npm4 = radeon->type[type].npm4; - state->nstates = radeon->type[type].nstates; - state->states = calloc(1, state->nstates * 4); - state->pm4 = calloc(1, radeon->type[type].npm4 * 4); - if (state->states == NULL || state->pm4 == NULL) { - radeon_state_decref(state); - return NULL; - } - return state; + state->npm4 = found->npm4; + state->nstates = found->reginfo[shader_index].nstates; + return 0; } -struct radeon_state *radeon_state_duplicate(struct radeon_state *state) +int radeon_state_convert(struct radeon_state *state, u32 stype, u32 id, u32 shader_type) { - struct radeon_state *nstate = radeon_state(state->radeon, state->type, state->id); - unsigned i; + struct radeon_stype_info *found = NULL; + int i, j, shader_index = -1; if (state == NULL) - return NULL; - nstate->cpm4 = state->cpm4; - nstate->nbo = state->nbo; - nstate->nreloc = state->nreloc; - memcpy(nstate->states, state->states, state->nstates * 4); - memcpy(nstate->pm4, state->pm4, state->npm4 * 4); - memcpy(nstate->placement, state->placement, 8 * 4); - memcpy(nstate->reloc_pm4_id, state->reloc_pm4_id, 8 * 4); - memcpy(nstate->reloc_bo_id, state->reloc_bo_id, 8 * 4); - memcpy(nstate->bo_dirty, state->bo_dirty, 4 * 4); - for (i = 0; i < state->nbo; i++) { - nstate->bo[i] = radeon_bo_incref(state->radeon, state->bo[i]); + return 0; + /* traverse the stype array */ + for (i = 0; i < state->radeon->nstype; i++) { + /* if the type doesn't match, if the shader doesn't match */ + if (stype != state->radeon->stype[i].stype) + continue; + if (shader_type) { + for (j = 0; j < 4; j++) { + if (state->radeon->stype[i].reginfo[j].shader_type == shader_type) { + shader_index = j; + break; + } + } + if (shader_index == -1) + continue; + } else { + if (state->radeon->stype[i].reginfo[0].shader_type) + continue; + else + shader_index = 0; + } + if (id > state->radeon->stype[i].num) + continue; + + found = &state->radeon->stype[i]; + break; } - return nstate; -} -struct radeon_state *radeon_state_incref(struct radeon_state *state) -{ - state->refcount++; - return state; + if (!found) { + fprintf(stderr, "%s invalid type %d/id %d/shader class %d\n", __func__, stype, id, shader_type); + return -EINVAL; + } + + if (found->reginfo[shader_index].nstates != state->nstates) { + fprintf(stderr, "invalid type change from (%d %d %d) to (%d %d %d)\n", + state->stype->stype, state->id, state->shader_index, stype, id, shader_index); + } + + state->stype = found; + state->id = id; + state->shader_index = shader_index; + state->state_id = state->radeon->nstate_per_shader * shader_index + state->radeon->state_type_id[stype] + id; + return radeon_state_pm4(state); } -struct radeon_state *radeon_state_decref(struct radeon_state *state) +void radeon_state_fini(struct radeon_state *state) { unsigned i; if (state == NULL) return NULL; - if (--state->refcount > 0) { - return NULL; - } for (i = 0; i < state->nbo; i++) { state->bo[i] = radeon_bo_decref(state->radeon, state->bo[i]); } - free(state->immd); - free(state->states); - free(state->pm4); - memset(state, 0, sizeof(*state)); - free(state); - return NULL; + memset(state, 0, sizeof(struct radeon_state)); } int radeon_state_replace_always(struct radeon_state *ostate, @@ -147,12 +181,13 @@ int radeon_state_pm4(struct radeon_state *state) { int r; - if (state == NULL || state->cpm4) + if (state == NULL) return 0; - r = state->radeon->type[state->type].pm4(state); + state->cpm4 = 0; + r = state->stype->pm4(state); if (r) { fprintf(stderr, "%s failed to build PM4 for state(%d %d)\n", - __func__, state->type, state->id); + __func__, state->stype->stype, state->id); return r; } state->pm4_crc = crc32(state->pm4, state->cpm4 * 4); diff --git a/src/gallium/winsys/sw/wrapper/wrapper_sw_winsys.c b/src/gallium/winsys/sw/wrapper/wrapper_sw_winsys.c index b997abda9b..3a76098b65 100644 --- a/src/gallium/winsys/sw/wrapper/wrapper_sw_winsys.c +++ b/src/gallium/winsys/sw/wrapper/wrapper_sw_winsys.c @@ -52,6 +52,7 @@ struct wrapper_sw_winsys struct sw_winsys base; struct pipe_screen *screen; struct pipe_context *pipe; + enum pipe_texture_target target; }; struct wrapper_sw_displaytarget @@ -145,7 +146,7 @@ wsw_dt_create(struct sw_winsys *ws, * XXX Why don't we just get the template. */ memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; + templ.target = wsw->target; templ.width0 = width; templ.height0 = height; templ.format = format; @@ -291,6 +292,11 @@ wrapper_sw_winsys_warp_pipe_screen(struct pipe_screen *screen) if (!wsw->pipe) goto err_free; + if(screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) + wsw->target = PIPE_TEXTURE_2D; + else + wsw->target = PIPE_TEXTURE_RECT; + return &wsw->base; err_free: diff --git a/src/glsl/.dir-locals.el b/src/glsl/.dir-locals.el new file mode 100644 index 0000000000..be19e29a5a --- /dev/null +++ b/src/glsl/.dir-locals.el @@ -0,0 +1,3 @@ +((c-mode . ((c-basic-offset . 3))) + (c++-mode . ((c-basic-offset . 3))) +) diff --git a/src/glsl/.gitignore b/src/glsl/.gitignore new file mode 100644 index 0000000000..4c212313e4 --- /dev/null +++ b/src/glsl/.gitignore @@ -0,0 +1,2 @@ +glsl_compiler +glsl_parser.output diff --git a/src/glsl/Makefile b/src/glsl/Makefile index ca7f2d2ac7..aedca0f0d1 100644 --- a/src/glsl/Makefile +++ b/src/glsl/Makefile @@ -1,15 +1,178 @@ -# src/glsl/Makefile +#src/glsl/pp/Makefile TOP = ../.. include $(TOP)/configs/current -SUBDIRS = pp cl apps +LIBNAME = glsl -default install clean: - @for dir in $(SUBDIRS) ; do \ - if [ -d $$dir ] ; then \ - (cd $$dir && $(MAKE) $@) || exit 1; \ - fi \ - done +LIBGLCPP_SOURCES = \ + glcpp/glcpp-lex.c \ + glcpp/glcpp-parse.c \ + glcpp/pp.c +GLCPP_SOURCES = \ + $(LIBGLCPP_SOURCES) \ + glcpp/glcpp.c + +C_SOURCES = \ + $(LIBGLCPP_SOURCES) + +CXX_SOURCES = \ + ast_expr.cpp \ + ast_function.cpp \ + ast_to_hir.cpp \ + ast_type.cpp \ + builtin_function.cpp \ + glsl_lexer.cpp \ + glsl_parser.cpp \ + glsl_parser_extras.cpp \ + glsl_types.cpp \ + glsl_symbol_table.cpp \ + hir_field_selection.cpp \ + ir_algebraic.cpp \ + ir_basic_block.cpp \ + ir_clone.cpp \ + ir_constant_expression.cpp \ + ir_constant_folding.cpp \ + ir_constant_propagation.cpp \ + ir_constant_variable.cpp \ + ir_copy_propagation.cpp \ + ir.cpp \ + ir_dead_code.cpp \ + ir_dead_code_local.cpp \ + ir_dead_functions.cpp \ + ir_div_to_mul_rcp.cpp \ + ir_explog_to_explog2.cpp \ + ir_expression_flattening.cpp \ + ir_function_can_inline.cpp \ + ir_function.cpp \ + ir_function_inlining.cpp \ + ir_hierarchical_visitor.cpp \ + ir_hv_accept.cpp \ + ir_if_return.cpp \ + ir_if_simplification.cpp \ + ir_if_to_cond_assign.cpp \ + ir_import_prototypes.cpp \ + ir_mat_op_to_vec.cpp \ + ir_mod_to_fract.cpp \ + ir_noop_swizzle.cpp \ + ir_print_visitor.cpp \ + ir_reader.cpp \ + ir_rvalue_visitor.cpp \ + ir_set_program_inouts.cpp \ + ir_structure_splitting.cpp \ + ir_sub_to_add_neg.cpp \ + ir_swizzle_swizzle.cpp \ + ir_tree_grafting.cpp \ + ir_validate.cpp \ + ir_variable.cpp \ + ir_variable_refcount.cpp \ + ir_vec_index_to_cond_assign.cpp \ + ir_vec_index_to_swizzle.cpp \ + linker.cpp \ + link_functions.cpp \ + s_expression.cpp + +LIBS = \ + $(TOP)/src/glsl/libglsl.a \ + $(TALLOC_LIBS) + +APPS = glsl_compiler glcpp/glcpp + +GLSL2_C_SOURCES = \ + ../mesa/program/hash_table.c \ + ../mesa/program/symbol_table.c +GLSL2_CXX_SOURCES = \ + main.cpp + +GLSL2_OBJECTS = \ + $(GLSL2_C_SOURCES:.c=.o) \ + $(GLSL2_CXX_SOURCES:.cpp=.o) + +### Basic defines ### + +DEFINES += \ + $(LIBRARY_DEFINES) \ + $(API_DEFINES) + +GLCPP_OBJECTS = \ + $(GLCPP_SOURCES:.c=.o) \ + ../mesa/program/hash_table.o + +OBJECTS = \ + $(C_SOURCES:.c=.o) \ + $(CXX_SOURCES:.cpp=.o) + +INCLUDES = \ + $(TALLOC_CFLAGS) \ + -I. \ + -I../mesa \ + -I../mapi \ + -I../../include \ + $(LIBRARY_INCLUDES) + +ALL_SOURCES = \ + $(C_SOURCES) \ + $(CXX_SOURCES) \ + $(GLSL2_CXX_SOURCES) \ + $(GLSL2_C_SOURCES) + +##### TARGETS ##### + +default: depend lib$(LIBNAME).a $(APPS) + +lib$(LIBNAME).a: $(OBJECTS) Makefile $(TOP)/src/glsl/Makefile.template + $(MKLIB) -cplusplus -o $(LIBNAME) -static $(OBJECTS) + +depend: $(ALL_SOURCES) Makefile + rm -f depend + touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(INCLUDES) $(ALL_SOURCES) 2> /dev/null + +# Remove .o and backup files +clean: + rm -f $(GLCPP_OBJECTS) $(GLSL2_OBJECTS) $(OBJECTS) lib$(LIBNAME).a depend depend.bak + -rm -f $(APPS) + +# Dummy target +install: + @echo -n "" + + +##### RULES ##### + +glsl_compiler: $(GLSL2_OBJECTS) libglsl.a + $(APP_CXX) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(GLSL2_OBJECTS) $(LIBS) -o $@ + +glcpp/glcpp: $(GLCPP_OBJECTS) libglsl.a + $(APP_CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(GLCPP_OBJECTS) $(LIBS) -o $@ + +.cpp.o: + $(CXX) -c $(INCLUDES) $(CXXFLAGS) $(DEFINES) $< -o $@ + +.c.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + +glsl_lexer.cpp: glsl_lexer.lpp + flex --nounistd -o$@ $< + +glsl_parser.cpp: glsl_parser.ypp + bison -v -o "$@" -p "_mesa_glsl_" --defines=glsl_parser.h $< + +glcpp/glcpp-lex.c: glcpp/glcpp-lex.l + flex --nounistd -o$@ $< + +glcpp/glcpp-parse.c: glcpp/glcpp-parse.y + bison -v -o "$@" --defines=glcpp/glcpp-parse.h $< + +builtins: builtin_function.cpp builtins/profiles/* builtins/ir/* builtins/tools/generate_builtins.py builtins/tools/texture_builtins.py + @echo Bootstrapping the compiler... + cp builtins/tools/builtin_function.cpp . + make glsl_compiler + @echo Regenerating builtin_function.cpp... + ./builtins/tools/generate_builtins.py > builtin_function.cpp + @echo Rebuilding the real compiler... + make glsl_compiler + +-include depend diff --git a/src/glsl/Makefile.am b/src/glsl/Makefile.am new file mode 100644 index 0000000000..5728a8b63d --- /dev/null +++ b/src/glsl/Makefile.am @@ -0,0 +1,75 @@ +# Copyright © 2010 Intel Corporation +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, and/or sell copies of the Software, and to permit persons to whom +# the Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +# AUTHORS, COPYRIGHT HOLDERS, AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +# USE OR OTHER DEALINGS IN THE SOFTWARE. + +AUTOMAKE_OPTIONS = foreign +AM_CPPFLAGS = -I mesa + +SUBDIRS = glcpp + +bin_PROGRAMS = glsl + +glsl_LDADD = ./glcpp/libglcpp.la +glsl_LDFLAGS = @LDFLAGS@ $(talloc_LIBS) +glsl_SOURCES = \ + main.cpp \ + builtin_types.h \ + glsl_types.cpp \ + glsl_parser.ypp glsl_lexer.lpp glsl_parser_extras.cpp \ + ast_expr.cpp ast_to_hir.cpp ast_function.cpp ast_type.cpp \ + ir.cpp hir_field_selection.cpp builtin_function.cpp \ + ir_print_visitor.cpp ir_variable.cpp ir_function.cpp \ + ir_basic_block.cpp \ + ir_basic_block.h \ + ir_clone.cpp \ + ir_constant_expression.cpp \ + ir_constant_folding.cpp \ + ir_constant_variable.cpp \ + ir_copy_propagation.cpp \ + ir_copy_propagation.h \ + ir_dead_code.cpp \ + ir_dead_code.h \ + ir_dead_code_local.cpp \ + ir_expression_flattening.cpp \ + ir_function_can_inline.cpp \ + ir_function_inlining.cpp \ + ir_if_simplification.cpp \ + ir_optimization.h \ + ir_reader.cpp s_expression.cpp \ + ir_hv_accept.cpp \ + ir_hierarchical_visitor.h \ + ir_hierarchical_visitor.cpp \ + ir_swizzle_swizzle.cpp \ + ir_to_mesa.cpp \ + ir_to_mesa.h \ + ir_validate.cpp \ + ir_vec_index_to_swizzle.cpp \ + linker.cpp + +BUILT_SOURCES = glsl_parser.h glsl_parser.cpp glsl_lexer.cpp +CLEANFILES = $(BUILT_SOURCES) + +builtin_function.cpp: builtins/*/* + ./builtins/tools/generate_builtins.pl > builtin_function.cpp +glsl_parser.h: glsl_parser.cpp + +.lpp.cpp: + $(LEXCOMPILE) --outfile="$@" $< diff --git a/src/glsl/README b/src/glsl/README new file mode 100644 index 0000000000..2e501d6206 --- /dev/null +++ b/src/glsl/README @@ -0,0 +1,191 @@ +Welcome to Mesa's GLSL compiler. A brief overview of how things flow: + +1) lex and yacc-based preprocessor takes the incoming shader string +and produces a new string containing the preprocessed shader. This +takes care of things like #if, #ifdef, #define, and preprocessor macro +invocations. Note that #version, #extension, and some others are +passed straight through. See glcpp/* + +2) lex and yacc-based parser takes the preprocessed string and +generates the AST (abstract syntax tree). Almost no checking is +performed in this stage. See glsl_lexer.lpp and glsl_parser.ypp. + +3) The AST is converted to "HIR". This is the intermediate +representation of the compiler. Constructors are generated, function +calls are resolved to particular function signatures, and all the +semantic checking is performed. See ast_*.cpp for the conversion, and +ir.h for the IR structures. + +4) The driver (Mesa, or main.cpp for the standalone binary) performs +optimizations. These include copy propagation, dead code elimination, +constant folding, and others. Generally the driver will call +optimizations in a loop, as each may open up opportunities for other +optimizations to do additional work. See most files called ir_*.cpp + +5) linking is performed. This does checking to ensure that the +outputs of the vertex shader match the inputs of the fragment shader, +and assigns locations to uniforms, attributes, and varyings. See +linker.cpp. + +6) The driver may perform additional optimization at this point, as +for example dead code elimination previously couldn't remove functions +or global variable usage when we didn't know what other code would be +linked in. + +7) The driver performs code generation out of the IR, taking a linked +shader program and producing a compiled program for each stage. See +ir_to_mesa.cpp for Mesa IR code generation. + +FAQ: + +Q: What is HIR versus IR versus LIR? + +A: The idea behind the naming was that ast_to_hir would produce a +high-level IR ("HIR"), with things like matrix operations, structure +assignments, etc., present. A series of lowering passes would occur +that do things like break matrix multiplication into a series of dot +products/MADs, make structure assignment be a series of assignment of +components, flatten if statements into conditional moves, and such, +producing a low level IR ("LIR"). + +However, it now appears that each driver will have different +requirements from a LIR. A 915-generation chipset wants all functions +inlined, all loops unrolled, all ifs flattened, no variable array +accesses, and matrix multiplication broken down. The Mesa IR backend +for swrast would like matrices and structure assignment broken down, +but it can support function calls and dynamic branching. A 965 vertex +shader IR backend could potentially even handle some matrix operations +without breaking them down, but the 965 fragment shader IR backend +would want to break to have (almost) all operations down channel-wise +and perform optimization on that. As a result, there's no single +low-level IR that will make everyone happy. So that usage has fallen +out of favor, and each driver will perform a series of lowering passes +to take the HIR down to whatever restrictions it wants to impose +before doing codegen. + +Q: How is the IR structured? + +A: The best way to get started seeing it would be to run the +standalone compiler against a shader: + +./glsl_compiler --dump-lir \ + ~/src/piglit/tests/shaders/glsl-orangebook-ch06-bump.frag + +So for example one of the ir_instructions in main() contains: + +(assign (constant bool (1)) (var_ref litColor) (expression vec3 * (var_ref Surf +aceColor) (var_ref __retval) ) ) + +Or more visually: + (assign) + / | \ + (var_ref) (expression *) (constant bool 1) + / / \ +(litColor) (var_ref) (var_ref) + / \ + (SurfaceColor) (__retval) + +which came from: + +litColor = SurfaceColor * max(dot(normDelta, LightDir), 0.0); + +(the max call is not represented in this expression tree, as it was a +function call that got inlined but not brought into this expression +tree) + +Each of those nodes is a subclass of ir_instruction. A particular +ir_instruction instance may only appear once in the whole IR tree with +the exception of ir_variables, which appear once as variable +declarations: + +(declare () vec3 normDelta) + +and multiple times as the targets of variable dereferences: +... +(assign (constant bool (1)) (var_ref __retval) (expression float dot + (var_ref normDelta) (var_ref LightDir) ) ) +... +(assign (constant bool (1)) (var_ref __retval) (expression vec3 - + (var_ref LightDir) (expression vec3 * (constant float (2.000000)) + (expression vec3 * (expression float dot (var_ref normDelta) (var_ref + LightDir) ) (var_ref normDelta) ) ) ) ) +... + +Each node has a type. Expressions may involve several different types: +(declare (uniform ) mat4 gl_ModelViewMatrix) +((assign (constant bool (1)) (var_ref constructor_tmp) (expression + vec4 * (var_ref gl_ModelViewMatrix) (var_ref gl_Vertex) ) ) + +An expression tree can be arbitrarily deep, and the compiler tries to +keep them structured like that so that things like algebraic +optimizations ((color * 1.0 == color) and ((mat1 * mat2) * vec == mat1 +* (mat2 * vec))) or recognizing operation patterns for code generation +(vec1 * vec2 + vec3 == mad(vec1, vec2, vec3)) are easier. This comes +at the expense of additional trickery in implementing some +optimizations like CSE where one must navigate an expression tree. + +Q: Why no SSA representation? + +A: Converting an IR tree to SSA form makes dead code elmimination, +common subexpression elimination, and many other optimizations much +easier. However, in our primarily vector-based language, there's some +major questions as to how it would work. Do we do SSA on the scalar +or vector level? If we do it at the vector level, we're going to end +up with many different versions of the variable when encountering code +like: + +(assign (constant bool (1)) (swiz x (var_ref __retval) ) (var_ref a) ) +(assign (constant bool (1)) (swiz y (var_ref __retval) ) (var_ref b) ) +(assign (constant bool (1)) (swiz z (var_ref __retval) ) (var_ref c) ) + +If every masked update of a component relies on the previous value of +the variable, then we're probably going to be quite limited in our +dead code elimination wins, and recognizing common expressions may +just not happen. On the other hand, if we operate channel-wise, then +we'll be prone to optimizing the operation on one of the channels at +the expense of making its instruction flow different from the other +channels, and a vector-based GPU would end up with worse code than if +we didn't optimize operations on that channel! + +Once again, it appears that our optimization requirements are driven +significantly by the target architecture. For now, targeting the Mesa +IR backend, SSA does not appear to be that important to producing +excellent code, but we do expect to do some SSA-based optimizations +for the 965 fragment shader backend when that is developed. + +Q: How should I expand instructions that take multiple backend instructions? + +Sometimes you'll have to do the expansion in your code generation -- +see, for example, ir_to_mesa.cpp's handling of ir_binop_mul for +matrices. However, in many cases you'll want to do a pass over the IR +to convert non-native instructions to a series of native instructions. +For example, for the Mesa backend we have ir_div_to_mul_rcp.cpp because +Mesa IR (and many hardware backends) only have a reciprocal +instruction, not a divide. Implementing non-native instructions this +way gives the chance for constant folding to occur, so (a / 2.0) +becomes (a * 0.5) after codegen instead of (a * (1.0 / 2.0)) + +Q: How shoud I handle my special hardware instructions with respect to IR? + +Our current theory is that if multiple targets have an instruction for +some operation, then we should probably be able to represent that in +the IR. Generally this is in the form of an ir_{bin,un}op expression +type. For example, we initially implemented fract() using (a - +floor(a)), but both 945 and 965 have instructions to give that result, +and it would also simplify the implementation of mod(), so +ir_unop_fract was added. The following areas need updating to add a +new expression type: + +ir.h (new enum) +ir.cpp:get_num_operands() (used for ir_reader) +ir.cpp:operator_strs (used for ir_reader) +ir_constant_expression.cpp (you probably want to be able to constant fold) +ir_validate.cpp (check users have the right types) + +You may also need to update the backends if they will see the new expr type: + +../mesa/shaders/ir_to_mesa.cpp + +You can then use the new expression from builtins (if all backends +would rather see it), or scan the IR and convert to use your new +expression type (see ir_mod_to_fract, for example). diff --git a/src/glsl/SConscript b/src/glsl/SConscript index 8e18626c40..a808a5bc5d 100644 --- a/src/glsl/SConscript +++ b/src/glsl/SConscript @@ -4,23 +4,72 @@ Import('*') env = env.Clone() +env.Prepend(CPPPATH = [ + '#src/mapi', + '#src/mesa', +]) + +if env['platform'] == 'windows': + env.Prepend(CPPPATH = ['#src/talloc']) + sources = [ - 'pp/sl_pp_context.c', - 'pp/sl_pp_define.c', - 'pp/sl_pp_dict.c', - 'pp/sl_pp_error.c', - 'pp/sl_pp_expression.c', - 'pp/sl_pp_extension.c', - 'pp/sl_pp_if.c', - 'pp/sl_pp_line.c', - 'pp/sl_pp_macro.c', - 'pp/sl_pp_pragma.c', - 'pp/sl_pp_process.c', - 'pp/sl_pp_purify.c', - 'pp/sl_pp_token.c', - 'pp/sl_pp_token_util.c', - 'pp/sl_pp_version.c', - 'cl/sl_cl_parse.c', + 'glcpp/glcpp-lex.c', + 'glcpp/glcpp-parse.c', + 'glcpp/pp.c', + 'ast_expr.cpp', + 'ast_function.cpp', + 'ast_to_hir.cpp', + 'ast_type.cpp', + 'builtin_function.cpp', + 'glsl_lexer.cpp', + 'glsl_parser.cpp', + 'glsl_parser_extras.cpp', + 'glsl_types.cpp', + 'glsl_symbol_table.cpp', + 'hir_field_selection.cpp', + 'ir_algebraic.cpp', + 'ir_basic_block.cpp', + 'ir_clone.cpp', + 'ir_constant_expression.cpp', + 'ir_constant_folding.cpp', + 'ir_constant_propagation.cpp', + 'ir_constant_variable.cpp', + 'ir_copy_propagation.cpp', + 'ir.cpp', + 'ir_dead_code.cpp', + 'ir_dead_code_local.cpp', + 'ir_dead_functions.cpp', + 'ir_div_to_mul_rcp.cpp', + 'ir_explog_to_explog2.cpp', + 'ir_expression_flattening.cpp', + 'ir_function_can_inline.cpp', + 'ir_function.cpp', + 'ir_function_inlining.cpp', + 'ir_hierarchical_visitor.cpp', + 'ir_hv_accept.cpp', + 'ir_if_return.cpp', + 'ir_if_simplification.cpp', + 'ir_if_to_cond_assign.cpp', + 'ir_import_prototypes.cpp', + 'ir_mat_op_to_vec.cpp', + 'ir_mod_to_fract.cpp', + 'ir_noop_swizzle.cpp', + 'ir_print_visitor.cpp', + 'ir_reader.cpp', + 'ir_rvalue_visitor.cpp', + 'ir_set_program_inouts.cpp', + 'ir_structure_splitting.cpp', + 'ir_sub_to_add_neg.cpp', + 'ir_swizzle_swizzle.cpp', + 'ir_tree_grafting.cpp', + 'ir_validate.cpp', + 'ir_variable.cpp', + 'ir_variable_refcount.cpp', + 'ir_vec_index_to_cond_assign.cpp', + 'ir_vec_index_to_swizzle.cpp', + 'linker.cpp', + 'link_functions.cpp', + 's_expression.cpp', ] glsl = env.ConvenienceLibrary( @@ -30,6 +79,9 @@ glsl = env.ConvenienceLibrary( Export('glsl') +# FIXME: We can't build the programs because there's a cyclic dependency between tis directory and src/mesa +Return() + env = env.Clone() if env['platform'] == 'windows': @@ -37,33 +89,16 @@ if env['platform'] == 'windows': 'user32', ]) -env.Prepend(LIBS = [glsl]) - -env.Program( - target = 'purify', - source = ['apps/purify.c'], -) +env.Prepend(LIBS = [glsl, talloc]) env.Program( - target = 'tokenise', - source = ['apps/tokenise.c'], + target = 'glsl2', + source = [ + 'main.cpp', + ] ) env.Program( - target = 'version', - source = ['apps/version.c'], + target = 'glcpp', + source = ['glcpp/glcpp.c'], ) - -env.Program( - target = 'process', - source = ['apps/process.c'], -) - -glsl_compile = env.Program( - target = 'compile', - source = ['apps/compile.c'], -) - -if env['platform'] == common.default_platform: - # Only export the GLSL compiler when building for the host platform - Export('glsl_compile') diff --git a/src/glsl/TODO b/src/glsl/TODO new file mode 100644 index 0000000000..07ac5f5c6e --- /dev/null +++ b/src/glsl/TODO @@ -0,0 +1,50 @@ +- Handle constant expressions of (struct == struct) + +- Handle constant expressions of (struct != struct) + +- Treat built-in functions with constant parameters as constant expressions. + - Rewrite all built-in functions return a single expression. + - Modify the HIR generator for functions to automatically inline built-in + functions durning translation. + - Care must be taken to handle both the 1.10 rules and the 1.20+ rules. In + 1.10, built-in functions cannot be constant expressions. + +- Detect code paths in non-void functions that don't reach a return statement + +- Handle over-riding built-in functions + - Is the overload per-compilation unit or per-linked shader? + +- Handle redeclaration of built-in variables + - Handle addition of qualifiers such as 'invariant' or 'centroid'. + - Handle resizing of arrays. + - Other? We'll have to look at the spec. + +- Improve handling of constants and their initializers. Constant initializers + should never generate any code. This is trival for scalar constants. It is + also trivial for arrays, matrices, and vectors that are accessed with + constant index values. For others it is more complicated. Perhaps these + cases should be silently converted to uniforms? + +1.30 features: + +- Implement AST-to-HIR conversion of bit-shift operators. + +- Implement AST-to-HIR conversion of bit-wise {&,|,^,!} operators. + +- Implement AST-to-HIR conversion of switch-statements + - switch + - case + - Update break to correcly handle mixed nexting of switch-statements + and loops. + +- Handle currently unsupported constant expression types + - ir_unop_bit_not + - ir_binop_mod + - ir_binop_lshift + - ir_binop_rshift + - ir_binop_bit_and + - ir_binop_bit_xor + - ir_binop_bit_or + +- Implement support for 1.30 style shadow compares which only return a float + instead of a vec4. diff --git a/src/glsl/apps/.gitignore b/src/glsl/apps/.gitignore deleted file mode 100644 index 7e011ce7a1..0000000000 --- a/src/glsl/apps/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -compile -process -purify -tokenise -version diff --git a/src/glsl/apps/Makefile b/src/glsl/apps/Makefile deleted file mode 100644 index 39a0df7fea..0000000000 --- a/src/glsl/apps/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# src/glsl/apps/Makefile - -TOP = ../../.. - -include $(TOP)/configs/current - -LIBS = \ - $(TOP)/src/glsl/pp/libglslpp.a \ - $(TOP)/src/glsl/cl/libglslcl.a - -SOURCES = \ - compile.c \ - process.c \ - purify.c \ - tokenise.c \ - version.c - -APPS = $(SOURCES:%.c=%) - -INCLUDES = -I. - - -##### RULES ##### - -.SUFFIXES: -.SUFFIXES: .c - -.c: - $(APP_CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $< $(LIBS) -o $@ - -.c.o: - $(APP_CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ - - -##### TARGETS ##### - -default: $(APPS) - -install: - -clean: - -rm -f $(APPS) - -rm -f *.o diff --git a/src/glsl/apps/compile.c b/src/glsl/apps/compile.c deleted file mode 100644 index 5114fc9d0b..0000000000 --- a/src/glsl/apps/compile.c +++ /dev/null @@ -1,198 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include "../pp/sl_pp_public.h" -#include "../pp/sl_pp_purify.h" -#include "../cl/sl_cl_parse.h" - - -static void -usage(void) -{ - printf("Usage:\n"); - printf(" compile fragment|vertex|geometry <source> <output>\n"); -} - -int -main(int argc, - char *argv[]) -{ - FILE *in; - long size; - char *inbuf; - struct sl_pp_purify_options options; - char errmsg[100] = ""; - struct sl_pp_context *context; - unsigned int version; - FILE *out; - unsigned char *outbytes; - unsigned int cboutbytes; - unsigned int shader_type; - - if (argc != 4) { - usage(); - return 1; - } - - if (!strcmp(argv[1], "fragment")) { - shader_type = 1; - } else if (!strcmp(argv[1], "vertex")) { - shader_type = 2; - } else if (!strcmp(argv[1], "geometry")) { - shader_type = 3; - } else { - usage(); - return 1; - } - - in = fopen(argv[2], "rb"); - if (!in) { - printf("Could not open `%s' for read.\n", argv[2]); - usage(); - return 1; - } - - fseek(in, 0, SEEK_END); - size = ftell(in); - assert(size != -1); - if (size == -1) { - return 1; - } - fseek(in, 0, SEEK_SET); - - out = fopen(argv[3], "w"); - if (!out) { - fclose(in); - printf("Could not open `%s' for write.\n", argv[3]); - usage(); - return 1; - } - - inbuf = malloc(size + 1); - if (!inbuf) { - fprintf(out, "$OOMERROR\n"); - - fclose(out); - fclose(in); - printf("Out of memory.\n"); - return 0; - } - - if (fread(inbuf, 1, size, in) != size) { - fprintf(out, "$READERROR\n"); - - free(inbuf); - fclose(out); - fclose(in); - printf("Could not read from `%s'.\n", argv[2]); - return 0; - } - inbuf[size] = '\0'; - - fclose(in); - - memset(&options, 0, sizeof(options)); - - context = sl_pp_context_create(inbuf, &options); - if (!context) { - fprintf(out, "$CONTEXERROR\n"); - - free(inbuf); - fclose(out); - printf("Could not create parse context.\n"); - return 0; - } - - if (sl_pp_version(context, &version)) { - fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context)); - - printf("Error: %s\n", sl_pp_context_error_message(context)); - sl_pp_context_destroy(context); - free(inbuf); - fclose(out); - return 0; - } - - if (sl_pp_context_add_extension(context, "GL_ARB_draw_buffers") || - sl_pp_context_add_extension(context, "GL_ARB_texture_rectangle")) { - fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context)); - - printf("Error: %s\n", sl_pp_context_error_message(context)); - sl_pp_context_destroy(context); - free(inbuf); - fclose(out); - return 0; - } - - if (sl_cl_compile(context, shader_type, 1, &outbytes, &cboutbytes, errmsg, sizeof(errmsg)) == 0) { - unsigned int i; - unsigned int line = 0; - - fprintf(out, "\n/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */"); - fprintf(out, "\n/* %s */", argv[2]); - fprintf(out, "\n\n"); - - for (i = 0; i < cboutbytes; i++) { - unsigned int a; - - if (outbytes[i] < 10) { - a = 1; - } else if (outbytes[i] < 100) { - a = 2; - } else { - a = 3; - } - if (i < cboutbytes - 1) { - a++; - } - if (line + a >= 100) { - fprintf (out, "\n"); - line = 0; - } - line += a; - fprintf (out, "%u", outbytes[i]); - if (i < cboutbytes - 1) { - fprintf (out, ","); - } - } - fprintf (out, "\n"); - free(outbytes); - } else { - fprintf(out, "$SYNTAXERROR: `%s'\n", errmsg); - - printf("Error: %s\n", errmsg); - } - - sl_pp_context_destroy(context); - free(inbuf); - fclose(out); - return 0; -} diff --git a/src/glsl/apps/process.c b/src/glsl/apps/process.c deleted file mode 100644 index 6d5ce6eea3..0000000000 --- a/src/glsl/apps/process.c +++ /dev/null @@ -1,388 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include "../pp/sl_pp_public.h" -#include "../pp/sl_pp_purify.h" -#include "../pp/sl_pp_token.h" - - -int -main(int argc, - char *argv[]) -{ - FILE *in; - long size; - char *inbuf; - struct sl_pp_purify_options options; - struct sl_pp_context *context; - unsigned int version; - struct sl_pp_token_info *outtokens; - FILE *out; - unsigned int i; - - if (argc != 3) { - printf("Usage: process infile outfile\n"); - return 1; - } - - in = fopen(argv[1], "rb"); - if (!in) { - return 1; - } - - fseek(in, 0, SEEK_END); - size = ftell(in); - assert(size != -1); - if (size == -1) { - return 1; - } - fseek(in, 0, SEEK_SET); - - out = fopen(argv[2], "wb"); - if (!out) { - fclose(in); - return 1; - } - - inbuf = malloc(size + 1); - if (!inbuf) { - fprintf(out, "$OOMERROR\n"); - - fclose(out); - fclose(in); - return 1; - } - - if (fread(inbuf, 1, size, in) != size) { - fprintf(out, "$READERROR\n"); - - free(inbuf); - fclose(out); - fclose(in); - return 1; - } - inbuf[size] = '\0'; - - fclose(in); - - memset(&options, 0, sizeof(options)); - - context = sl_pp_context_create(inbuf, &options); - if (!context) { - fprintf(out, "$CONTEXERROR\n"); - - free(inbuf); - fclose(out); - return 1; - } - - if (sl_pp_version(context, &version)) { - fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context)); - - sl_pp_context_destroy(context); - free(inbuf); - fclose(out); - return -1; - } - - if (sl_pp_context_add_extension(context, "GL_ARB_draw_buffers") || - sl_pp_context_add_extension(context, "GL_ARB_texture_rectangle")) { - fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context)); - - printf("Error: %s\n", sl_pp_context_error_message(context)); - sl_pp_context_destroy(context); - free(inbuf); - fclose(out); - return 0; - } - - if (sl_pp_context_add_predefined(context, "__GLSL_PP_PREDEFINED_MACRO_TEST", "1")) { - fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context)); - - printf("Error: %s\n", sl_pp_context_error_message(context)); - sl_pp_context_destroy(context); - free(inbuf); - fclose(out); - return 0; - } - - if (sl_pp_process(context, &outtokens)) { - fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context)); - - sl_pp_context_destroy(context); - free(inbuf); - fclose(out); - return -1; - } - - free(inbuf); - - for (i = 0; outtokens[i].token != SL_PP_EOF; i++) { - switch (outtokens[i].token) { - case SL_PP_NEWLINE: - fprintf(out, "\n"); - break; - - case SL_PP_COMMA: - fprintf(out, ", "); - break; - - case SL_PP_SEMICOLON: - fprintf(out, "; "); - break; - - case SL_PP_LBRACE: - fprintf(out, "{ "); - break; - - case SL_PP_RBRACE: - fprintf(out, "} "); - break; - - case SL_PP_LPAREN: - fprintf(out, "( "); - break; - - case SL_PP_RPAREN: - fprintf(out, ") "); - break; - - case SL_PP_LBRACKET: - fprintf(out, "[ "); - break; - - case SL_PP_RBRACKET: - fprintf(out, "] "); - break; - - case SL_PP_DOT: - fprintf(out, ". "); - break; - - case SL_PP_INCREMENT: - fprintf(out, "++ "); - break; - - case SL_PP_ADDASSIGN: - fprintf(out, "+= "); - break; - - case SL_PP_PLUS: - fprintf(out, "+ "); - break; - - case SL_PP_DECREMENT: - fprintf(out, "-- "); - break; - - case SL_PP_SUBASSIGN: - fprintf(out, "-= "); - break; - - case SL_PP_MINUS: - fprintf(out, "- "); - break; - - case SL_PP_BITNOT: - fprintf(out, "~ "); - break; - - case SL_PP_NOTEQUAL: - fprintf(out, "!= "); - break; - - case SL_PP_NOT: - fprintf(out, "! "); - break; - - case SL_PP_MULASSIGN: - fprintf(out, "*= "); - break; - - case SL_PP_STAR: - fprintf(out, "* "); - break; - - case SL_PP_DIVASSIGN: - fprintf(out, "/= "); - break; - - case SL_PP_SLASH: - fprintf(out, "/ "); - break; - - case SL_PP_MODASSIGN: - fprintf(out, "%%= "); - break; - - case SL_PP_MODULO: - fprintf(out, "%% "); - break; - - case SL_PP_LSHIFTASSIGN: - fprintf(out, "<<= "); - break; - - case SL_PP_LSHIFT: - fprintf(out, "<< "); - break; - - case SL_PP_LESSEQUAL: - fprintf(out, "<= "); - break; - - case SL_PP_LESS: - fprintf(out, "< "); - break; - - case SL_PP_RSHIFTASSIGN: - fprintf(out, ">>= "); - break; - - case SL_PP_RSHIFT: - fprintf(out, ">> "); - break; - - case SL_PP_GREATEREQUAL: - fprintf(out, ">= "); - break; - - case SL_PP_GREATER: - fprintf(out, "> "); - break; - - case SL_PP_EQUAL: - fprintf(out, "== "); - break; - - case SL_PP_ASSIGN: - fprintf(out, "= "); - break; - - case SL_PP_AND: - fprintf(out, "&& "); - break; - - case SL_PP_BITANDASSIGN: - fprintf(out, "&= "); - break; - - case SL_PP_BITAND: - fprintf(out, "& "); - break; - - case SL_PP_XOR: - fprintf(out, "^^ "); - break; - - case SL_PP_BITXORASSIGN: - fprintf(out, "^= "); - break; - - case SL_PP_BITXOR: - fprintf(out, "^ "); - break; - - case SL_PP_OR: - fprintf(out, "|| "); - break; - - case SL_PP_BITORASSIGN: - fprintf(out, "|= "); - break; - - case SL_PP_BITOR: - fprintf(out, "| "); - break; - - case SL_PP_QUESTION: - fprintf(out, "? "); - break; - - case SL_PP_COLON: - fprintf(out, ": "); - break; - - case SL_PP_IDENTIFIER: - fprintf(out, "%s ", sl_pp_context_cstr(context, outtokens[i].data.identifier)); - break; - - case SL_PP_UINT: - fprintf(out, "%s ", sl_pp_context_cstr(context, outtokens[i].data._uint)); - break; - - case SL_PP_FLOAT: - fprintf(out, "%s ", sl_pp_context_cstr(context, outtokens[i].data._float)); - break; - - case SL_PP_OTHER: - fprintf(out, "%c", outtokens[i].data.other); - break; - - case SL_PP_PRAGMA_OPTIMIZE: - fprintf(out, "#pragma optimize(%s)", outtokens[i].data.pragma ? "on" : "off"); - break; - - case SL_PP_PRAGMA_DEBUG: - fprintf(out, "#pragma debug(%s)", outtokens[i].data.pragma ? "on" : "off"); - break; - - case SL_PP_EXTENSION_REQUIRE: - fprintf(out, "#extension %s : require", sl_pp_context_cstr(context, outtokens[i].data.extension)); - break; - - case SL_PP_EXTENSION_ENABLE: - fprintf(out, "#extension %s : enable", sl_pp_context_cstr(context, outtokens[i].data.extension)); - break; - - case SL_PP_EXTENSION_WARN: - fprintf(out, "#extension %s : warn", sl_pp_context_cstr(context, outtokens[i].data.extension)); - break; - - case SL_PP_EXTENSION_DISABLE: - fprintf(out, "#extension %s : disable", sl_pp_context_cstr(context, outtokens[i].data.extension)); - break; - - case SL_PP_LINE: - fprintf(out, "#line %u %u", outtokens[i].data.line.lineno, outtokens[i].data.line.fileno); - break; - - default: - assert(0); - } - } - - sl_pp_context_destroy(context); - free(outtokens); - fclose(out); - - return 0; -} diff --git a/src/glsl/apps/purify.c b/src/glsl/apps/purify.c deleted file mode 100644 index e3fca59ab4..0000000000 --- a/src/glsl/apps/purify.c +++ /dev/null @@ -1,112 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "../pp/sl_pp_public.h" -#include "../pp/sl_pp_purify.h" - - -int -main(int argc, - char *argv[]) -{ - FILE *in; - long size; - char *inbuf; - struct sl_pp_purify_options options; - char *outbuf; - char errmsg[100] = ""; - unsigned int errline = 0; - FILE *out; - - if (argc != 3) { - printf("Usage: purify infile outfile\n"); - return 1; - } - - in = fopen(argv[1], "rb"); - if (!in) { - return 1; - } - - fseek(in, 0, SEEK_END); - size = ftell(in); - assert(size != -1); - if (size == -1) { - return 1; - } - fseek(in, 0, SEEK_SET); - - out = fopen(argv[2], "wb"); - if (!out) { - fclose(in); - return 1; - } - - inbuf = malloc(size + 1); - if (!inbuf) { - fprintf(out, "$OOMERROR\n"); - - fclose(out); - fclose(in); - return 1; - } - - if (fread(inbuf, 1, size, in) != size) { - fprintf(out, "$READERROR\n"); - - free(inbuf); - fclose(out); - fclose(in); - return 1; - } - inbuf[size] = '\0'; - - fclose(in); - - memset(&options, 0, sizeof(options)); - - if (sl_pp_purify(inbuf, &options, &outbuf, errmsg, sizeof(errmsg), &errline)) { - fprintf(out, "$PURIFYERROR %u: %s\n", errline, errmsg); - - free(inbuf); - fclose(out); - return 1; - } - - free(inbuf); - - fwrite(outbuf, 1, strlen(outbuf), out); - - free(outbuf); - fclose(out); - - return 0; -} diff --git a/src/glsl/apps/tokenise.c b/src/glsl/apps/tokenise.c deleted file mode 100644 index 3d68334bed..0000000000 --- a/src/glsl/apps/tokenise.c +++ /dev/null @@ -1,340 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include "../pp/sl_pp_public.h" -#include "../pp/sl_pp_purify.h" -#include "../pp/sl_pp_token.h" - - -int -main(int argc, - char *argv[]) -{ - FILE *in; - long size; - char *inbuf; - struct sl_pp_purify_options options; - struct sl_pp_context *context; - struct sl_pp_token_info *tokens; - FILE *out; - unsigned int i; - - if (argc != 3) { - printf("Usage: tokenize infile outfile\n"); - return 1; - } - - in = fopen(argv[1], "rb"); - if (!in) { - return 1; - } - - fseek(in, 0, SEEK_END); - size = ftell(in); - assert(size != -1); - if (size == -1) { - return 1; - } - fseek(in, 0, SEEK_SET); - - out = fopen(argv[2], "wb"); - if (!out) { - fclose(in); - return 1; - } - - inbuf = malloc(size + 1); - if (!inbuf) { - fprintf(out, "$OOMERROR\n"); - - fclose(out); - fclose(in); - return 1; - } - - if (fread(inbuf, 1, size, in) != size) { - fprintf(out, "$READERROR\n"); - - free(inbuf); - fclose(out); - fclose(in); - return 1; - } - inbuf[size] = '\0'; - - fclose(in); - - memset(&options, 0, sizeof(options)); - - context = sl_pp_context_create(inbuf, &options); - if (!context) { - fprintf(out, "$CONTEXERROR\n"); - - free(inbuf); - fclose(out); - return 1; - } - - if (sl_pp_tokenise(context, &tokens)) { - fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context)); - - sl_pp_context_destroy(context); - free(inbuf); - fclose(out); - return 1; - } - - free(inbuf); - - for (i = 0; tokens[i].token != SL_PP_EOF; i++) { - switch (tokens[i].token) { - case SL_PP_WHITESPACE: - break; - - case SL_PP_NEWLINE: - fprintf(out, "\n"); - break; - - case SL_PP_HASH: - fprintf(out, "# "); - break; - - case SL_PP_COMMA: - fprintf(out, ", "); - break; - - case SL_PP_SEMICOLON: - fprintf(out, "; "); - break; - - case SL_PP_LBRACE: - fprintf(out, "{ "); - break; - - case SL_PP_RBRACE: - fprintf(out, "} "); - break; - - case SL_PP_LPAREN: - fprintf(out, "( "); - break; - - case SL_PP_RPAREN: - fprintf(out, ") "); - break; - - case SL_PP_LBRACKET: - fprintf(out, "[ "); - break; - - case SL_PP_RBRACKET: - fprintf(out, "] "); - break; - - case SL_PP_DOT: - fprintf(out, ". "); - break; - - case SL_PP_INCREMENT: - fprintf(out, "++ "); - break; - - case SL_PP_ADDASSIGN: - fprintf(out, "+= "); - break; - - case SL_PP_PLUS: - fprintf(out, "+ "); - break; - - case SL_PP_DECREMENT: - fprintf(out, "-- "); - break; - - case SL_PP_SUBASSIGN: - fprintf(out, "-= "); - break; - - case SL_PP_MINUS: - fprintf(out, "- "); - break; - - case SL_PP_BITNOT: - fprintf(out, "~ "); - break; - - case SL_PP_NOTEQUAL: - fprintf(out, "!= "); - break; - - case SL_PP_NOT: - fprintf(out, "! "); - break; - - case SL_PP_MULASSIGN: - fprintf(out, "*= "); - break; - - case SL_PP_STAR: - fprintf(out, "* "); - break; - - case SL_PP_DIVASSIGN: - fprintf(out, "/= "); - break; - - case SL_PP_SLASH: - fprintf(out, "/ "); - break; - - case SL_PP_MODASSIGN: - fprintf(out, "%%= "); - break; - - case SL_PP_MODULO: - fprintf(out, "%% "); - break; - - case SL_PP_LSHIFTASSIGN: - fprintf(out, "<<= "); - break; - - case SL_PP_LSHIFT: - fprintf(out, "<< "); - break; - - case SL_PP_LESSEQUAL: - fprintf(out, "<= "); - break; - - case SL_PP_LESS: - fprintf(out, "< "); - break; - - case SL_PP_RSHIFTASSIGN: - fprintf(out, ">>= "); - break; - - case SL_PP_RSHIFT: - fprintf(out, ">> "); - break; - - case SL_PP_GREATEREQUAL: - fprintf(out, ">= "); - break; - - case SL_PP_GREATER: - fprintf(out, "> "); - break; - - case SL_PP_EQUAL: - fprintf(out, "== "); - break; - - case SL_PP_ASSIGN: - fprintf(out, "= "); - break; - - case SL_PP_AND: - fprintf(out, "&& "); - break; - - case SL_PP_BITANDASSIGN: - fprintf(out, "&= "); - break; - - case SL_PP_BITAND: - fprintf(out, "& "); - break; - - case SL_PP_XOR: - fprintf(out, "^^ "); - break; - - case SL_PP_BITXORASSIGN: - fprintf(out, "^= "); - break; - - case SL_PP_BITXOR: - fprintf(out, "^ "); - break; - - case SL_PP_OR: - fprintf(out, "|| "); - break; - - case SL_PP_BITORASSIGN: - fprintf(out, "|= "); - break; - - case SL_PP_BITOR: - fprintf(out, "| "); - break; - - case SL_PP_QUESTION: - fprintf(out, "? "); - break; - - case SL_PP_COLON: - fprintf(out, ": "); - break; - - case SL_PP_IDENTIFIER: - fprintf(out, "%s ", sl_pp_context_cstr(context, tokens[i].data.identifier)); - break; - - case SL_PP_UINT: - fprintf(out, "(%s) ", sl_pp_context_cstr(context, tokens[i].data._uint)); - break; - - case SL_PP_FLOAT: - fprintf(out, "(%s) ", sl_pp_context_cstr(context, tokens[i].data._float)); - break; - - case SL_PP_OTHER: - if (tokens[i].data.other == '\'') { - fprintf(out, "'\\'' "); - } else { - fprintf(out, "'%c' ", tokens[i].data.other); - } - break; - - default: - assert(0); - } - } - - sl_pp_context_destroy(context); - free(tokens); - fclose(out); - - return 0; -} diff --git a/src/glsl/apps/version.c b/src/glsl/apps/version.c deleted file mode 100644 index 8506f35ba1..0000000000 --- a/src/glsl/apps/version.c +++ /dev/null @@ -1,121 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include "../pp/sl_pp_public.h" -#include "../pp/sl_pp_purify.h" - - -int -main(int argc, - char *argv[]) -{ - FILE *in; - long size; - char *inbuf; - struct sl_pp_purify_options options; - struct sl_pp_context *context; - unsigned int version; - FILE *out; - - if (argc != 3) { - printf("Usage: version infile outfile\n"); - return 1; - } - - in = fopen(argv[1], "rb"); - if (!in) { - return 1; - } - - fseek(in, 0, SEEK_END); - size = ftell(in); - assert(size != -1); - if (size == -1) { - return 1; - } - fseek(in, 0, SEEK_SET); - - out = fopen(argv[2], "wb"); - if (!out) { - fclose(in); - return 1; - } - - inbuf = malloc(size + 1); - if (!inbuf) { - fprintf(out, "$OOMERROR\n"); - - fclose(out); - fclose(in); - return 1; - } - - if (fread(inbuf, 1, size, in) != size) { - fprintf(out, "$READERROR\n"); - - free(inbuf); - fclose(out); - fclose(in); - return 1; - } - inbuf[size] = '\0'; - - fclose(in); - - memset(&options, 0, sizeof(options)); - - context = sl_pp_context_create(inbuf, &options); - if (!context) { - fprintf(out, "$CONTEXERROR\n"); - - free(inbuf); - fclose(out); - return 1; - } - - if (sl_pp_version(context, &version)) { - fprintf(out, "$ERROR: `%s'\n", sl_pp_context_error_message(context)); - - sl_pp_context_destroy(context); - free(inbuf); - fclose(out); - return -1; - } - - sl_pp_context_destroy(context); - free(inbuf); - - fprintf(out, "%u\n", version); - - fclose(out); - - return 0; -} diff --git a/src/glsl/ast.h b/src/glsl/ast.h new file mode 100644 index 0000000000..44c31b6e62 --- /dev/null +++ b/src/glsl/ast.h @@ -0,0 +1,664 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef AST_H +#define AST_H + +#include "list.h" +#include "glsl_parser_extras.h" + +struct _mesa_glsl_parse_state; + +struct YYLTYPE; + +class ast_node { +public: + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *node; + + node = talloc_zero_size(ctx, size); + assert(node != NULL); + + return node; + } + + /* If the user *does* call delete, that's OK, we will just + * talloc_free in that case. */ + static void operator delete(void *table) + { + talloc_free(table); + } + + virtual void print(void) const; + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + /** + * Retrieve the source location of an AST node + * + * This function is primarily used to get the source position of an AST node + * into a form that can be passed to \c _mesa_glsl_error. + * + * \sa _mesa_glsl_error, ast_node::set_location + */ + struct YYLTYPE get_location(void) const + { + struct YYLTYPE locp; + + locp.source = this->location.source; + locp.first_line = this->location.line; + locp.first_column = this->location.column; + locp.last_line = locp.first_line; + locp.last_column = locp.first_column; + + return locp; + } + + /** + * Set the source location of an AST node from a parser location + * + * \sa ast_node::get_location + */ + void set_location(const struct YYLTYPE &locp) + { + this->location.source = locp.source; + this->location.line = locp.first_line; + this->location.column = locp.first_column; + } + + struct { + unsigned source; + unsigned line; + unsigned column; + } location; + + exec_node link; + +protected: + ast_node(void); +}; + + +enum ast_operators { + ast_assign, + ast_plus, /**< Unary + operator. */ + ast_neg, + ast_add, + ast_sub, + ast_mul, + ast_div, + ast_mod, + ast_lshift, + ast_rshift, + ast_less, + ast_greater, + ast_lequal, + ast_gequal, + ast_equal, + ast_nequal, + ast_bit_and, + ast_bit_xor, + ast_bit_or, + ast_bit_not, + ast_logic_and, + ast_logic_xor, + ast_logic_or, + ast_logic_not, + + ast_mul_assign, + ast_div_assign, + ast_mod_assign, + ast_add_assign, + ast_sub_assign, + ast_ls_assign, + ast_rs_assign, + ast_and_assign, + ast_xor_assign, + ast_or_assign, + + ast_conditional, + + ast_pre_inc, + ast_pre_dec, + ast_post_inc, + ast_post_dec, + ast_field_selection, + ast_array_index, + + ast_function_call, + + ast_identifier, + ast_int_constant, + ast_uint_constant, + ast_float_constant, + ast_bool_constant, + + ast_sequence +}; + +class ast_expression : public ast_node { +public: + ast_expression(int oper, ast_expression *, + ast_expression *, ast_expression *); + + ast_expression(const char *identifier) : + oper(ast_identifier) + { + subexpressions[0] = NULL; + subexpressions[1] = NULL; + subexpressions[2] = NULL; + primary_expression.identifier = (char *) identifier; + } + + static const char *operator_string(enum ast_operators op); + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + virtual void print(void) const; + + enum ast_operators oper; + + ast_expression *subexpressions[3]; + + union { + char *identifier; + int int_constant; + float float_constant; + unsigned uint_constant; + int bool_constant; + } primary_expression; + + + /** + * List of expressions for an \c ast_sequence or parameters for an + * \c ast_function_call + */ + exec_list expressions; +}; + +class ast_expression_bin : public ast_expression { +public: + ast_expression_bin(int oper, ast_expression *, ast_expression *); + + virtual void print(void) const; +}; + +/** + * Subclass of expressions for function calls + */ +class ast_function_expression : public ast_expression { +public: + ast_function_expression(ast_expression *callee) + : ast_expression(ast_function_call, callee, + NULL, NULL), + cons(false) + { + /* empty */ + } + + ast_function_expression(class ast_type_specifier *type) + : ast_expression(ast_function_call, (ast_expression *) type, + NULL, NULL), + cons(true) + { + /* empty */ + } + + bool is_constructor() const + { + return cons; + } + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + +private: + /** + * Is this function call actually a constructor? + */ + bool cons; +}; + + +/** + * Number of possible operators for an ast_expression + * + * This is done as a define instead of as an additional value in the enum so + * that the compiler won't generate spurious messages like "warning: + * enumeration value ‘ast_num_operators’ not handled in switch" + */ +#define AST_NUM_OPERATORS (ast_sequence + 1) + + +class ast_compound_statement : public ast_node { +public: + ast_compound_statement(int new_scope, ast_node *statements); + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + int new_scope; + exec_list statements; +}; + +class ast_declaration : public ast_node { +public: + ast_declaration(char *identifier, int is_array, ast_expression *array_size, + ast_expression *initializer); + virtual void print(void) const; + + char *identifier; + + int is_array; + ast_expression *array_size; + + ast_expression *initializer; +}; + + +enum { + ast_precision_high = 0, /**< Default precision. */ + ast_precision_medium, + ast_precision_low +}; + +struct ast_type_qualifier { + unsigned invariant:1; + unsigned constant:1; + unsigned attribute:1; + unsigned varying:1; + unsigned in:1; + unsigned out:1; + unsigned centroid:1; + unsigned uniform:1; + unsigned smooth:1; + unsigned flat:1; + unsigned noperspective:1; + + /** \name Layout qualifiers for GL_ARB_fragment_coord_conventions */ + /*@{*/ + unsigned origin_upper_left:1; + unsigned pixel_center_integer:1; + /*@}*/ +}; + +class ast_struct_specifier : public ast_node { +public: + ast_struct_specifier(char *identifier, ast_node *declarator_list); + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + char *name; + exec_list declarations; +}; + + +enum ast_types { + ast_void, + ast_float, + ast_int, + ast_uint, + ast_bool, + ast_vec2, + ast_vec3, + ast_vec4, + ast_bvec2, + ast_bvec3, + ast_bvec4, + ast_ivec2, + ast_ivec3, + ast_ivec4, + ast_uvec2, + ast_uvec3, + ast_uvec4, + ast_mat2, + ast_mat2x3, + ast_mat2x4, + ast_mat3x2, + ast_mat3, + ast_mat3x4, + ast_mat4x2, + ast_mat4x3, + ast_mat4, + ast_sampler1d, + ast_sampler2d, + ast_sampler2drect, + ast_sampler3d, + ast_samplercube, + ast_sampler1dshadow, + ast_sampler2dshadow, + ast_sampler2drectshadow, + ast_samplercubeshadow, + ast_sampler1darray, + ast_sampler2darray, + ast_sampler1darrayshadow, + ast_sampler2darrayshadow, + ast_isampler1d, + ast_isampler2d, + ast_isampler3d, + ast_isamplercube, + ast_isampler1darray, + ast_isampler2darray, + ast_usampler1d, + ast_usampler2d, + ast_usampler3d, + ast_usamplercube, + ast_usampler1darray, + ast_usampler2darray, + + ast_struct, + ast_type_name +}; + + +class ast_type_specifier : public ast_node { +public: + ast_type_specifier(int specifier); + + /** Construct a type specifier from a type name */ + ast_type_specifier(const char *name) + : type_specifier(ast_type_name), type_name(name), structure(NULL), + is_array(false), array_size(NULL), precision(ast_precision_high) + { + /* empty */ + } + + /** Construct a type specifier from a structure definition */ + ast_type_specifier(ast_struct_specifier *s) + : type_specifier(ast_struct), type_name(s->name), structure(s), + is_array(false), array_size(NULL), precision(ast_precision_high) + { + /* empty */ + } + + const struct glsl_type *glsl_type(const char **name, + struct _mesa_glsl_parse_state *state) + const; + + virtual void print(void) const; + + ir_rvalue *hir(exec_list *, struct _mesa_glsl_parse_state *); + + enum ast_types type_specifier; + + const char *type_name; + ast_struct_specifier *structure; + + int is_array; + ast_expression *array_size; + + unsigned precision:2; +}; + + +class ast_fully_specified_type : public ast_node { +public: + virtual void print(void) const; + bool has_qualifiers() const; + + ast_type_qualifier qualifier; + ast_type_specifier *specifier; +}; + + +class ast_declarator_list : public ast_node { +public: + ast_declarator_list(ast_fully_specified_type *); + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + ast_fully_specified_type *type; + exec_list declarations; + + /** + * Special flag for vertex shader "invariant" declarations. + * + * Vertex shaders can contain "invariant" variable redeclarations that do + * not include a type. For example, "invariant gl_Position;". This flag + * is used to note these cases when no type is specified. + */ + int invariant; +}; + + +class ast_parameter_declarator : public ast_node { +public: + ast_parameter_declarator() + { + this->identifier = NULL; + this->is_array = false; + this->array_size = 0; + } + + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + ast_fully_specified_type *type; + char *identifier; + int is_array; + ast_expression *array_size; + + static void parameters_to_hir(exec_list *ast_parameters, + bool formal, exec_list *ir_parameters, + struct _mesa_glsl_parse_state *state); + +private: + /** Is this parameter declaration part of a formal parameter list? */ + bool formal_parameter; + + /** + * Is this parameter 'void' type? + * + * This field is set by \c ::hir. + */ + bool is_void; +}; + + +class ast_function : public ast_node { +public: + ast_function(void); + + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + ast_fully_specified_type *return_type; + char *identifier; + + exec_list parameters; + +private: + /** + * Is this prototype part of the function definition? + * + * Used by ast_function_definition::hir to process the parameters, etc. + * of the function. + * + * \sa ::hir + */ + bool is_definition; + + /** + * Function signature corresponding to this function prototype instance + * + * Used by ast_function_definition::hir to process the parameters, etc. + * of the function. + * + * \sa ::hir + */ + class ir_function_signature *signature; + + friend class ast_function_definition; +}; + + +class ast_declaration_statement : public ast_node { +public: + ast_declaration_statement(void); + + enum { + ast_function, + ast_declaration, + ast_precision + } mode; + + union { + class ast_function *function; + ast_declarator_list *declarator; + ast_type_specifier *type; + ast_node *node; + } declaration; +}; + + +class ast_expression_statement : public ast_node { +public: + ast_expression_statement(ast_expression *); + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + ast_expression *expression; +}; + + +class ast_case_label : public ast_node { +public: + + /** + * An expression of NULL means 'default'. + */ + ast_expression *expression; +}; + +class ast_selection_statement : public ast_node { +public: + ast_selection_statement(ast_expression *condition, + ast_node *then_statement, + ast_node *else_statement); + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + ast_expression *condition; + ast_node *then_statement; + ast_node *else_statement; +}; + + +class ast_switch_statement : public ast_node { +public: + ast_expression *expression; + exec_list statements; +}; + +class ast_iteration_statement : public ast_node { +public: + ast_iteration_statement(int mode, ast_node *init, ast_node *condition, + ast_expression *rest_expression, ast_node *body); + + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *, struct _mesa_glsl_parse_state *); + + enum ast_iteration_modes { + ast_for, + ast_while, + ast_do_while + } mode; + + + ast_node *init_statement; + ast_node *condition; + ast_expression *rest_expression; + + ast_node *body; + +private: + /** + * Generate IR from the condition of a loop + * + * This is factored out of ::hir because some loops have the condition + * test at the top (for and while), and others have it at the end (do-while). + */ + void condition_to_hir(class ir_loop *, struct _mesa_glsl_parse_state *); +}; + + +class ast_jump_statement : public ast_node { +public: + ast_jump_statement(int mode, ast_expression *return_value); + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + enum ast_jump_modes { + ast_continue, + ast_break, + ast_return, + ast_discard + } mode; + + ast_expression *opt_return_value; +}; + + +class ast_function_definition : public ast_node { +public: + virtual void print(void) const; + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + ast_function *prototype; + ast_compound_statement *body; +}; + + +extern void +_mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state); + +extern ir_rvalue * +_mesa_ast_field_selection_to_hir(const ast_expression *expr, + exec_list *instructions, + struct _mesa_glsl_parse_state *state); + +#endif /* AST_H */ diff --git a/src/glsl/ast_expr.cpp b/src/glsl/ast_expr.cpp new file mode 100644 index 0000000000..4e83decb92 --- /dev/null +++ b/src/glsl/ast_expr.cpp @@ -0,0 +1,96 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <cstdio> +#include <cassert> +#include "ast.h" + +const char * +ast_expression::operator_string(enum ast_operators op) +{ + static const char *const operators[] = { + "=", + "+", + "-", + "+", + "-", + "*", + "/", + "%", + "<<", + ">>", + "<", + ">", + "<=", + ">=", + "==", + "!=", + "&", + "^", + "|", + "~", + "&&", + "^^", + "||", + "!", + + "*=", + "/=", + "%=", + "+=", + "-=", + "<<=", + ">>=", + "&=", + "^=", + "|=", + + "?:", + + "++", + "--", + "++", + "--", + ".", + }; + + assert((unsigned int)op < sizeof(operators) / sizeof(operators[0])); + + return operators[op]; +} + + +ast_expression_bin::ast_expression_bin(int oper, ast_expression *ex0, + ast_expression *ex1) : + ast_expression(oper, ex0, ex1, NULL) +{ + assert((oper >= ast_plus) && (oper <= ast_logic_not)); +} + + +void +ast_expression_bin::print(void) const +{ + subexpressions[0]->print(); + printf("%s ", operator_string(oper)); + subexpressions[1]->print(); +} diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp new file mode 100644 index 0000000000..61012b850a --- /dev/null +++ b/src/glsl/ast_function.cpp @@ -0,0 +1,1240 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "glsl_symbol_table.h" +#include "ast.h" +#include "glsl_types.h" +#include "ir.h" +#include "main/core.h" /* for MIN2 */ + +static ir_rvalue * +convert_component(ir_rvalue *src, const glsl_type *desired_type); + +bool +apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from, + struct _mesa_glsl_parse_state *state); + +static unsigned +process_parameters(exec_list *instructions, exec_list *actual_parameters, + exec_list *parameters, + struct _mesa_glsl_parse_state *state) +{ + unsigned count = 0; + + foreach_list (n, parameters) { + ast_node *const ast = exec_node_data(ast_node, n, link); + ir_rvalue *result = ast->hir(instructions, state); + + ir_constant *const constant = result->constant_expression_value(); + if (constant != NULL) + result = constant; + + actual_parameters->push_tail(result); + count++; + } + + return count; +} + + +/** + * Generate a source prototype for a function signature + * + * \param return_type Return type of the function. May be \c NULL. + * \param name Name of the function. + * \param parameters Parameter list for the function. This may be either a + * formal or actual parameter list. Only the type is used. + * + * \return + * A talloced string representing the prototype of the function. + */ +char * +prototype_string(const glsl_type *return_type, const char *name, + exec_list *parameters) +{ + char *str = NULL; + + if (return_type != NULL) + str = talloc_asprintf(str, "%s ", return_type->name); + + str = talloc_asprintf_append(str, "%s(", name); + + const char *comma = ""; + foreach_list(node, parameters) { + const ir_instruction *const param = (ir_instruction *) node; + + str = talloc_asprintf_append(str, "%s%s", comma, param->type->name); + comma = ", "; + } + + str = talloc_strdup_append(str, ")"); + return str; +} + + +static ir_rvalue * +process_call(exec_list *instructions, ir_function *f, + YYLTYPE *loc, exec_list *actual_parameters, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + + ir_function_signature *sig = f->matching_signature(actual_parameters); + + /* The instructions param will be used when the FINISHMEs below are done */ + (void) instructions; + + if (sig != NULL) { + /* Verify that 'out' and 'inout' actual parameters are lvalues. This + * isn't done in ir_function::matching_signature because that function + * cannot generate the necessary diagnostics. + */ + exec_list_iterator actual_iter = actual_parameters->iterator(); + exec_list_iterator formal_iter = sig->parameters.iterator(); + + while (actual_iter.has_next()) { + ir_rvalue *actual = (ir_rvalue *) actual_iter.get(); + ir_variable *formal = (ir_variable *) formal_iter.get(); + + assert(actual != NULL); + assert(formal != NULL); + + if ((formal->mode == ir_var_out) + || (formal->mode == ir_var_inout)) { + if (! actual->is_lvalue()) { + /* FINISHME: Log a better diagnostic here. There is no way + * FINISHME: to tell the user which parameter is invalid. + */ + _mesa_glsl_error(loc, state, "`%s' parameter is not lvalue", + (formal->mode == ir_var_out) ? "out" : "inout"); + } + } + + if (formal->type->is_numeric() || formal->type->is_boolean()) { + ir_rvalue *converted = convert_component(actual, formal->type); + actual->replace_with(converted); + } + + actual_iter.next(); + formal_iter.next(); + } + + /* Always insert the call in the instruction stream, and return a deref + * of its return val if it returns a value, since we don't know if + * the rvalue is going to be assigned to anything or not. + */ + ir_call *call = new(ctx) ir_call(sig, actual_parameters); + if (!sig->return_type->is_void()) { + ir_variable *var; + ir_dereference_variable *deref; + + var = new(ctx) ir_variable(sig->return_type, + talloc_asprintf(ctx, "%s_retval", + sig->function_name()), + ir_var_temporary); + instructions->push_tail(var); + + deref = new(ctx) ir_dereference_variable(var); + ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL); + instructions->push_tail(assign); + if (state->language_version >= 120) + var->constant_value = call->constant_expression_value(); + + deref = new(ctx) ir_dereference_variable(var); + return deref; + } else { + instructions->push_tail(call); + return NULL; + } + } else { + char *str = prototype_string(NULL, f->name, actual_parameters); + + _mesa_glsl_error(loc, state, "no matching function for call to `%s'", + str); + talloc_free(str); + + const char *prefix = "candidates are: "; + foreach_list (node, &f->signatures) { + ir_function_signature *sig = (ir_function_signature *) node; + + str = prototype_string(sig->return_type, f->name, &sig->parameters); + _mesa_glsl_error(loc, state, "%s%s\n", prefix, str); + talloc_free(str); + + prefix = " "; + } + + return ir_call::get_error_instruction(ctx); + } +} + + +static ir_rvalue * +match_function_by_name(exec_list *instructions, const char *name, + YYLTYPE *loc, exec_list *actual_parameters, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + ir_function *f = state->symbols->get_function(name); + + if (f == NULL) { + _mesa_glsl_error(loc, state, "function `%s' undeclared", name); + return ir_call::get_error_instruction(ctx); + } + + /* Once we've determined that the function being called might exist, try + * to find an overload of the function that matches the parameters. + */ + return process_call(instructions, f, loc, actual_parameters, state); +} + + +/** + * Perform automatic type conversion of constructor parameters + * + * This implements the rules in the "Conversion and Scalar Constructors" + * section (GLSL 1.10 section 5.4.1), not the "Implicit Conversions" rules. + */ +static ir_rvalue * +convert_component(ir_rvalue *src, const glsl_type *desired_type) +{ + void *ctx = talloc_parent(src); + const unsigned a = desired_type->base_type; + const unsigned b = src->type->base_type; + ir_expression *result = NULL; + + if (src->type->is_error()) + return src; + + assert(a <= GLSL_TYPE_BOOL); + assert(b <= GLSL_TYPE_BOOL); + + if ((a == b) || (src->type->is_integer() && desired_type->is_integer())) + return src; + + switch (a) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + if (b == GLSL_TYPE_FLOAT) + result = new(ctx) ir_expression(ir_unop_f2i, desired_type, src, NULL); + else { + assert(b == GLSL_TYPE_BOOL); + result = new(ctx) ir_expression(ir_unop_b2i, desired_type, src, NULL); + } + break; + case GLSL_TYPE_FLOAT: + switch (b) { + case GLSL_TYPE_UINT: + result = new(ctx) ir_expression(ir_unop_u2f, desired_type, src, NULL); + break; + case GLSL_TYPE_INT: + result = new(ctx) ir_expression(ir_unop_i2f, desired_type, src, NULL); + break; + case GLSL_TYPE_BOOL: + result = new(ctx) ir_expression(ir_unop_b2f, desired_type, src, NULL); + break; + } + break; + case GLSL_TYPE_BOOL: + switch (b) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + result = new(ctx) ir_expression(ir_unop_i2b, desired_type, src, NULL); + break; + case GLSL_TYPE_FLOAT: + result = new(ctx) ir_expression(ir_unop_f2b, desired_type, src, NULL); + break; + } + break; + } + + assert(result != NULL); + + /* Try constant folding; it may fold in the conversion we just added. */ + ir_constant *const constant = result->constant_expression_value(); + return (constant != NULL) ? (ir_rvalue *) constant : (ir_rvalue *) result; +} + +/** + * Dereference a specific component from a scalar, vector, or matrix + */ +static ir_rvalue * +dereference_component(ir_rvalue *src, unsigned component) +{ + void *ctx = talloc_parent(src); + assert(component < src->type->components()); + + /* If the source is a constant, just create a new constant instead of a + * dereference of the existing constant. + */ + ir_constant *constant = src->as_constant(); + if (constant) + return new(ctx) ir_constant(constant, component); + + if (src->type->is_scalar()) { + return src; + } else if (src->type->is_vector()) { + return new(ctx) ir_swizzle(src, component, 0, 0, 0, 1); + } else { + assert(src->type->is_matrix()); + + /* Dereference a row of the matrix, then call this function again to get + * a specific element from that row. + */ + const int c = component / src->type->column_type()->vector_elements; + const int r = component % src->type->column_type()->vector_elements; + ir_constant *const col_index = new(ctx) ir_constant(c); + ir_dereference *const col = new(ctx) ir_dereference_array(src, col_index); + + col->type = src->type->column_type(); + + return dereference_component(col, r); + } + + assert(!"Should not get here."); + return NULL; +} + + +static ir_rvalue * +process_array_constructor(exec_list *instructions, + const glsl_type *constructor_type, + YYLTYPE *loc, exec_list *parameters, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + /* Array constructors come in two forms: sized and unsized. Sized array + * constructors look like 'vec4[2](a, b)', where 'a' and 'b' are vec4 + * variables. In this case the number of parameters must exactly match the + * specified size of the array. + * + * Unsized array constructors look like 'vec4[](a, b)', where 'a' and 'b' + * are vec4 variables. In this case the size of the array being constructed + * is determined by the number of parameters. + * + * From page 52 (page 58 of the PDF) of the GLSL 1.50 spec: + * + * "There must be exactly the same number of arguments as the size of + * the array being constructed. If no size is present in the + * constructor, then the array is explicitly sized to the number of + * arguments provided. The arguments are assigned in order, starting at + * element 0, to the elements of the constructed array. Each argument + * must be the same type as the element type of the array, or be a type + * that can be converted to the element type of the array according to + * Section 4.1.10 "Implicit Conversions."" + */ + exec_list actual_parameters; + const unsigned parameter_count = + process_parameters(instructions, &actual_parameters, parameters, state); + + if ((parameter_count == 0) + || ((constructor_type->length != 0) + && (constructor_type->length != parameter_count))) { + const unsigned min_param = (constructor_type->length == 0) + ? 1 : constructor_type->length; + + _mesa_glsl_error(loc, state, "array constructor must have %s %u " + "parameter%s", + (constructor_type->length != 0) ? "at least" : "exactly", + min_param, (min_param <= 1) ? "" : "s"); + return ir_call::get_error_instruction(ctx); + } + + if (constructor_type->length == 0) { + constructor_type = + glsl_type::get_array_instance(constructor_type->element_type(), + parameter_count); + assert(constructor_type != NULL); + assert(constructor_type->length == parameter_count); + } + + bool all_parameters_are_constant = true; + + /* Type cast each parameter and, if possible, fold constants. */ + foreach_list_safe(n, &actual_parameters) { + ir_rvalue *ir = (ir_rvalue *) n; + ir_rvalue *result = ir; + + /* Apply implicit conversions (not the scalar constructor rules!) */ + if (constructor_type->element_type()->is_float()) { + const glsl_type *desired_type = + glsl_type::get_instance(GLSL_TYPE_FLOAT, + ir->type->vector_elements, + ir->type->matrix_columns); + result = convert_component(ir, desired_type); + } + + if (result->type != constructor_type->element_type()) { + _mesa_glsl_error(loc, state, "type error in array constructor: " + "expected: %s, found %s", + constructor_type->element_type()->name, + result->type->name); + } + + /* Attempt to convert the parameter to a constant valued expression. + * After doing so, track whether or not all the parameters to the + * constructor are trivially constant valued expressions. + */ + ir_rvalue *const constant = result->constant_expression_value(); + + if (constant != NULL) + result = constant; + else + all_parameters_are_constant = false; + + ir->replace_with(result); + } + + if (all_parameters_are_constant) + return new(ctx) ir_constant(constructor_type, &actual_parameters); + + ir_variable *var = new(ctx) ir_variable(constructor_type, "array_ctor", + ir_var_temporary); + instructions->push_tail(var); + + int i = 0; + foreach_list(node, &actual_parameters) { + ir_rvalue *rhs = (ir_rvalue *) node; + ir_rvalue *lhs = new(ctx) ir_dereference_array(var, + new(ctx) ir_constant(i)); + + ir_instruction *assignment = new(ctx) ir_assignment(lhs, rhs, NULL); + instructions->push_tail(assignment); + + i++; + } + + return new(ctx) ir_dereference_variable(var); +} + + +/** + * Try to convert a record constructor to a constant expression + */ +static ir_constant * +constant_record_constructor(const glsl_type *constructor_type, + exec_list *parameters, void *mem_ctx) +{ + foreach_list(node, parameters) { + ir_constant *constant = ((ir_instruction *) node)->as_constant(); + if (constant == NULL) + return NULL; + node->replace_with(constant); + } + + return new(mem_ctx) ir_constant(constructor_type, parameters); +} + + +/** + * Determine if a list consists of a single scalar r-value + */ +bool +single_scalar_parameter(exec_list *parameters) +{ + const ir_rvalue *const p = (ir_rvalue *) parameters->head; + assert(((ir_rvalue *)p)->as_rvalue() != NULL); + + return (p->type->is_scalar() && p->next->is_tail_sentinel()); +} + + +/** + * Generate inline code for a vector constructor + * + * The generated constructor code will consist of a temporary variable + * declaration of the same type as the constructor. A sequence of assignments + * from constructor parameters to the temporary will follow. + * + * \return + * An \c ir_dereference_variable of the temprorary generated in the constructor + * body. + */ +ir_rvalue * +emit_inline_vector_constructor(const glsl_type *type, + exec_list *instructions, + exec_list *parameters, + void *ctx) +{ + assert(!parameters->is_empty()); + + ir_variable *var = new(ctx) ir_variable(type, "vec_ctor", ir_var_temporary); + instructions->push_tail(var); + + /* There are two kinds of vector constructors. + * + * - Construct a vector from a single scalar by replicating that scalar to + * all components of the vector. + * + * - Construct a vector from an arbirary combination of vectors and + * scalars. The components of the constructor parameters are assigned + * to the vector in order until the vector is full. + */ + const unsigned lhs_components = type->components(); + if (single_scalar_parameter(parameters)) { + ir_rvalue *first_param = (ir_rvalue *)parameters->head; + ir_rvalue *rhs = new(ctx) ir_swizzle(first_param, 0, 0, 0, 0, + lhs_components); + ir_dereference_variable *lhs = new(ctx) ir_dereference_variable(var); + const unsigned mask = (1U << lhs_components) - 1; + + assert(rhs->type == lhs->type); + + ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL, mask); + instructions->push_tail(inst); + } else { + unsigned base_component = 0; + ir_constant_data data; + unsigned constant_mask = 0; + + memset(&data, 0, sizeof(data)); + + foreach_list(node, parameters) { + ir_rvalue *param = (ir_rvalue *) node; + unsigned rhs_components = param->type->components(); + + /* Do not try to assign more components to the vector than it has! + */ + if ((rhs_components + base_component) > lhs_components) { + rhs_components = lhs_components - base_component; + } + + const ir_constant *const c = param->as_constant(); + if (c != NULL) { + for (unsigned i = 0; i < rhs_components; i++) { + switch (c->type->base_type) { + case GLSL_TYPE_UINT: + data.u[i + base_component] = c->get_uint_component(i); + break; + case GLSL_TYPE_INT: + data.i[i + base_component] = c->get_int_component(i); + break; + case GLSL_TYPE_FLOAT: + data.f[i + base_component] = c->get_float_component(i); + break; + case GLSL_TYPE_BOOL: + data.b[i + base_component] = c->get_bool_component(i); + break; + default: + assert(!"Should not get here."); + break; + } + } + + /* Mask of fields to be written in the assignment. + */ + constant_mask |= ((1U << rhs_components) - 1) << base_component; + } + + /* Advance the component index by the number of components that were + * just assigned. + */ + base_component += rhs_components; + } + + if (constant_mask != 0) { + ir_dereference *lhs = new(ctx) ir_dereference_variable(var); + ir_rvalue *rhs = new(ctx) ir_constant(var->type, &data); + + ir_instruction *inst = + new(ctx) ir_assignment(lhs, rhs, NULL, constant_mask); + instructions->push_tail(inst); + } + + base_component = 0; + foreach_list(node, parameters) { + ir_rvalue *param = (ir_rvalue *) node; + unsigned rhs_components = param->type->components(); + + /* Do not try to assign more components to the vector than it has! + */ + if ((rhs_components + base_component) > lhs_components) { + rhs_components = lhs_components - base_component; + } + + const ir_constant *const c = param->as_constant(); + if (c == NULL) { + /* Generate a swizzle that puts the first element of the source at + * the location of the first element of the destination. + */ + unsigned swiz[4] = { 0, 0, 0, 0 }; + for (unsigned i = 0; i < rhs_components; i++) + swiz[i + base_component] = i; + + /* Mask of fields to be written in the assignment. + */ + const unsigned write_mask = ((1U << rhs_components) - 1) + << base_component; + + ir_dereference *lhs = new(ctx) ir_dereference_variable(var); + ir_rvalue *rhs = new(ctx) ir_swizzle(param, swiz, lhs_components); + + ir_instruction *inst = + new(ctx) ir_assignment(lhs, rhs, NULL, write_mask); + instructions->push_tail(inst); + } + + /* Advance the component index by the number of components that were + * just assigned. + */ + base_component += rhs_components; + } + } + return new(ctx) ir_dereference_variable(var); +} + + +/** + * Generate assignment of a portion of a vector to a portion of a matrix column + * + * \param src_base First component of the source to be used in assignment + * \param column Column of destination to be assiged + * \param row_base First component of the destination column to be assigned + * \param count Number of components to be assigned + * + * \note + * \c src_base + \c count must be less than or equal to the number of components + * in the source vector. + */ +ir_instruction * +assign_to_matrix_column(ir_variable *var, unsigned column, unsigned row_base, + ir_rvalue *src, unsigned src_base, unsigned count, + void *mem_ctx) +{ + ir_constant *col_idx = new(mem_ctx) ir_constant(column); + ir_dereference *column_ref = new(mem_ctx) ir_dereference_array(var, col_idx); + + assert(column_ref->type->components() >= (row_base + count)); + assert(src->type->components() >= (src_base + count)); + + /* Generate a swizzle that puts the first element of the source at the + * location of the first element of the destination. + */ + unsigned swiz[4] = { src_base, src_base, src_base, src_base }; + for (unsigned i = 0; i < count; i++) + swiz[i + row_base] = src_base + i; + + ir_rvalue *const rhs = + new(mem_ctx) ir_swizzle(src, swiz, column_ref->type->components()); + + /* Mask of fields to be written in the assignment. + */ + const unsigned write_mask = ((1U << count) - 1) << row_base; + + return new(mem_ctx) ir_assignment(column_ref, rhs, NULL, write_mask); +} + + +/** + * Generate inline code for a matrix constructor + * + * The generated constructor code will consist of a temporary variable + * declaration of the same type as the constructor. A sequence of assignments + * from constructor parameters to the temporary will follow. + * + * \return + * An \c ir_dereference_variable of the temprorary generated in the constructor + * body. + */ +ir_rvalue * +emit_inline_matrix_constructor(const glsl_type *type, + exec_list *instructions, + exec_list *parameters, + void *ctx) +{ + assert(!parameters->is_empty()); + + ir_variable *var = new(ctx) ir_variable(type, "mat_ctor", ir_var_temporary); + instructions->push_tail(var); + + /* There are three kinds of matrix constructors. + * + * - Construct a matrix from a single scalar by replicating that scalar to + * along the diagonal of the matrix and setting all other components to + * zero. + * + * - Construct a matrix from an arbirary combination of vectors and + * scalars. The components of the constructor parameters are assigned + * to the matrix in colum-major order until the matrix is full. + * + * - Construct a matrix from a single matrix. The source matrix is copied + * to the upper left portion of the constructed matrix, and the remaining + * elements take values from the identity matrix. + */ + ir_rvalue *const first_param = (ir_rvalue *) parameters->head; + if (single_scalar_parameter(parameters)) { + /* Assign the scalar to the X component of a vec4, and fill the remaining + * components with zero. + */ + ir_variable *rhs_var = + new(ctx) ir_variable(glsl_type::vec4_type, "mat_ctor_vec", + ir_var_temporary); + instructions->push_tail(rhs_var); + + ir_constant_data zero; + zero.f[0] = 0.0; + zero.f[1] = 0.0; + zero.f[2] = 0.0; + zero.f[3] = 0.0; + + ir_instruction *inst = + new(ctx) ir_assignment(new(ctx) ir_dereference_variable(rhs_var), + new(ctx) ir_constant(rhs_var->type, &zero), + NULL); + instructions->push_tail(inst); + + ir_dereference *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var); + + inst = new(ctx) ir_assignment(rhs_ref, first_param, NULL, 0x01); + instructions->push_tail(inst); + + /* Assign the temporary vector to each column of the destination matrix + * with a swizzle that puts the X component on the diagonal of the + * matrix. In some cases this may mean that the X component does not + * get assigned into the column at all (i.e., when the matrix has more + * columns than rows). + */ + static const unsigned rhs_swiz[4][4] = { + { 0, 1, 1, 1 }, + { 1, 0, 1, 1 }, + { 1, 1, 0, 1 }, + { 1, 1, 1, 0 } + }; + + const unsigned cols_to_init = MIN2(type->matrix_columns, + type->vector_elements); + for (unsigned i = 0; i < cols_to_init; i++) { + ir_constant *const col_idx = new(ctx) ir_constant(i); + ir_rvalue *const col_ref = new(ctx) ir_dereference_array(var, col_idx); + + ir_rvalue *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var); + ir_rvalue *const rhs = new(ctx) ir_swizzle(rhs_ref, rhs_swiz[i], + type->vector_elements); + + inst = new(ctx) ir_assignment(col_ref, rhs, NULL); + instructions->push_tail(inst); + } + + for (unsigned i = cols_to_init; i < type->matrix_columns; i++) { + ir_constant *const col_idx = new(ctx) ir_constant(i); + ir_rvalue *const col_ref = new(ctx) ir_dereference_array(var, col_idx); + + ir_rvalue *const rhs_ref = new(ctx) ir_dereference_variable(rhs_var); + ir_rvalue *const rhs = new(ctx) ir_swizzle(rhs_ref, 1, 1, 1, 1, + type->vector_elements); + + inst = new(ctx) ir_assignment(col_ref, rhs, NULL); + instructions->push_tail(inst); + } + } else if (first_param->type->is_matrix()) { + /* From page 50 (56 of the PDF) of the GLSL 1.50 spec: + * + * "If a matrix is constructed from a matrix, then each component + * (column i, row j) in the result that has a corresponding + * component (column i, row j) in the argument will be initialized + * from there. All other components will be initialized to the + * identity matrix. If a matrix argument is given to a matrix + * constructor, it is an error to have any other arguments." + */ + assert(first_param->next->is_tail_sentinel()); + ir_rvalue *const src_matrix = first_param; + + /* If the source matrix is smaller, pre-initialize the relavent parts of + * the destination matrix to the identity matrix. + */ + if ((src_matrix->type->matrix_columns < var->type->matrix_columns) + || (src_matrix->type->vector_elements < var->type->vector_elements)) { + + /* If the source matrix has fewer rows, every column of the destination + * must be initialized. Otherwise only the columns in the destination + * that do not exist in the source must be initialized. + */ + unsigned col = + (src_matrix->type->vector_elements < var->type->vector_elements) + ? 0 : src_matrix->type->matrix_columns; + + const glsl_type *const col_type = var->type->column_type(); + for (/* empty */; col < var->type->matrix_columns; col++) { + ir_constant_data ident; + + ident.f[0] = 0.0; + ident.f[1] = 0.0; + ident.f[2] = 0.0; + ident.f[3] = 0.0; + + ident.f[col] = 1.0; + + ir_rvalue *const rhs = new(ctx) ir_constant(col_type, &ident); + + ir_rvalue *const lhs = + new(ctx) ir_dereference_array(var, new(ctx) ir_constant(col)); + + ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL); + instructions->push_tail(inst); + } + } + + /* Assign columns from the source matrix to the destination matrix. + * + * Since the parameter will be used in the RHS of multiple assignments, + * generate a temporary and copy the paramter there. + */ + ir_variable *const rhs_var = + new(ctx) ir_variable(first_param->type, "mat_ctor_mat", + ir_var_temporary); + instructions->push_tail(rhs_var); + + ir_dereference *const rhs_var_ref = + new(ctx) ir_dereference_variable(rhs_var); + ir_instruction *const inst = + new(ctx) ir_assignment(rhs_var_ref, first_param, NULL); + instructions->push_tail(inst); + + const unsigned last_row = MIN2(src_matrix->type->vector_elements, + var->type->vector_elements); + const unsigned last_col = MIN2(src_matrix->type->matrix_columns, + var->type->matrix_columns); + + unsigned swiz[4] = { 0, 0, 0, 0 }; + for (unsigned i = 1; i < src_matrix->type->vector_elements; i++) + swiz[i] = i; + + const unsigned write_mask = (1U << last_row) - 1; + + for (unsigned i = 0; i < last_col; i++) { + ir_dereference *const lhs = + new(ctx) ir_dereference_array(var, new(ctx) ir_constant(i)); + ir_rvalue *const rhs_col = + new(ctx) ir_dereference_array(rhs_var, new(ctx) ir_constant(i)); + + /* If one matrix has columns that are smaller than the columns of the + * other matrix, wrap the column access of the larger with a swizzle + * so that the LHS and RHS of the assignment have the same size (and + * therefore have the same type). + * + * It would be perfectly valid to unconditionally generate the + * swizzles, this this will typically result in a more compact IR tree. + */ + ir_rvalue *rhs; + if (lhs->type->vector_elements != rhs_col->type->vector_elements) { + rhs = new(ctx) ir_swizzle(rhs_col, swiz, + lhs->type->vector_elements); + } else { + rhs = rhs_col; + } + + assert(lhs->type == rhs->type); + + ir_instruction *inst = + new(ctx) ir_assignment(lhs, rhs, NULL, write_mask); + instructions->push_tail(inst); + } + } else { + const unsigned cols = type->matrix_columns; + const unsigned rows = type->vector_elements; + unsigned col_idx = 0; + unsigned row_idx = 0; + + foreach_list (node, parameters) { + ir_rvalue *const rhs = (ir_rvalue *) node; + const unsigned components_remaining_this_column = rows - row_idx; + unsigned rhs_components = rhs->type->components(); + unsigned rhs_base = 0; + + /* Since the parameter might be used in the RHS of two assignments, + * generate a temporary and copy the paramter there. + */ + ir_variable *rhs_var = + new(ctx) ir_variable(rhs->type, "mat_ctor_vec", ir_var_temporary); + instructions->push_tail(rhs_var); + + ir_dereference *rhs_var_ref = + new(ctx) ir_dereference_variable(rhs_var); + ir_instruction *inst = new(ctx) ir_assignment(rhs_var_ref, rhs, NULL); + instructions->push_tail(inst); + + /* Assign the current parameter to as many components of the matrix + * as it will fill. + * + * NOTE: A single vector parameter can span two matrix columns. A + * single vec4, for example, can completely fill a mat2. + */ + if (rhs_components >= components_remaining_this_column) { + const unsigned count = MIN2(rhs_components, + components_remaining_this_column); + + rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var); + + ir_instruction *inst = assign_to_matrix_column(var, col_idx, + row_idx, + rhs_var_ref, 0, + count, ctx); + instructions->push_tail(inst); + + rhs_base = count; + + col_idx++; + row_idx = 0; + } + + /* If there is data left in the parameter and components left to be + * set in the destination, emit another assignment. It is possible + * that the assignment could be of a vec4 to the last element of the + * matrix. In this case col_idx==cols, but there is still data + * left in the source parameter. Obviously, don't emit an assignment + * to data outside the destination matrix. + */ + if ((col_idx < cols) && (rhs_base < rhs_components)) { + const unsigned count = rhs_components - rhs_base; + + rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var); + + ir_instruction *inst = assign_to_matrix_column(var, col_idx, + row_idx, + rhs_var_ref, + rhs_base, + count, ctx); + instructions->push_tail(inst); + + row_idx += count; + } + } + } + + return new(ctx) ir_dereference_variable(var); +} + + +ir_rvalue * +emit_inline_record_constructor(const glsl_type *type, + exec_list *instructions, + exec_list *parameters, + void *mem_ctx) +{ + ir_variable *const var = + new(mem_ctx) ir_variable(type, "record_ctor", ir_var_temporary); + ir_dereference_variable *const d = new(mem_ctx) ir_dereference_variable(var); + + instructions->push_tail(var); + + exec_node *node = parameters->head; + for (unsigned i = 0; i < type->length; i++) { + assert(!node->is_tail_sentinel()); + + ir_dereference *const lhs = + new(mem_ctx) ir_dereference_record(d->clone(mem_ctx, NULL), + type->fields.structure[i].name); + + ir_rvalue *const rhs = ((ir_instruction *) node)->as_rvalue(); + assert(rhs != NULL); + + ir_instruction *const assign = new(mem_ctx) ir_assignment(lhs, rhs, NULL); + + instructions->push_tail(assign); + node = node->next; + } + + return d; +} + + +ir_rvalue * +ast_function_expression::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + /* There are three sorts of function calls. + * + * 1. constructors - The first subexpression is an ast_type_specifier. + * 2. methods - Only the .length() method of array types. + * 3. functions - Calls to regular old functions. + * + * Method calls are actually detected when the ast_field_selection + * expression is handled. + */ + if (is_constructor()) { + const ast_type_specifier *type = (ast_type_specifier *) subexpressions[0]; + YYLTYPE loc = type->get_location(); + const char *name; + + const glsl_type *const constructor_type = type->glsl_type(& name, state); + + + /* Constructors for samplers are illegal. + */ + if (constructor_type->is_sampler()) { + _mesa_glsl_error(& loc, state, "cannot construct sampler type `%s'", + constructor_type->name); + return ir_call::get_error_instruction(ctx); + } + + if (constructor_type->is_array()) { + if (state->language_version <= 110) { + _mesa_glsl_error(& loc, state, + "array constructors forbidden in GLSL 1.10"); + return ir_call::get_error_instruction(ctx); + } + + return process_array_constructor(instructions, constructor_type, + & loc, &this->expressions, state); + } + + + /* There are two kinds of constructor call. Constructors for built-in + * language types, such as mat4 and vec2, are free form. The only + * requirement is that the parameters must provide enough values of the + * correct scalar type. Constructors for arrays and structures must + * have the exact number of parameters with matching types in the + * correct order. These constructors follow essentially the same type + * matching rules as functions. + */ + if (!constructor_type->is_numeric() && !constructor_type->is_boolean()) + return ir_call::get_error_instruction(ctx); + + /* Total number of components of the type being constructed. */ + const unsigned type_components = constructor_type->components(); + + /* Number of components from parameters that have actually been + * consumed. This is used to perform several kinds of error checking. + */ + unsigned components_used = 0; + + unsigned matrix_parameters = 0; + unsigned nonmatrix_parameters = 0; + exec_list actual_parameters; + + foreach_list (n, &this->expressions) { + ast_node *ast = exec_node_data(ast_node, n, link); + ir_rvalue *result = ast->hir(instructions, state)->as_rvalue(); + + /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec: + * + * "It is an error to provide extra arguments beyond this + * last used argument." + */ + if (components_used >= type_components) { + _mesa_glsl_error(& loc, state, "too many parameters to `%s' " + "constructor", + constructor_type->name); + return ir_call::get_error_instruction(ctx); + } + + if (!result->type->is_numeric() && !result->type->is_boolean()) { + _mesa_glsl_error(& loc, state, "cannot construct `%s' from a " + "non-numeric data type", + constructor_type->name); + return ir_call::get_error_instruction(ctx); + } + + /* Count the number of matrix and nonmatrix parameters. This + * is used below to enforce some of the constructor rules. + */ + if (result->type->is_matrix()) + matrix_parameters++; + else + nonmatrix_parameters++; + + actual_parameters.push_tail(result); + components_used += result->type->components(); + } + + /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec: + * + * "It is an error to construct matrices from other matrices. This + * is reserved for future use." + */ + if ((state->language_version <= 110) && (matrix_parameters > 0) + && constructor_type->is_matrix()) { + _mesa_glsl_error(& loc, state, "cannot construct `%s' from a " + "matrix in GLSL 1.10", + constructor_type->name); + return ir_call::get_error_instruction(ctx); + } + + /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec: + * + * "If a matrix argument is given to a matrix constructor, it is + * an error to have any other arguments." + */ + if ((matrix_parameters > 0) + && ((matrix_parameters + nonmatrix_parameters) > 1) + && constructor_type->is_matrix()) { + _mesa_glsl_error(& loc, state, "for matrix `%s' constructor, " + "matrix must be only parameter", + constructor_type->name); + return ir_call::get_error_instruction(ctx); + } + + /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec: + * + * "In these cases, there must be enough components provided in the + * arguments to provide an initializer for every component in the + * constructed value." + */ + if (components_used < type_components && components_used != 1 + && matrix_parameters == 0) { + _mesa_glsl_error(& loc, state, "too few components to construct " + "`%s'", + constructor_type->name); + return ir_call::get_error_instruction(ctx); + } + + /* Later, we cast each parameter to the same base type as the + * constructor. Since there are no non-floating point matrices, we + * need to break them up into a series of column vectors. + */ + if (constructor_type->base_type != GLSL_TYPE_FLOAT) { + foreach_list_safe(n, &actual_parameters) { + ir_rvalue *matrix = (ir_rvalue *) n; + + if (!matrix->type->is_matrix()) + continue; + + /* Create a temporary containing the matrix. */ + ir_variable *var = new(ctx) ir_variable(matrix->type, "matrix_tmp", + ir_var_temporary); + instructions->push_tail(var); + instructions->push_tail(new(ctx) ir_assignment(new(ctx) + ir_dereference_variable(var), matrix, NULL)); + var->constant_value = matrix->constant_expression_value(); + + /* Replace the matrix with dereferences of its columns. */ + for (int i = 0; i < matrix->type->matrix_columns; i++) { + matrix->insert_before(new (ctx) ir_dereference_array(var, + new(ctx) ir_constant(i))); + } + matrix->remove(); + } + } + + bool all_parameters_are_constant = true; + + /* Type cast each parameter and, if possible, fold constants.*/ + foreach_list_safe(n, &actual_parameters) { + ir_rvalue *ir = (ir_rvalue *) n; + + const glsl_type *desired_type = + glsl_type::get_instance(constructor_type->base_type, + ir->type->vector_elements, + ir->type->matrix_columns); + ir_rvalue *result = convert_component(ir, desired_type); + + /* Attempt to convert the parameter to a constant valued expression. + * After doing so, track whether or not all the parameters to the + * constructor are trivially constant valued expressions. + */ + ir_rvalue *const constant = result->constant_expression_value(); + + if (constant != NULL) + result = constant; + else + all_parameters_are_constant = false; + + if (result != ir) { + ir->replace_with(result); + } + } + + /* If all of the parameters are trivially constant, create a + * constant representing the complete collection of parameters. + */ + if (all_parameters_are_constant) { + return new(ctx) ir_constant(constructor_type, &actual_parameters); + } else if (constructor_type->is_scalar()) { + return dereference_component((ir_rvalue *) actual_parameters.head, + 0); + } else if (constructor_type->is_vector()) { + return emit_inline_vector_constructor(constructor_type, + instructions, + &actual_parameters, + ctx); + } else { + assert(constructor_type->is_matrix()); + return emit_inline_matrix_constructor(constructor_type, + instructions, + &actual_parameters, + ctx); + } + } else { + const ast_expression *id = subexpressions[0]; + YYLTYPE loc = id->get_location(); + exec_list actual_parameters; + + process_parameters(instructions, &actual_parameters, &this->expressions, + state); + + const glsl_type *const type = + state->symbols->get_type(id->primary_expression.identifier); + + if ((type != NULL) && type->is_record()) { + exec_node *node = actual_parameters.head; + for (unsigned i = 0; i < type->length; i++) { + ir_rvalue *ir = (ir_rvalue *) node; + + if (node->is_tail_sentinel()) { + _mesa_glsl_error(&loc, state, + "insufficient parameters to constructor " + "for `%s'", + type->name); + return ir_call::get_error_instruction(ctx); + } + + if (apply_implicit_conversion(type->fields.structure[i].type, ir, + state)) { + node->replace_with(ir); + } else { + _mesa_glsl_error(&loc, state, + "parameter type mismatch in constructor " + "for `%s.%s' (%s vs %s)", + type->name, + type->fields.structure[i].name, + ir->type->name, + type->fields.structure[i].type->name); + return ir_call::get_error_instruction(ctx);; + } + + node = node->next; + } + + if (!node->is_tail_sentinel()) { + _mesa_glsl_error(&loc, state, "too many parameters in constructor " + "for `%s'", type->name); + return ir_call::get_error_instruction(ctx); + } + + ir_rvalue *const constant = + constant_record_constructor(type, &actual_parameters, state); + + return (constant != NULL) + ? constant + : emit_inline_record_constructor(type, instructions, + &actual_parameters, state); + } + + return match_function_by_name(instructions, + id->primary_expression.identifier, & loc, + &actual_parameters, state); + } + + return ir_call::get_error_instruction(ctx); +} diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp new file mode 100644 index 0000000000..762f802c2b --- /dev/null +++ b/src/glsl/ast_to_hir.cpp @@ -0,0 +1,2751 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ast_to_hir.c + * Convert abstract syntax to to high-level intermediate reprensentation (HIR). + * + * During the conversion to HIR, the majority of the symantic checking is + * preformed on the program. This includes: + * + * * Symbol table management + * * Type checking + * * Function binding + * + * The majority of this work could be done during parsing, and the parser could + * probably generate HIR directly. However, this results in frequent changes + * to the parser code. Since we do not assume that every system this complier + * is built on will have Flex and Bison installed, we have to store the code + * generated by these tools in our version control system. In other parts of + * the system we've seen problems where a parser was changed but the generated + * code was not committed, merge conflicts where created because two developers + * had slightly different versions of Bison installed, etc. + * + * I have also noticed that running Bison generated parsers in GDB is very + * irritating. When you get a segfault on '$$ = $1->foo', you can't very + * well 'print $1' in GDB. + * + * As a result, my preference is to put as little C code as possible in the + * parser (and lexer) sources. + */ + +#include "main/core.h" /* for struct gl_extensions */ +#include "glsl_symbol_table.h" +#include "glsl_parser_extras.h" +#include "ast.h" +#include "glsl_types.h" +#include "ir.h" + +void +_mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) +{ + _mesa_glsl_initialize_variables(instructions, state); + _mesa_glsl_initialize_functions(instructions, state); + + state->current_function = NULL; + + /* Section 4.2 of the GLSL 1.20 specification states: + * "The built-in functions are scoped in a scope outside the global scope + * users declare global variables in. That is, a shader's global scope, + * available for user-defined functions and global variables, is nested + * inside the scope containing the built-in functions." + * + * Since built-in functions like ftransform() access built-in variables, + * it follows that those must be in the outer scope as well. + * + * We push scope here to create this nesting effect...but don't pop. + * This way, a shader's globals are still in the symbol table for use + * by the linker. + */ + state->symbols->push_scope(); + + foreach_list_typed (ast_node, ast, link, & state->translation_unit) + ast->hir(instructions, state); +} + + +/** + * If a conversion is available, convert one operand to a different type + * + * The \c from \c ir_rvalue is converted "in place". + * + * \param to Type that the operand it to be converted to + * \param from Operand that is being converted + * \param state GLSL compiler state + * + * \return + * If a conversion is possible (or unnecessary), \c true is returned. + * Otherwise \c false is returned. + */ +bool +apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + if (to->base_type == from->type->base_type) + return true; + + /* This conversion was added in GLSL 1.20. If the compilation mode is + * GLSL 1.10, the conversion is skipped. + */ + if (state->language_version < 120) + return false; + + /* From page 27 (page 33 of the PDF) of the GLSL 1.50 spec: + * + * "There are no implicit array or structure conversions. For + * example, an array of int cannot be implicitly converted to an + * array of float. There are no implicit conversions between + * signed and unsigned integers." + */ + /* FINISHME: The above comment is partially a lie. There is int/uint + * FINISHME: conversion for immediate constants. + */ + if (!to->is_float() || !from->type->is_numeric()) + return false; + + /* Convert to a floating point type with the same number of components + * as the original type - i.e. int to float, not int to vec4. + */ + to = glsl_type::get_instance(GLSL_TYPE_FLOAT, from->type->vector_elements, + from->type->matrix_columns); + + switch (from->type->base_type) { + case GLSL_TYPE_INT: + from = new(ctx) ir_expression(ir_unop_i2f, to, from, NULL); + break; + case GLSL_TYPE_UINT: + from = new(ctx) ir_expression(ir_unop_u2f, to, from, NULL); + break; + case GLSL_TYPE_BOOL: + from = new(ctx) ir_expression(ir_unop_b2f, to, from, NULL); + break; + default: + assert(0); + } + + return true; +} + + +static const struct glsl_type * +arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, + bool multiply, + struct _mesa_glsl_parse_state *state, YYLTYPE *loc) +{ + const glsl_type *type_a = value_a->type; + const glsl_type *type_b = value_b->type; + + /* From GLSL 1.50 spec, page 56: + * + * "The arithmetic binary operators add (+), subtract (-), + * multiply (*), and divide (/) operate on integer and + * floating-point scalars, vectors, and matrices." + */ + if (!type_a->is_numeric() || !type_b->is_numeric()) { + _mesa_glsl_error(loc, state, + "Operands to arithmetic operators must be numeric"); + return glsl_type::error_type; + } + + + /* "If one operand is floating-point based and the other is + * not, then the conversions from Section 4.1.10 "Implicit + * Conversions" are applied to the non-floating-point-based operand." + */ + if (!apply_implicit_conversion(type_a, value_b, state) + && !apply_implicit_conversion(type_b, value_a, state)) { + _mesa_glsl_error(loc, state, + "Could not implicitly convert operands to " + "arithmetic operator"); + return glsl_type::error_type; + } + type_a = value_a->type; + type_b = value_b->type; + + /* "If the operands are integer types, they must both be signed or + * both be unsigned." + * + * From this rule and the preceeding conversion it can be inferred that + * both types must be GLSL_TYPE_FLOAT, or GLSL_TYPE_UINT, or GLSL_TYPE_INT. + * The is_numeric check above already filtered out the case where either + * type is not one of these, so now the base types need only be tested for + * equality. + */ + if (type_a->base_type != type_b->base_type) { + _mesa_glsl_error(loc, state, + "base type mismatch for arithmetic operator"); + return glsl_type::error_type; + } + + /* "All arithmetic binary operators result in the same fundamental type + * (signed integer, unsigned integer, or floating-point) as the + * operands they operate on, after operand type conversion. After + * conversion, the following cases are valid + * + * * The two operands are scalars. In this case the operation is + * applied, resulting in a scalar." + */ + if (type_a->is_scalar() && type_b->is_scalar()) + return type_a; + + /* "* One operand is a scalar, and the other is a vector or matrix. + * In this case, the scalar operation is applied independently to each + * component of the vector or matrix, resulting in the same size + * vector or matrix." + */ + if (type_a->is_scalar()) { + if (!type_b->is_scalar()) + return type_b; + } else if (type_b->is_scalar()) { + return type_a; + } + + /* All of the combinations of <scalar, scalar>, <vector, scalar>, + * <scalar, vector>, <scalar, matrix>, and <matrix, scalar> have been + * handled. + */ + assert(!type_a->is_scalar()); + assert(!type_b->is_scalar()); + + /* "* The two operands are vectors of the same size. In this case, the + * operation is done component-wise resulting in the same size + * vector." + */ + if (type_a->is_vector() && type_b->is_vector()) { + if (type_a == type_b) { + return type_a; + } else { + _mesa_glsl_error(loc, state, + "vector size mismatch for arithmetic operator"); + return glsl_type::error_type; + } + } + + /* All of the combinations of <scalar, scalar>, <vector, scalar>, + * <scalar, vector>, <scalar, matrix>, <matrix, scalar>, and + * <vector, vector> have been handled. At least one of the operands must + * be matrix. Further, since there are no integer matrix types, the base + * type of both operands must be float. + */ + assert(type_a->is_matrix() || type_b->is_matrix()); + assert(type_a->base_type == GLSL_TYPE_FLOAT); + assert(type_b->base_type == GLSL_TYPE_FLOAT); + + /* "* The operator is add (+), subtract (-), or divide (/), and the + * operands are matrices with the same number of rows and the same + * number of columns. In this case, the operation is done component- + * wise resulting in the same size matrix." + * * The operator is multiply (*), where both operands are matrices or + * one operand is a vector and the other a matrix. A right vector + * operand is treated as a column vector and a left vector operand as a + * row vector. In all these cases, it is required that the number of + * columns of the left operand is equal to the number of rows of the + * right operand. Then, the multiply (*) operation does a linear + * algebraic multiply, yielding an object that has the same number of + * rows as the left operand and the same number of columns as the right + * operand. Section 5.10 "Vector and Matrix Operations" explains in + * more detail how vectors and matrices are operated on." + */ + if (! multiply) { + if (type_a == type_b) + return type_a; + } else { + if (type_a->is_matrix() && type_b->is_matrix()) { + /* Matrix multiply. The columns of A must match the rows of B. Given + * the other previously tested constraints, this means the vector type + * of a row from A must be the same as the vector type of a column from + * B. + */ + if (type_a->row_type() == type_b->column_type()) { + /* The resulting matrix has the number of columns of matrix B and + * the number of rows of matrix A. We get the row count of A by + * looking at the size of a vector that makes up a column. The + * transpose (size of a row) is done for B. + */ + const glsl_type *const type = + glsl_type::get_instance(type_a->base_type, + type_a->column_type()->vector_elements, + type_b->row_type()->vector_elements); + assert(type != glsl_type::error_type); + + return type; + } + } else if (type_a->is_matrix()) { + /* A is a matrix and B is a column vector. Columns of A must match + * rows of B. Given the other previously tested constraints, this + * means the vector type of a row from A must be the same as the + * vector the type of B. + */ + if (type_a->row_type() == type_b) { + /* The resulting vector has a number of elements equal to + * the number of rows of matrix A. */ + const glsl_type *const type = + glsl_type::get_instance(type_a->base_type, + type_a->column_type()->vector_elements, + 1); + assert(type != glsl_type::error_type); + + return type; + } + } else { + assert(type_b->is_matrix()); + + /* A is a row vector and B is a matrix. Columns of A must match rows + * of B. Given the other previously tested constraints, this means + * the type of A must be the same as the vector type of a column from + * B. + */ + if (type_a == type_b->column_type()) { + /* The resulting vector has a number of elements equal to + * the number of columns of matrix B. */ + const glsl_type *const type = + glsl_type::get_instance(type_a->base_type, + type_b->row_type()->vector_elements, + 1); + assert(type != glsl_type::error_type); + + return type; + } + } + + _mesa_glsl_error(loc, state, "size mismatch for matrix multiplication"); + return glsl_type::error_type; + } + + + /* "All other cases are illegal." + */ + _mesa_glsl_error(loc, state, "type mismatch"); + return glsl_type::error_type; +} + + +static const struct glsl_type * +unary_arithmetic_result_type(const struct glsl_type *type, + struct _mesa_glsl_parse_state *state, YYLTYPE *loc) +{ + /* From GLSL 1.50 spec, page 57: + * + * "The arithmetic unary operators negate (-), post- and pre-increment + * and decrement (-- and ++) operate on integer or floating-point + * values (including vectors and matrices). All unary operators work + * component-wise on their operands. These result with the same type + * they operated on." + */ + if (!type->is_numeric()) { + _mesa_glsl_error(loc, state, + "Operands to arithmetic operators must be numeric"); + return glsl_type::error_type; + } + + return type; +} + + +static const struct glsl_type * +modulus_result_type(const struct glsl_type *type_a, + const struct glsl_type *type_b, + struct _mesa_glsl_parse_state *state, YYLTYPE *loc) +{ + /* From GLSL 1.50 spec, page 56: + * "The operator modulus (%) operates on signed or unsigned integers or + * integer vectors. The operand types must both be signed or both be + * unsigned." + */ + if (!type_a->is_integer() || !type_b->is_integer() + || (type_a->base_type != type_b->base_type)) { + _mesa_glsl_error(loc, state, "type mismatch"); + return glsl_type::error_type; + } + + /* "The operands cannot be vectors of differing size. If one operand is + * a scalar and the other vector, then the scalar is applied component- + * wise to the vector, resulting in the same type as the vector. If both + * are vectors of the same size, the result is computed component-wise." + */ + if (type_a->is_vector()) { + if (!type_b->is_vector() + || (type_a->vector_elements == type_b->vector_elements)) + return type_a; + } else + return type_b; + + /* "The operator modulus (%) is not defined for any other data types + * (non-integer types)." + */ + _mesa_glsl_error(loc, state, "type mismatch"); + return glsl_type::error_type; +} + + +static const struct glsl_type * +relational_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b, + struct _mesa_glsl_parse_state *state, YYLTYPE *loc) +{ + const glsl_type *type_a = value_a->type; + const glsl_type *type_b = value_b->type; + + /* From GLSL 1.50 spec, page 56: + * "The relational operators greater than (>), less than (<), greater + * than or equal (>=), and less than or equal (<=) operate only on + * scalar integer and scalar floating-point expressions." + */ + if (!type_a->is_numeric() + || !type_b->is_numeric() + || !type_a->is_scalar() + || !type_b->is_scalar()) { + _mesa_glsl_error(loc, state, + "Operands to relational operators must be scalar and " + "numeric"); + return glsl_type::error_type; + } + + /* "Either the operands' types must match, or the conversions from + * Section 4.1.10 "Implicit Conversions" will be applied to the integer + * operand, after which the types must match." + */ + if (!apply_implicit_conversion(type_a, value_b, state) + && !apply_implicit_conversion(type_b, value_a, state)) { + _mesa_glsl_error(loc, state, + "Could not implicitly convert operands to " + "relational operator"); + return glsl_type::error_type; + } + type_a = value_a->type; + type_b = value_b->type; + + if (type_a->base_type != type_b->base_type) { + _mesa_glsl_error(loc, state, "base type mismatch"); + return glsl_type::error_type; + } + + /* "The result is scalar Boolean." + */ + return glsl_type::bool_type; +} + + +/** + * Validates that a value can be assigned to a location with a specified type + * + * Validates that \c rhs can be assigned to some location. If the types are + * not an exact match but an automatic conversion is possible, \c rhs will be + * converted. + * + * \return + * \c NULL if \c rhs cannot be assigned to a location with type \c lhs_type. + * Otherwise the actual RHS to be assigned will be returned. This may be + * \c rhs, or it may be \c rhs after some type conversion. + * + * \note + * In addition to being used for assignments, this function is used to + * type-check return values. + */ +ir_rvalue * +validate_assignment(struct _mesa_glsl_parse_state *state, + const glsl_type *lhs_type, ir_rvalue *rhs) +{ + const glsl_type *rhs_type = rhs->type; + + /* If there is already some error in the RHS, just return it. Anything + * else will lead to an avalanche of error message back to the user. + */ + if (rhs_type->is_error()) + return rhs; + + /* If the types are identical, the assignment can trivially proceed. + */ + if (rhs_type == lhs_type) + return rhs; + + /* If the array element types are the same and the size of the LHS is zero, + * the assignment is okay. + * + * Note: Whole-array assignments are not permitted in GLSL 1.10, but this + * is handled by ir_dereference::is_lvalue. + */ + if (lhs_type->is_array() && rhs->type->is_array() + && (lhs_type->element_type() == rhs->type->element_type()) + && (lhs_type->array_size() == 0)) { + return rhs; + } + + /* Check for implicit conversion in GLSL 1.20 */ + if (apply_implicit_conversion(lhs_type, rhs, state)) { + rhs_type = rhs->type; + if (rhs_type == lhs_type) + return rhs; + } + + return NULL; +} + +ir_rvalue * +do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, + ir_rvalue *lhs, ir_rvalue *rhs, + YYLTYPE lhs_loc) +{ + void *ctx = state; + bool error_emitted = (lhs->type->is_error() || rhs->type->is_error()); + + if (!error_emitted) { + if (!lhs->is_lvalue()) { + _mesa_glsl_error(& lhs_loc, state, "non-lvalue in assignment"); + error_emitted = true; + } + } + + ir_rvalue *new_rhs = validate_assignment(state, lhs->type, rhs); + if (new_rhs == NULL) { + _mesa_glsl_error(& lhs_loc, state, "type mismatch"); + } else { + rhs = new_rhs; + + /* If the LHS array was not declared with a size, it takes it size from + * the RHS. If the LHS is an l-value and a whole array, it must be a + * dereference of a variable. Any other case would require that the LHS + * is either not an l-value or not a whole array. + */ + if (lhs->type->array_size() == 0) { + ir_dereference *const d = lhs->as_dereference(); + + assert(d != NULL); + + ir_variable *const var = d->variable_referenced(); + + assert(var != NULL); + + if (var->max_array_access >= unsigned(rhs->type->array_size())) { + /* FINISHME: This should actually log the location of the RHS. */ + _mesa_glsl_error(& lhs_loc, state, "array size must be > %u due to " + "previous access", + var->max_array_access); + } + + var->type = glsl_type::get_array_instance(lhs->type->element_type(), + rhs->type->array_size()); + d->type = var->type; + } + } + + /* Most callers of do_assignment (assign, add_assign, pre_inc/dec, + * but not post_inc) need the converted assigned value as an rvalue + * to handle things like: + * + * i = j += 1; + * + * So we always just store the computed value being assigned to a + * temporary and return a deref of that temporary. If the rvalue + * ends up not being used, the temp will get copy-propagated out. + */ + ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp", + ir_var_temporary); + ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var); + instructions->push_tail(var); + instructions->push_tail(new(ctx) ir_assignment(deref_var, + rhs, + NULL)); + deref_var = new(ctx) ir_dereference_variable(var); + + if (!error_emitted) + instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var, NULL)); + + return new(ctx) ir_dereference_variable(var); +} + +static ir_rvalue * +get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue) +{ + void *ctx = talloc_parent(lvalue); + ir_variable *var; + + var = new(ctx) ir_variable(lvalue->type, "_post_incdec_tmp", + ir_var_temporary); + instructions->push_tail(var); + var->mode = ir_var_auto; + + instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var), + lvalue, NULL)); + + /* Once we've created this temporary, mark it read only so it's no + * longer considered an lvalue. + */ + var->read_only = true; + + return new(ctx) ir_dereference_variable(var); +} + + +ir_rvalue * +ast_node::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + (void) instructions; + (void) state; + + return NULL; +} + + +ir_rvalue * +ast_expression::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + static const int operations[AST_NUM_OPERATORS] = { + -1, /* ast_assign doesn't convert to ir_expression. */ + -1, /* ast_plus doesn't convert to ir_expression. */ + ir_unop_neg, + ir_binop_add, + ir_binop_sub, + ir_binop_mul, + ir_binop_div, + ir_binop_mod, + ir_binop_lshift, + ir_binop_rshift, + ir_binop_less, + ir_binop_greater, + ir_binop_lequal, + ir_binop_gequal, + ir_binop_equal, + ir_binop_nequal, + ir_binop_bit_and, + ir_binop_bit_xor, + ir_binop_bit_or, + ir_unop_bit_not, + ir_binop_logic_and, + ir_binop_logic_xor, + ir_binop_logic_or, + ir_unop_logic_not, + + /* Note: The following block of expression types actually convert + * to multiple IR instructions. + */ + ir_binop_mul, /* ast_mul_assign */ + ir_binop_div, /* ast_div_assign */ + ir_binop_mod, /* ast_mod_assign */ + ir_binop_add, /* ast_add_assign */ + ir_binop_sub, /* ast_sub_assign */ + ir_binop_lshift, /* ast_ls_assign */ + ir_binop_rshift, /* ast_rs_assign */ + ir_binop_bit_and, /* ast_and_assign */ + ir_binop_bit_xor, /* ast_xor_assign */ + ir_binop_bit_or, /* ast_or_assign */ + + -1, /* ast_conditional doesn't convert to ir_expression. */ + ir_binop_add, /* ast_pre_inc. */ + ir_binop_sub, /* ast_pre_dec. */ + ir_binop_add, /* ast_post_inc. */ + ir_binop_sub, /* ast_post_dec. */ + -1, /* ast_field_selection doesn't conv to ir_expression. */ + -1, /* ast_array_index doesn't convert to ir_expression. */ + -1, /* ast_function_call doesn't conv to ir_expression. */ + -1, /* ast_identifier doesn't convert to ir_expression. */ + -1, /* ast_int_constant doesn't convert to ir_expression. */ + -1, /* ast_uint_constant doesn't conv to ir_expression. */ + -1, /* ast_float_constant doesn't conv to ir_expression. */ + -1, /* ast_bool_constant doesn't conv to ir_expression. */ + -1, /* ast_sequence doesn't convert to ir_expression. */ + }; + ir_rvalue *result = NULL; + ir_rvalue *op[3]; + const struct glsl_type *type = glsl_type::error_type; + bool error_emitted = false; + YYLTYPE loc; + + loc = this->get_location(); + + switch (this->oper) { + case ast_assign: { + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + result = do_assignment(instructions, state, op[0], op[1], + this->subexpressions[0]->get_location()); + error_emitted = result->type->is_error(); + type = result->type; + break; + } + + case ast_plus: + op[0] = this->subexpressions[0]->hir(instructions, state); + + type = unary_arithmetic_result_type(op[0]->type, state, & loc); + + error_emitted = type->is_error(); + + result = op[0]; + break; + + case ast_neg: + op[0] = this->subexpressions[0]->hir(instructions, state); + + type = unary_arithmetic_result_type(op[0]->type, state, & loc); + + error_emitted = type->is_error(); + + result = new(ctx) ir_expression(operations[this->oper], type, + op[0], NULL); + break; + + case ast_add: + case ast_sub: + case ast_mul: + case ast_div: + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + type = arithmetic_result_type(op[0], op[1], + (this->oper == ast_mul), + state, & loc); + error_emitted = type->is_error(); + + result = new(ctx) ir_expression(operations[this->oper], type, + op[0], op[1]); + break; + + case ast_mod: + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + type = modulus_result_type(op[0]->type, op[1]->type, state, & loc); + + assert(operations[this->oper] == ir_binop_mod); + + result = new(ctx) ir_expression(operations[this->oper], type, + op[0], op[1]); + error_emitted = type->is_error(); + break; + + case ast_lshift: + case ast_rshift: + _mesa_glsl_error(& loc, state, "FINISHME: implement bit-shift operators"); + error_emitted = true; + break; + + case ast_less: + case ast_greater: + case ast_lequal: + case ast_gequal: + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + type = relational_result_type(op[0], op[1], state, & loc); + + /* The relational operators must either generate an error or result + * in a scalar boolean. See page 57 of the GLSL 1.50 spec. + */ + assert(type->is_error() + || ((type->base_type == GLSL_TYPE_BOOL) + && type->is_scalar())); + + result = new(ctx) ir_expression(operations[this->oper], type, + op[0], op[1]); + error_emitted = type->is_error(); + break; + + case ast_nequal: + case ast_equal: + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + /* From page 58 (page 64 of the PDF) of the GLSL 1.50 spec: + * + * "The equality operators equal (==), and not equal (!=) + * operate on all types. They result in a scalar Boolean. If + * the operand types do not match, then there must be a + * conversion from Section 4.1.10 "Implicit Conversions" + * applied to one operand that can make them match, in which + * case this conversion is done." + */ + if ((!apply_implicit_conversion(op[0]->type, op[1], state) + && !apply_implicit_conversion(op[1]->type, op[0], state)) + || (op[0]->type != op[1]->type)) { + _mesa_glsl_error(& loc, state, "operands of `%s' must have the same " + "type", (this->oper == ast_equal) ? "==" : "!="); + error_emitted = true; + } else if ((state->language_version <= 110) + && (op[0]->type->is_array() || op[1]->type->is_array())) { + _mesa_glsl_error(& loc, state, "array comparisons forbidden in " + "GLSL 1.10"); + error_emitted = true; + } + + result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type, + op[0], op[1]); + type = glsl_type::bool_type; + + assert(result->type == glsl_type::bool_type); + break; + + case ast_bit_and: + case ast_bit_xor: + case ast_bit_or: + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + if (state->language_version < 130) { + _mesa_glsl_error(&loc, state, "bit-wise operations require GLSL 1.30"); + error_emitted = true; + } + + if (!op[0]->type->is_integer()) { + _mesa_glsl_error(&loc, state, "LHS of `%s' must be an integer", + operator_string(this->oper)); + error_emitted = true; + } + + if (!op[1]->type->is_integer()) { + _mesa_glsl_error(&loc, state, "RHS of `%s' must be an integer", + operator_string(this->oper)); + error_emitted = true; + } + + if (op[0]->type->base_type != op[1]->type->base_type) { + _mesa_glsl_error(&loc, state, "operands of `%s' must have the same " + "base type", operator_string(this->oper)); + error_emitted = true; + } + + if (op[0]->type->is_vector() && op[1]->type->is_vector() + && op[0]->type->vector_elements != op[1]->type->vector_elements) { + _mesa_glsl_error(&loc, state, "operands of `%s' cannot be vectors of " + "different sizes", operator_string(this->oper)); + error_emitted = true; + } + + type = op[0]->type->is_scalar() ? op[1]->type : op[0]->type; + result = new(ctx) ir_expression(operations[this->oper], type, + op[0], op[1]); + error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); + break; + + case ast_bit_not: + op[0] = this->subexpressions[0]->hir(instructions, state); + + if (state->language_version < 130) { + _mesa_glsl_error(&loc, state, "bit-wise operations require GLSL 1.30"); + error_emitted = true; + } + + if (!op[0]->type->is_integer()) { + _mesa_glsl_error(&loc, state, "operand of `~' must be an integer"); + error_emitted = true; + } + + type = op[0]->type; + result = new(ctx) ir_expression(ir_unop_bit_not, type, op[0], NULL); + break; + + case ast_logic_and: { + op[0] = this->subexpressions[0]->hir(instructions, state); + + if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { + YYLTYPE loc = this->subexpressions[0]->get_location(); + + _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean", + operator_string(this->oper)); + error_emitted = true; + } + + ir_constant *op0_const = op[0]->constant_expression_value(); + if (op0_const) { + if (op0_const->value.b[0]) { + op[1] = this->subexpressions[1]->hir(instructions, state); + + if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { + YYLTYPE loc = this->subexpressions[1]->get_location(); + + _mesa_glsl_error(& loc, state, + "RHS of `%s' must be scalar boolean", + operator_string(this->oper)); + error_emitted = true; + } + result = op[1]; + } else { + result = op0_const; + } + type = glsl_type::bool_type; + } else { + ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type, + "and_tmp", + ir_var_temporary); + instructions->push_tail(tmp); + + ir_if *const stmt = new(ctx) ir_if(op[0]); + instructions->push_tail(stmt); + + op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state); + + if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { + YYLTYPE loc = this->subexpressions[1]->get_location(); + + _mesa_glsl_error(& loc, state, + "RHS of `%s' must be scalar boolean", + operator_string(this->oper)); + error_emitted = true; + } + + ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp); + ir_assignment *const then_assign = + new(ctx) ir_assignment(then_deref, op[1], NULL); + stmt->then_instructions.push_tail(then_assign); + + ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp); + ir_assignment *const else_assign = + new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false), NULL); + stmt->else_instructions.push_tail(else_assign); + + result = new(ctx) ir_dereference_variable(tmp); + type = tmp->type; + } + break; + } + + case ast_logic_or: { + op[0] = this->subexpressions[0]->hir(instructions, state); + + if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { + YYLTYPE loc = this->subexpressions[0]->get_location(); + + _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean", + operator_string(this->oper)); + error_emitted = true; + } + + ir_constant *op0_const = op[0]->constant_expression_value(); + if (op0_const) { + if (op0_const->value.b[0]) { + result = op0_const; + } else { + op[1] = this->subexpressions[1]->hir(instructions, state); + + if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { + YYLTYPE loc = this->subexpressions[1]->get_location(); + + _mesa_glsl_error(& loc, state, + "RHS of `%s' must be scalar boolean", + operator_string(this->oper)); + error_emitted = true; + } + result = op[1]; + } + type = glsl_type::bool_type; + } else { + ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type, + "or_tmp", + ir_var_temporary); + instructions->push_tail(tmp); + + ir_if *const stmt = new(ctx) ir_if(op[0]); + instructions->push_tail(stmt); + + op[1] = this->subexpressions[1]->hir(&stmt->else_instructions, state); + + if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { + YYLTYPE loc = this->subexpressions[1]->get_location(); + + _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean", + operator_string(this->oper)); + error_emitted = true; + } + + ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp); + ir_assignment *const then_assign = + new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true), NULL); + stmt->then_instructions.push_tail(then_assign); + + ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp); + ir_assignment *const else_assign = + new(ctx) ir_assignment(else_deref, op[1], NULL); + stmt->else_instructions.push_tail(else_assign); + + result = new(ctx) ir_dereference_variable(tmp); + type = tmp->type; + } + break; + } + + case ast_logic_xor: + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + + result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type, + op[0], op[1]); + type = glsl_type::bool_type; + break; + + case ast_logic_not: + op[0] = this->subexpressions[0]->hir(instructions, state); + + if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { + YYLTYPE loc = this->subexpressions[0]->get_location(); + + _mesa_glsl_error(& loc, state, + "operand of `!' must be scalar boolean"); + error_emitted = true; + } + + result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type, + op[0], NULL); + type = glsl_type::bool_type; + break; + + case ast_mul_assign: + case ast_div_assign: + case ast_add_assign: + case ast_sub_assign: { + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + type = arithmetic_result_type(op[0], op[1], + (this->oper == ast_mul_assign), + state, & loc); + + ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type, + op[0], op[1]); + + result = do_assignment(instructions, state, + op[0]->clone(ctx, NULL), temp_rhs, + this->subexpressions[0]->get_location()); + type = result->type; + error_emitted = (op[0]->type->is_error()); + + /* GLSL 1.10 does not allow array assignment. However, we don't have to + * explicitly test for this because none of the binary expression + * operators allow array operands either. + */ + + break; + } + + case ast_mod_assign: { + op[0] = this->subexpressions[0]->hir(instructions, state); + op[1] = this->subexpressions[1]->hir(instructions, state); + + type = modulus_result_type(op[0]->type, op[1]->type, state, & loc); + + assert(operations[this->oper] == ir_binop_mod); + + ir_rvalue *temp_rhs; + temp_rhs = new(ctx) ir_expression(operations[this->oper], type, + op[0], op[1]); + + result = do_assignment(instructions, state, + op[0]->clone(ctx, NULL), temp_rhs, + this->subexpressions[0]->get_location()); + type = result->type; + error_emitted = type->is_error(); + break; + } + + case ast_ls_assign: + case ast_rs_assign: + _mesa_glsl_error(& loc, state, + "FINISHME: implement bit-shift assignment operators"); + error_emitted = true; + break; + + case ast_and_assign: + case ast_xor_assign: + case ast_or_assign: + _mesa_glsl_error(& loc, state, + "FINISHME: implement logic assignment operators"); + error_emitted = true; + break; + + case ast_conditional: { + op[0] = this->subexpressions[0]->hir(instructions, state); + + /* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec: + * + * "The ternary selection operator (?:). It operates on three + * expressions (exp1 ? exp2 : exp3). This operator evaluates the + * first expression, which must result in a scalar Boolean." + */ + if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { + YYLTYPE loc = this->subexpressions[0]->get_location(); + + _mesa_glsl_error(& loc, state, "?: condition must be scalar boolean"); + error_emitted = true; + } + + /* The :? operator is implemented by generating an anonymous temporary + * followed by an if-statement. The last instruction in each branch of + * the if-statement assigns a value to the anonymous temporary. This + * temporary is the r-value of the expression. + */ + exec_list then_instructions; + exec_list else_instructions; + + op[1] = this->subexpressions[1]->hir(&then_instructions, state); + op[2] = this->subexpressions[2]->hir(&else_instructions, state); + + /* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec: + * + * "The second and third expressions can be any type, as + * long their types match, or there is a conversion in + * Section 4.1.10 "Implicit Conversions" that can be applied + * to one of the expressions to make their types match. This + * resulting matching type is the type of the entire + * expression." + */ + if ((!apply_implicit_conversion(op[1]->type, op[2], state) + && !apply_implicit_conversion(op[2]->type, op[1], state)) + || (op[1]->type != op[2]->type)) { + YYLTYPE loc = this->subexpressions[1]->get_location(); + + _mesa_glsl_error(& loc, state, "Second and third operands of ?: " + "operator must have matching types."); + error_emitted = true; + type = glsl_type::error_type; + } else { + type = op[1]->type; + } + + ir_constant *cond_val = op[0]->constant_expression_value(); + ir_constant *then_val = op[1]->constant_expression_value(); + ir_constant *else_val = op[2]->constant_expression_value(); + + if (then_instructions.is_empty() + && else_instructions.is_empty() + && (cond_val != NULL) && (then_val != NULL) && (else_val != NULL)) { + result = (cond_val->value.b[0]) ? then_val : else_val; + } else { + ir_variable *const tmp = + new(ctx) ir_variable(type, "conditional_tmp", ir_var_temporary); + instructions->push_tail(tmp); + + ir_if *const stmt = new(ctx) ir_if(op[0]); + instructions->push_tail(stmt); + + then_instructions.move_nodes_to(& stmt->then_instructions); + ir_dereference *const then_deref = + new(ctx) ir_dereference_variable(tmp); + ir_assignment *const then_assign = + new(ctx) ir_assignment(then_deref, op[1], NULL); + stmt->then_instructions.push_tail(then_assign); + + else_instructions.move_nodes_to(& stmt->else_instructions); + ir_dereference *const else_deref = + new(ctx) ir_dereference_variable(tmp); + ir_assignment *const else_assign = + new(ctx) ir_assignment(else_deref, op[2], NULL); + stmt->else_instructions.push_tail(else_assign); + + result = new(ctx) ir_dereference_variable(tmp); + } + break; + } + + case ast_pre_inc: + case ast_pre_dec: { + op[0] = this->subexpressions[0]->hir(instructions, state); + if (op[0]->type->base_type == GLSL_TYPE_FLOAT) + op[1] = new(ctx) ir_constant(1.0f); + else + op[1] = new(ctx) ir_constant(1); + + type = arithmetic_result_type(op[0], op[1], false, state, & loc); + + ir_rvalue *temp_rhs; + temp_rhs = new(ctx) ir_expression(operations[this->oper], type, + op[0], op[1]); + + result = do_assignment(instructions, state, + op[0]->clone(ctx, NULL), temp_rhs, + this->subexpressions[0]->get_location()); + type = result->type; + error_emitted = op[0]->type->is_error(); + break; + } + + case ast_post_inc: + case ast_post_dec: { + op[0] = this->subexpressions[0]->hir(instructions, state); + if (op[0]->type->base_type == GLSL_TYPE_FLOAT) + op[1] = new(ctx) ir_constant(1.0f); + else + op[1] = new(ctx) ir_constant(1); + + error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); + + type = arithmetic_result_type(op[0], op[1], false, state, & loc); + + ir_rvalue *temp_rhs; + temp_rhs = new(ctx) ir_expression(operations[this->oper], type, + op[0], op[1]); + + /* Get a temporary of a copy of the lvalue before it's modified. + * This may get thrown away later. + */ + result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL)); + + (void)do_assignment(instructions, state, + op[0]->clone(ctx, NULL), temp_rhs, + this->subexpressions[0]->get_location()); + + type = result->type; + error_emitted = op[0]->type->is_error(); + break; + } + + case ast_field_selection: + result = _mesa_ast_field_selection_to_hir(this, instructions, state); + type = result->type; + break; + + case ast_array_index: { + YYLTYPE index_loc = subexpressions[1]->get_location(); + + op[0] = subexpressions[0]->hir(instructions, state); + op[1] = subexpressions[1]->hir(instructions, state); + + error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); + + ir_rvalue *const array = op[0]; + + result = new(ctx) ir_dereference_array(op[0], op[1]); + + /* Do not use op[0] after this point. Use array. + */ + op[0] = NULL; + + + if (error_emitted) + break; + + if (!array->type->is_array() + && !array->type->is_matrix() + && !array->type->is_vector()) { + _mesa_glsl_error(& index_loc, state, + "cannot dereference non-array / non-matrix / " + "non-vector"); + error_emitted = true; + } + + if (!op[1]->type->is_integer()) { + _mesa_glsl_error(& index_loc, state, + "array index must be integer type"); + error_emitted = true; + } else if (!op[1]->type->is_scalar()) { + _mesa_glsl_error(& index_loc, state, + "array index must be scalar"); + error_emitted = true; + } + + /* If the array index is a constant expression and the array has a + * declared size, ensure that the access is in-bounds. If the array + * index is not a constant expression, ensure that the array has a + * declared size. + */ + ir_constant *const const_index = op[1]->constant_expression_value(); + if (const_index != NULL) { + const int idx = const_index->value.i[0]; + const char *type_name; + unsigned bound = 0; + + if (array->type->is_matrix()) { + type_name = "matrix"; + } else if (array->type->is_vector()) { + type_name = "vector"; + } else { + type_name = "array"; + } + + /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec: + * + * "It is illegal to declare an array with a size, and then + * later (in the same shader) index the same array with an + * integral constant expression greater than or equal to the + * declared size. It is also illegal to index an array with a + * negative constant expression." + */ + if (array->type->is_matrix()) { + if (array->type->row_type()->vector_elements <= idx) { + bound = array->type->row_type()->vector_elements; + } + } else if (array->type->is_vector()) { + if (array->type->vector_elements <= idx) { + bound = array->type->vector_elements; + } + } else { + if ((array->type->array_size() > 0) + && (array->type->array_size() <= idx)) { + bound = array->type->array_size(); + } + } + + if (bound > 0) { + _mesa_glsl_error(& loc, state, "%s index must be < %u", + type_name, bound); + error_emitted = true; + } else if (idx < 0) { + _mesa_glsl_error(& loc, state, "%s index must be >= 0", + type_name); + error_emitted = true; + } + + if (array->type->is_array()) { + /* If the array is a variable dereference, it dereferences the + * whole array, by definition. Use this to get the variable. + * + * FINISHME: Should some methods for getting / setting / testing + * FINISHME: array access limits be added to ir_dereference? + */ + ir_variable *const v = array->whole_variable_referenced(); + if ((v != NULL) && (unsigned(idx) > v->max_array_access)) + v->max_array_access = idx; + } + } else if (array->type->array_size() == 0) { + _mesa_glsl_error(&loc, state, "unsized array index must be constant"); + } else { + if (array->type->is_array()) { + /* whole_variable_referenced can return NULL if the array is a + * member of a structure. In this case it is safe to not update + * the max_array_access field because it is never used for fields + * of structures. + */ + ir_variable *v = array->whole_variable_referenced(); + if (v != NULL) + v->max_array_access = array->type->array_size(); + } + } + + if (error_emitted) + result->type = glsl_type::error_type; + + type = result->type; + break; + } + + case ast_function_call: + /* Should *NEVER* get here. ast_function_call should always be handled + * by ast_function_expression::hir. + */ + assert(0); + break; + + case ast_identifier: { + /* ast_identifier can appear several places in a full abstract syntax + * tree. This particular use must be at location specified in the grammar + * as 'variable_identifier'. + */ + ir_variable *var = + state->symbols->get_variable(this->primary_expression.identifier); + + result = new(ctx) ir_dereference_variable(var); + + if (var != NULL) { + type = result->type; + } else { + _mesa_glsl_error(& loc, state, "`%s' undeclared", + this->primary_expression.identifier); + + error_emitted = true; + } + break; + } + + case ast_int_constant: + type = glsl_type::int_type; + result = new(ctx) ir_constant(this->primary_expression.int_constant); + break; + + case ast_uint_constant: + type = glsl_type::uint_type; + result = new(ctx) ir_constant(this->primary_expression.uint_constant); + break; + + case ast_float_constant: + type = glsl_type::float_type; + result = new(ctx) ir_constant(this->primary_expression.float_constant); + break; + + case ast_bool_constant: + type = glsl_type::bool_type; + result = new(ctx) ir_constant(bool(this->primary_expression.bool_constant)); + break; + + case ast_sequence: { + /* It should not be possible to generate a sequence in the AST without + * any expressions in it. + */ + assert(!this->expressions.is_empty()); + + /* The r-value of a sequence is the last expression in the sequence. If + * the other expressions in the sequence do not have side-effects (and + * therefore add instructions to the instruction list), they get dropped + * on the floor. + */ + foreach_list_typed (ast_node, ast, link, &this->expressions) + result = ast->hir(instructions, state); + + type = result->type; + + /* Any errors should have already been emitted in the loop above. + */ + error_emitted = true; + break; + } + } + + if (type->is_error() && !error_emitted) + _mesa_glsl_error(& loc, state, "type mismatch"); + + return result; +} + + +ir_rvalue * +ast_expression_statement::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + /* It is possible to have expression statements that don't have an + * expression. This is the solitary semicolon: + * + * for (i = 0; i < 5; i++) + * ; + * + * In this case the expression will be NULL. Test for NULL and don't do + * anything in that case. + */ + if (expression != NULL) + expression->hir(instructions, state); + + /* Statements do not have r-values. + */ + return NULL; +} + + +ir_rvalue * +ast_compound_statement::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + if (new_scope) + state->symbols->push_scope(); + + foreach_list_typed (ast_node, ast, link, &this->statements) + ast->hir(instructions, state); + + if (new_scope) + state->symbols->pop_scope(); + + /* Compound statements do not have r-values. + */ + return NULL; +} + + +static const glsl_type * +process_array_type(const glsl_type *base, ast_node *array_size, + struct _mesa_glsl_parse_state *state) +{ + unsigned length = 0; + + /* FINISHME: Reject delcarations of multidimensional arrays. */ + + if (array_size != NULL) { + exec_list dummy_instructions; + ir_rvalue *const ir = array_size->hir(& dummy_instructions, state); + YYLTYPE loc = array_size->get_location(); + + /* FINISHME: Verify that the grammar forbids side-effects in array + * FINISHME: sizes. i.e., 'vec4 [x = 12] data' + */ + assert(dummy_instructions.is_empty()); + + if (ir != NULL) { + if (!ir->type->is_integer()) { + _mesa_glsl_error(& loc, state, "array size must be integer type"); + } else if (!ir->type->is_scalar()) { + _mesa_glsl_error(& loc, state, "array size must be scalar type"); + } else { + ir_constant *const size = ir->constant_expression_value(); + + if (size == NULL) { + _mesa_glsl_error(& loc, state, "array size must be a " + "constant valued expression"); + } else if (size->value.i[0] <= 0) { + _mesa_glsl_error(& loc, state, "array size must be > 0"); + } else { + assert(size->type == ir->type); + length = size->value.u[0]; + } + } + } + } + + return glsl_type::get_array_instance(base, length); +} + + +const glsl_type * +ast_type_specifier::glsl_type(const char **name, + struct _mesa_glsl_parse_state *state) const +{ + const struct glsl_type *type; + + if ((this->type_specifier == ast_struct) && (this->type_name == NULL)) { + /* FINISHME: Handle annonymous structures. */ + type = NULL; + } else { + type = state->symbols->get_type(this->type_name); + *name = this->type_name; + + if (this->is_array) { + type = process_array_type(type, this->array_size, state); + } + } + + return type; +} + + +static void +apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, + ir_variable *var, + struct _mesa_glsl_parse_state *state, + YYLTYPE *loc) +{ + if (qual->invariant) + var->invariant = 1; + + /* FINISHME: Mark 'in' variables at global scope as read-only. */ + if (qual->constant || qual->attribute || qual->uniform + || (qual->varying && (state->target == fragment_shader))) + var->read_only = 1; + + if (qual->centroid) + var->centroid = 1; + + if (qual->attribute && state->target != vertex_shader) { + var->type = glsl_type::error_type; + _mesa_glsl_error(loc, state, + "`attribute' variables may not be declared in the " + "%s shader", + _mesa_glsl_shader_target_name(state->target)); + } + + /* From page 25 (page 31 of the PDF) of the GLSL 1.10 spec: + * + * "The varying qualifier can be used only with the data types + * float, vec2, vec3, vec4, mat2, mat3, and mat4, or arrays of + * these." + */ + if (qual->varying) { + const glsl_type *non_array_type; + + if (var->type && var->type->is_array()) + non_array_type = var->type->fields.array; + else + non_array_type = var->type; + + if (non_array_type && non_array_type->base_type != GLSL_TYPE_FLOAT) { + var->type = glsl_type::error_type; + _mesa_glsl_error(loc, state, + "varying variables must be of base type float"); + } + } + + /* If there is no qualifier that changes the mode of the variable, leave + * the setting alone. + */ + if (qual->in && qual->out) + var->mode = ir_var_inout; + else if (qual->attribute || qual->in + || (qual->varying && (state->target == fragment_shader))) + var->mode = ir_var_in; + else if (qual->out || (qual->varying && (state->target == vertex_shader))) + var->mode = ir_var_out; + else if (qual->uniform) + var->mode = ir_var_uniform; + + if (qual->flat) + var->interpolation = ir_var_flat; + else if (qual->noperspective) + var->interpolation = ir_var_noperspective; + else + var->interpolation = ir_var_smooth; + + var->pixel_center_integer = qual->pixel_center_integer; + var->origin_upper_left = qual->origin_upper_left; + if ((qual->origin_upper_left || qual->pixel_center_integer) + && (strcmp(var->name, "gl_FragCoord") != 0)) { + const char *const qual_string = (qual->origin_upper_left) + ? "origin_upper_left" : "pixel_center_integer"; + + _mesa_glsl_error(loc, state, + "layout qualifier `%s' can only be applied to " + "fragment shader input `gl_FragCoord'", + qual_string); + } + + if (var->type->is_array() && (state->language_version >= 120)) { + var->array_lvalue = true; + } +} + + +ir_rvalue * +ast_declarator_list::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + const struct glsl_type *decl_type; + const char *type_name = NULL; + ir_rvalue *result = NULL; + YYLTYPE loc = this->get_location(); + + /* From page 46 (page 52 of the PDF) of the GLSL 1.50 spec: + * + * "To ensure that a particular output variable is invariant, it is + * necessary to use the invariant qualifier. It can either be used to + * qualify a previously declared variable as being invariant + * + * invariant gl_Position; // make existing gl_Position be invariant" + * + * In these cases the parser will set the 'invariant' flag in the declarator + * list, and the type will be NULL. + */ + if (this->invariant) { + assert(this->type == NULL); + + if (state->current_function != NULL) { + _mesa_glsl_error(& loc, state, + "All uses of `invariant' keyword must be at global " + "scope\n"); + } + + foreach_list_typed (ast_declaration, decl, link, &this->declarations) { + assert(!decl->is_array); + assert(decl->array_size == NULL); + assert(decl->initializer == NULL); + + ir_variable *const earlier = + state->symbols->get_variable(decl->identifier); + if (earlier == NULL) { + _mesa_glsl_error(& loc, state, + "Undeclared variable `%s' cannot be marked " + "invariant\n", decl->identifier); + } else if ((state->target == vertex_shader) + && (earlier->mode != ir_var_out)) { + _mesa_glsl_error(& loc, state, + "`%s' cannot be marked invariant, vertex shader " + "outputs only\n", decl->identifier); + } else if ((state->target == fragment_shader) + && (earlier->mode != ir_var_in)) { + _mesa_glsl_error(& loc, state, + "`%s' cannot be marked invariant, fragment shader " + "inputs only\n", decl->identifier); + } else { + earlier->invariant = true; + } + } + + /* Invariant redeclarations do not have r-values. + */ + return NULL; + } + + assert(this->type != NULL); + assert(!this->invariant); + + /* The type specifier may contain a structure definition. Process that + * before any of the variable declarations. + */ + (void) this->type->specifier->hir(instructions, state); + + decl_type = this->type->specifier->glsl_type(& type_name, state); + if (this->declarations.is_empty()) { + /* The only valid case where the declaration list can be empty is when + * the declaration is setting the default precision of a built-in type + * (e.g., 'precision highp vec4;'). + */ + + if (decl_type != NULL) { + } else { + _mesa_glsl_error(& loc, state, "incomplete declaration"); + } + } + + foreach_list_typed (ast_declaration, decl, link, &this->declarations) { + const struct glsl_type *var_type; + ir_variable *var; + + /* FINISHME: Emit a warning if a variable declaration shadows a + * FINISHME: declaration at a higher scope. + */ + + if ((decl_type == NULL) || decl_type->is_void()) { + if (type_name != NULL) { + _mesa_glsl_error(& loc, state, + "invalid type `%s' in declaration of `%s'", + type_name, decl->identifier); + } else { + _mesa_glsl_error(& loc, state, + "invalid type in declaration of `%s'", + decl->identifier); + } + continue; + } + + if (decl->is_array) { + var_type = process_array_type(decl_type, decl->array_size, state); + } else { + var_type = decl_type; + } + + var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto); + + /* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification; + * + * "Global variables can only use the qualifiers const, + * attribute, uni form, or varying. Only one may be + * specified. + * + * Local variables can only use the qualifier const." + * + * This is relaxed in GLSL 1.30. + */ + if (state->language_version < 120) { + if (this->type->qualifier.out) { + _mesa_glsl_error(& loc, state, + "`out' qualifier in declaration of `%s' " + "only valid for function parameters in GLSL 1.10.", + decl->identifier); + } + if (this->type->qualifier.in) { + _mesa_glsl_error(& loc, state, + "`in' qualifier in declaration of `%s' " + "only valid for function parameters in GLSL 1.10.", + decl->identifier); + } + /* FINISHME: Test for other invalid qualifiers. */ + } + + apply_type_qualifier_to_variable(& this->type->qualifier, var, state, + & loc); + + if (this->type->qualifier.invariant) { + if ((state->target == vertex_shader) && !(var->mode == ir_var_out || + var->mode == ir_var_inout)) { + /* FINISHME: Note that this doesn't work for invariant on + * a function signature outval + */ + _mesa_glsl_error(& loc, state, + "`%s' cannot be marked invariant, vertex shader " + "outputs only\n", var->name); + } else if ((state->target == fragment_shader) && + !(var->mode == ir_var_in || var->mode == ir_var_inout)) { + /* FINISHME: Note that this doesn't work for invariant on + * a function signature inval + */ + _mesa_glsl_error(& loc, state, + "`%s' cannot be marked invariant, fragment shader " + "inputs only\n", var->name); + } + } + + if (state->current_function != NULL) { + const char *mode = NULL; + const char *extra = ""; + + /* There is no need to check for 'inout' here because the parser will + * only allow that in function parameter lists. + */ + if (this->type->qualifier.attribute) { + mode = "attribute"; + } else if (this->type->qualifier.uniform) { + mode = "uniform"; + } else if (this->type->qualifier.varying) { + mode = "varying"; + } else if (this->type->qualifier.in) { + mode = "in"; + extra = " or in function parameter list"; + } else if (this->type->qualifier.out) { + mode = "out"; + extra = " or in function parameter list"; + } + + if (mode) { + _mesa_glsl_error(& loc, state, + "%s variable `%s' must be declared at " + "global scope%s", + mode, var->name, extra); + } + } else if (var->mode == ir_var_in) { + if (state->target == vertex_shader) { + bool error_emitted = false; + + /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec: + * + * "Vertex shader inputs can only be float, floating-point + * vectors, matrices, signed and unsigned integers and integer + * vectors. Vertex shader inputs can also form arrays of these + * types, but not structures." + * + * From page 31 (page 27 of the PDF) of the GLSL 1.30 spec: + * + * "Vertex shader inputs can only be float, floating-point + * vectors, matrices, signed and unsigned integers and integer + * vectors. They cannot be arrays or structures." + * + * From page 23 (page 29 of the PDF) of the GLSL 1.20 spec: + * + * "The attribute qualifier can be used only with float, + * floating-point vectors, and matrices. Attribute variables + * cannot be declared as arrays or structures." + */ + const glsl_type *check_type = var->type->is_array() + ? var->type->fields.array : var->type; + + switch (check_type->base_type) { + case GLSL_TYPE_FLOAT: + break; + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + if (state->language_version > 120) + break; + /* FALLTHROUGH */ + default: + _mesa_glsl_error(& loc, state, + "vertex shader input / attribute cannot have " + "type %s`%s'", + var->type->is_array() ? "array of " : "", + check_type->name); + error_emitted = true; + } + + if (!error_emitted && (state->language_version <= 130) + && var->type->is_array()) { + _mesa_glsl_error(& loc, state, + "vertex shader input / attribute cannot have " + "array type"); + error_emitted = true; + } + } + } + + /* Process the initializer and add its instructions to a temporary + * list. This list will be added to the instruction stream (below) after + * the declaration is added. This is done because in some cases (such as + * redeclarations) the declaration may not actually be added to the + * instruction stream. + */ + exec_list initializer_instructions; + if (decl->initializer != NULL) { + YYLTYPE initializer_loc = decl->initializer->get_location(); + + /* From page 24 (page 30 of the PDF) of the GLSL 1.10 spec: + * + * "All uniform variables are read-only and are initialized either + * directly by an application via API commands, or indirectly by + * OpenGL." + */ + if ((state->language_version <= 110) + && (var->mode == ir_var_uniform)) { + _mesa_glsl_error(& initializer_loc, state, + "cannot initialize uniforms in GLSL 1.10"); + } + + if (var->type->is_sampler()) { + _mesa_glsl_error(& initializer_loc, state, + "cannot initialize samplers"); + } + + if ((var->mode == ir_var_in) && (state->current_function == NULL)) { + _mesa_glsl_error(& initializer_loc, state, + "cannot initialize %s shader input / %s", + _mesa_glsl_shader_target_name(state->target), + (state->target == vertex_shader) + ? "attribute" : "varying"); + } + + ir_dereference *const lhs = new(ctx) ir_dereference_variable(var); + ir_rvalue *rhs = decl->initializer->hir(&initializer_instructions, + state); + + /* Calculate the constant value if this is a const or uniform + * declaration. + */ + if (this->type->qualifier.constant || this->type->qualifier.uniform) { + ir_rvalue *new_rhs = validate_assignment(state, var->type, rhs); + if (new_rhs != NULL) { + rhs = new_rhs; + + ir_constant *constant_value = rhs->constant_expression_value(); + if (!constant_value) { + _mesa_glsl_error(& initializer_loc, state, + "initializer of %s variable `%s' must be a " + "constant expression", + (this->type->qualifier.constant) + ? "const" : "uniform", + decl->identifier); + if (var->type->is_numeric()) { + /* Reduce cascading errors. */ + var->constant_value = ir_constant::zero(ctx, var->type); + } + } else { + rhs = constant_value; + var->constant_value = constant_value; + } + } else { + _mesa_glsl_error(&initializer_loc, state, + "initializer of type %s cannot be assigned to " + "variable of type %s", + rhs->type->name, var->type->name); + if (var->type->is_numeric()) { + /* Reduce cascading errors. */ + var->constant_value = ir_constant::zero(ctx, var->type); + } + } + } + + if (rhs && !rhs->type->is_error()) { + bool temp = var->read_only; + if (this->type->qualifier.constant) + var->read_only = false; + + /* Never emit code to initialize a uniform. + */ + if (!this->type->qualifier.uniform) + result = do_assignment(&initializer_instructions, state, + lhs, rhs, + this->get_location()); + var->read_only = temp; + } + } + + /* From page 23 (page 29 of the PDF) of the GLSL 1.10 spec: + * + * "It is an error to write to a const variable outside of + * its declaration, so they must be initialized when + * declared." + */ + if (this->type->qualifier.constant && decl->initializer == NULL) { + _mesa_glsl_error(& loc, state, + "const declaration of `%s' must be initialized"); + } + + /* Check if this declaration is actually a re-declaration, either to + * resize an array or add qualifiers to an existing variable. + * + * This is allowed for variables in the current scope, or when at + * global scope (for built-ins in the implicit outer scope). + */ + ir_variable *earlier = state->symbols->get_variable(decl->identifier); + if (earlier != NULL && (state->current_function == NULL || + state->symbols->name_declared_this_scope(decl->identifier))) { + + /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec, + * + * "It is legal to declare an array without a size and then + * later re-declare the same name as an array of the same + * type and specify a size." + */ + if ((earlier->type->array_size() == 0) + && var->type->is_array() + && (var->type->element_type() == earlier->type->element_type())) { + /* FINISHME: This doesn't match the qualifiers on the two + * FINISHME: declarations. It's not 100% clear whether this is + * FINISHME: required or not. + */ + + /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec: + * + * "The size [of gl_TexCoord] can be at most + * gl_MaxTextureCoords." + */ + const unsigned size = unsigned(var->type->array_size()); + if ((strcmp("gl_TexCoord", var->name) == 0) + && (size > state->Const.MaxTextureCoords)) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, "`gl_TexCoord' array size cannot " + "be larger than gl_MaxTextureCoords (%u)\n", + state->Const.MaxTextureCoords); + } else if ((size > 0) && (size <= earlier->max_array_access)) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, "array size must be > %u due to " + "previous access", + earlier->max_array_access); + } + + earlier->type = var->type; + delete var; + var = NULL; + } else if (state->extensions->ARB_fragment_coord_conventions + && strcmp(var->name, "gl_FragCoord") == 0 + && earlier->type == var->type + && earlier->mode == var->mode) { + /* Allow redeclaration of gl_FragCoord for ARB_fcc layout + * qualifiers. + */ + earlier->origin_upper_left = var->origin_upper_left; + earlier->pixel_center_integer = var->pixel_center_integer; + } else { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(&loc, state, "`%s' redeclared", decl->identifier); + } + + continue; + } + + /* By now, we know it's a new variable declaration (we didn't hit the + * above "continue"). + * + * From page 15 (page 21 of the PDF) of the GLSL 1.10 spec, + * + * "Identifiers starting with "gl_" are reserved for use by + * OpenGL, and may not be declared in a shader as either a + * variable or a function." + */ + if (strncmp(decl->identifier, "gl_", 3) == 0) + _mesa_glsl_error(& loc, state, + "identifier `%s' uses reserved `gl_' prefix", + decl->identifier); + + /* Add the variable to the symbol table. Note that the initializer's + * IR was already processed earlier (though it hasn't been emitted yet), + * without the variable in scope. + * + * This differs from most C-like languages, but it follows the GLSL + * specification. From page 28 (page 34 of the PDF) of the GLSL 1.50 + * spec: + * + * "Within a declaration, the scope of a name starts immediately + * after the initializer if present or immediately after the name + * being declared if not." + */ + if (!state->symbols->add_variable(var->name, var)) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(&loc, state, "name `%s' already taken in the " + "current scope", decl->identifier); + continue; + } + + /* Push the variable declaration to the top. It means that all + * the variable declarations will appear in a funny + * last-to-first order, but otherwise we run into trouble if a + * function is prototyped, a global var is decled, then the + * function is defined with usage of the global var. See + * glslparsertest's CorrectModule.frag. + */ + instructions->push_head(var); + instructions->append_list(&initializer_instructions); + } + + + /* Generally, variable declarations do not have r-values. However, + * one is used for the declaration in + * + * while (bool b = some_condition()) { + * ... + * } + * + * so we return the rvalue from the last seen declaration here. + */ + return result; +} + + +ir_rvalue * +ast_parameter_declarator::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + const struct glsl_type *type; + const char *name = NULL; + YYLTYPE loc = this->get_location(); + + type = this->type->specifier->glsl_type(& name, state); + + if (type == NULL) { + if (name != NULL) { + _mesa_glsl_error(& loc, state, + "invalid type `%s' in declaration of `%s'", + name, this->identifier); + } else { + _mesa_glsl_error(& loc, state, + "invalid type in declaration of `%s'", + this->identifier); + } + + type = glsl_type::error_type; + } + + /* From page 62 (page 68 of the PDF) of the GLSL 1.50 spec: + * + * "Functions that accept no input arguments need not use void in the + * argument list because prototypes (or definitions) are required and + * therefore there is no ambiguity when an empty argument list "( )" is + * declared. The idiom "(void)" as a parameter list is provided for + * convenience." + * + * Placing this check here prevents a void parameter being set up + * for a function, which avoids tripping up checks for main taking + * parameters and lookups of an unnamed symbol. + */ + if (type->is_void()) { + if (this->identifier != NULL) + _mesa_glsl_error(& loc, state, + "named parameter cannot have type `void'"); + + is_void = true; + return NULL; + } + + if (formal_parameter && (this->identifier == NULL)) { + _mesa_glsl_error(& loc, state, "formal parameter lacks a name"); + return NULL; + } + + /* This only handles "vec4 foo[..]". The earlier specifier->glsl_type(...) + * call already handled the "vec4[..] foo" case. + */ + if (this->is_array) { + type = process_array_type(type, this->array_size, state); + } + + if (type->array_size() == 0) { + _mesa_glsl_error(&loc, state, "arrays passed as parameters must have " + "a declared size."); + type = glsl_type::error_type; + } + + is_void = false; + ir_variable *var = new(ctx) ir_variable(type, this->identifier, ir_var_in); + + /* Apply any specified qualifiers to the parameter declaration. Note that + * for function parameters the default mode is 'in'. + */ + apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc); + + instructions->push_tail(var); + + /* Parameter declarations do not have r-values. + */ + return NULL; +} + + +void +ast_parameter_declarator::parameters_to_hir(exec_list *ast_parameters, + bool formal, + exec_list *ir_parameters, + _mesa_glsl_parse_state *state) +{ + ast_parameter_declarator *void_param = NULL; + unsigned count = 0; + + foreach_list_typed (ast_parameter_declarator, param, link, ast_parameters) { + param->formal_parameter = formal; + param->hir(ir_parameters, state); + + if (param->is_void) + void_param = param; + + count++; + } + + if ((void_param != NULL) && (count > 1)) { + YYLTYPE loc = void_param->get_location(); + + _mesa_glsl_error(& loc, state, + "`void' parameter must be only parameter"); + } +} + + +ir_rvalue * +ast_function::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + ir_function *f = NULL; + ir_function_signature *sig = NULL; + exec_list hir_parameters; + + const char *const name = identifier; + + /* From page 21 (page 27 of the PDF) of the GLSL 1.20 spec, + * + * "Function declarations (prototypes) cannot occur inside of functions; + * they must be at global scope, or for the built-in functions, outside + * the global scope." + * + * From page 27 (page 33 of the PDF) of the GLSL ES 1.00.16 spec, + * + * "User defined functions may only be defined within the global scope." + * + * Note that this language does not appear in GLSL 1.10. + */ + if ((state->current_function != NULL) && (state->language_version != 110)) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(&loc, state, + "declaration of function `%s' not allowed within " + "function body", name); + } + + /* From page 15 (page 21 of the PDF) of the GLSL 1.10 spec, + * + * "Identifiers starting with "gl_" are reserved for use by + * OpenGL, and may not be declared in a shader as either a + * variable or a function." + */ + if (strncmp(name, "gl_", 3) == 0) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(&loc, state, + "identifier `%s' uses reserved `gl_' prefix", name); + } + + /* Convert the list of function parameters to HIR now so that they can be + * used below to compare this function's signature with previously seen + * signatures for functions with the same name. + */ + ast_parameter_declarator::parameters_to_hir(& this->parameters, + is_definition, + & hir_parameters, state); + + const char *return_type_name; + const glsl_type *return_type = + this->return_type->specifier->glsl_type(& return_type_name, state); + + if (!return_type) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(&loc, state, + "function `%s' has undeclared return type `%s'", + name, return_type_name); + return_type = glsl_type::error_type; + } + + /* From page 56 (page 62 of the PDF) of the GLSL 1.30 spec: + * "No qualifier is allowed on the return type of a function." + */ + if (this->return_type->has_qualifiers()) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(& loc, state, + "function `%s' return type has qualifiers", name); + } + + /* Verify that this function's signature either doesn't match a previously + * seen signature for a function with the same name, or, if a match is found, + * that the previously seen signature does not have an associated definition. + */ + f = state->symbols->get_function(name); + if (f != NULL && !f->is_builtin) { + sig = f->exact_matching_signature(&hir_parameters); + if (sig != NULL) { + const char *badvar = sig->qualifiers_match(&hir_parameters); + if (badvar != NULL) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(&loc, state, "function `%s' parameter `%s' " + "qualifiers don't match prototype", name, badvar); + } + + if (sig->return_type != return_type) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(&loc, state, "function `%s' return type doesn't " + "match prototype", name); + } + + if (is_definition && sig->is_defined) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, "function `%s' redefined", name); + } + } + } else { + f = new(ctx) ir_function(name); + if (!state->symbols->add_function(f->name, f)) { + /* This function name shadows a non-function use of the same name. */ + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(&loc, state, "function name `%s' conflicts with " + "non-function", name); + return NULL; + } + + /* Emit the new function header */ + if (state->current_function == NULL) + instructions->push_tail(f); + else { + /* IR invariants disallow function declarations or definitions nested + * within other function definitions. Insert the new ir_function + * block in the instruction sequence before the ir_function block + * containing the current ir_function_signature. + * + * This can only happen in a GLSL 1.10 shader. In all other GLSL + * versions this nesting is disallowed. There is a check for this at + * the top of this function. + */ + ir_function *const curr = + const_cast<ir_function *>(state->current_function->function()); + + curr->insert_before(f); + } + } + + /* Verify the return type of main() */ + if (strcmp(name, "main") == 0) { + if (! return_type->is_void()) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, "main() must return void"); + } + + if (!hir_parameters.is_empty()) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, "main() must not take any parameters"); + } + } + + /* Finish storing the information about this new function in its signature. + */ + if (sig == NULL) { + sig = new(ctx) ir_function_signature(return_type); + f->add_signature(sig); + } + + sig->replace_parameters(&hir_parameters); + signature = sig; + + /* Function declarations (prototypes) do not have r-values. + */ + return NULL; +} + + +ir_rvalue * +ast_function_definition::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + prototype->is_definition = true; + prototype->hir(instructions, state); + + ir_function_signature *signature = prototype->signature; + if (signature == NULL) + return NULL; + + assert(state->current_function == NULL); + state->current_function = signature; + state->found_return = false; + + /* Duplicate parameters declared in the prototype as concrete variables. + * Add these to the symbol table. + */ + state->symbols->push_scope(); + foreach_iter(exec_list_iterator, iter, signature->parameters) { + ir_variable *const var = ((ir_instruction *) iter.get())->as_variable(); + + assert(var != NULL); + + /* The only way a parameter would "exist" is if two parameters have + * the same name. + */ + if (state->symbols->name_declared_this_scope(var->name)) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, "parameter `%s' redeclared", var->name); + } else { + state->symbols->add_variable(var->name, var); + } + } + + /* Convert the body of the function to HIR. */ + this->body->hir(&signature->body, state); + signature->is_defined = true; + + state->symbols->pop_scope(); + + assert(state->current_function == signature); + state->current_function = NULL; + + if (!signature->return_type->is_void() && !state->found_return) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(& loc, state, "function `%s' has non-void return type " + "%s, but no return statement", + signature->function_name(), + signature->return_type->name); + } + + /* Function definitions do not have r-values. + */ + return NULL; +} + + +ir_rvalue * +ast_jump_statement::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + + switch (mode) { + case ast_return: { + ir_return *inst; + assert(state->current_function); + + if (opt_return_value) { + if (state->current_function->return_type->base_type == + GLSL_TYPE_VOID) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, + "`return` with a value, in function `%s' " + "returning void", + state->current_function->function_name()); + } + + ir_expression *const ret = (ir_expression *) + opt_return_value->hir(instructions, state); + assert(ret != NULL); + + /* Implicit conversions are not allowed for return values. */ + if (state->current_function->return_type != ret->type) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, + "`return' with wrong type %s, in function `%s' " + "returning %s", + ret->type->name, + state->current_function->function_name(), + state->current_function->return_type->name); + } + + inst = new(ctx) ir_return(ret); + } else { + if (state->current_function->return_type->base_type != + GLSL_TYPE_VOID) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, + "`return' with no value, in function %s returning " + "non-void", + state->current_function->function_name()); + } + inst = new(ctx) ir_return; + } + + state->found_return = true; + instructions->push_tail(inst); + break; + } + + case ast_discard: + if (state->target != fragment_shader) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, + "`discard' may only appear in a fragment shader"); + } + instructions->push_tail(new(ctx) ir_discard); + break; + + case ast_break: + case ast_continue: + /* FINISHME: Handle switch-statements. They cannot contain 'continue', + * FINISHME: and they use a different IR instruction for 'break'. + */ + /* FINISHME: Correctly handle the nesting. If a switch-statement is + * FINISHME: inside a loop, a 'continue' is valid and will bind to the + * FINISHME: loop. + */ + if (state->loop_or_switch_nesting == NULL) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, + "`%s' may only appear in a loop", + (mode == ast_break) ? "break" : "continue"); + } else { + ir_loop *const loop = state->loop_or_switch_nesting->as_loop(); + + /* Inline the for loop expression again, since we don't know + * where near the end of the loop body the normal copy of it + * is going to be placed. + */ + if (mode == ast_continue && + state->loop_or_switch_nesting_ast->rest_expression) { + state->loop_or_switch_nesting_ast->rest_expression->hir(instructions, + state); + } + + if (loop != NULL) { + ir_loop_jump *const jump = + new(ctx) ir_loop_jump((mode == ast_break) + ? ir_loop_jump::jump_break + : ir_loop_jump::jump_continue); + instructions->push_tail(jump); + } + } + + break; + } + + /* Jump instructions do not have r-values. + */ + return NULL; +} + + +ir_rvalue * +ast_selection_statement::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + + ir_rvalue *const condition = this->condition->hir(instructions, state); + + /* From page 66 (page 72 of the PDF) of the GLSL 1.50 spec: + * + * "Any expression whose type evaluates to a Boolean can be used as the + * conditional expression bool-expression. Vector types are not accepted + * as the expression to if." + * + * The checks are separated so that higher quality diagnostics can be + * generated for cases where both rules are violated. + */ + if (!condition->type->is_boolean() || !condition->type->is_scalar()) { + YYLTYPE loc = this->condition->get_location(); + + _mesa_glsl_error(& loc, state, "if-statement condition must be scalar " + "boolean"); + } + + ir_if *const stmt = new(ctx) ir_if(condition); + + if (then_statement != NULL) { + state->symbols->push_scope(); + then_statement->hir(& stmt->then_instructions, state); + state->symbols->pop_scope(); + } + + if (else_statement != NULL) { + state->symbols->push_scope(); + else_statement->hir(& stmt->else_instructions, state); + state->symbols->pop_scope(); + } + + instructions->push_tail(stmt); + + /* if-statements do not have r-values. + */ + return NULL; +} + + +void +ast_iteration_statement::condition_to_hir(ir_loop *stmt, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + + if (condition != NULL) { + ir_rvalue *const cond = + condition->hir(& stmt->body_instructions, state); + + if ((cond == NULL) + || !cond->type->is_boolean() || !cond->type->is_scalar()) { + YYLTYPE loc = condition->get_location(); + + _mesa_glsl_error(& loc, state, + "loop condition must be scalar boolean"); + } else { + /* As the first code in the loop body, generate a block that looks + * like 'if (!condition) break;' as the loop termination condition. + */ + ir_rvalue *const not_cond = + new(ctx) ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond, + NULL); + + ir_if *const if_stmt = new(ctx) ir_if(not_cond); + + ir_jump *const break_stmt = + new(ctx) ir_loop_jump(ir_loop_jump::jump_break); + + if_stmt->then_instructions.push_tail(break_stmt); + stmt->body_instructions.push_tail(if_stmt); + } + } +} + + +ir_rvalue * +ast_iteration_statement::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + + /* For-loops and while-loops start a new scope, but do-while loops do not. + */ + if (mode != ast_do_while) + state->symbols->push_scope(); + + if (init_statement != NULL) + init_statement->hir(instructions, state); + + ir_loop *const stmt = new(ctx) ir_loop(); + instructions->push_tail(stmt); + + /* Track the current loop and / or switch-statement nesting. + */ + ir_instruction *const nesting = state->loop_or_switch_nesting; + ast_iteration_statement *nesting_ast = state->loop_or_switch_nesting_ast; + + state->loop_or_switch_nesting = stmt; + state->loop_or_switch_nesting_ast = this; + + if (mode != ast_do_while) + condition_to_hir(stmt, state); + + if (body != NULL) + body->hir(& stmt->body_instructions, state); + + if (rest_expression != NULL) + rest_expression->hir(& stmt->body_instructions, state); + + if (mode == ast_do_while) + condition_to_hir(stmt, state); + + if (mode != ast_do_while) + state->symbols->pop_scope(); + + /* Restore previous nesting before returning. + */ + state->loop_or_switch_nesting = nesting; + state->loop_or_switch_nesting_ast = nesting_ast; + + /* Loops do not have r-values. + */ + return NULL; +} + + +ir_rvalue * +ast_type_specifier::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + if (this->structure != NULL) + return this->structure->hir(instructions, state); + + return NULL; +} + + +ir_rvalue * +ast_struct_specifier::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + unsigned decl_count = 0; + + /* Make an initial pass over the list of structure fields to determine how + * many there are. Each element in this list is an ast_declarator_list. + * This means that we actually need to count the number of elements in the + * 'declarations' list in each of the elements. + */ + foreach_list_typed (ast_declarator_list, decl_list, link, + &this->declarations) { + foreach_list_const (decl_ptr, & decl_list->declarations) { + decl_count++; + } + } + + + /* Allocate storage for the structure fields and process the field + * declarations. As the declarations are processed, try to also convert + * the types to HIR. This ensures that structure definitions embedded in + * other structure definitions are processed. + */ + glsl_struct_field *const fields = talloc_array(state, glsl_struct_field, + decl_count); + + unsigned i = 0; + foreach_list_typed (ast_declarator_list, decl_list, link, + &this->declarations) { + const char *type_name; + + decl_list->type->specifier->hir(instructions, state); + + const glsl_type *decl_type = + decl_list->type->specifier->glsl_type(& type_name, state); + + foreach_list_typed (ast_declaration, decl, link, + &decl_list->declarations) { + const struct glsl_type *const field_type = + (decl->is_array) + ? process_array_type(decl_type, decl->array_size, state) + : decl_type; + + fields[i].type = (field_type != NULL) + ? field_type : glsl_type::error_type; + fields[i].name = decl->identifier; + i++; + } + } + + assert(i == decl_count); + + const char *name; + if (this->name == NULL) { + static unsigned anon_count = 1; + char buf[32]; + + snprintf(buf, sizeof(buf), "#anon_struct_%04x", anon_count); + anon_count++; + + name = strdup(buf); + } else { + name = this->name; + } + + const glsl_type *t = + glsl_type::get_record_instance(fields, decl_count, name); + + YYLTYPE loc = this->get_location(); + if (!state->symbols->add_type(name, t)) { + _mesa_glsl_error(& loc, state, "struct `%s' previously defined", name); + } else { + + const glsl_type **s = (const glsl_type **) + realloc(state->user_structures, + sizeof(state->user_structures[0]) * + (state->num_user_structures + 1)); + if (s != NULL) { + s[state->num_user_structures] = t; + state->user_structures = s; + state->num_user_structures++; + } + } + + /* Structure type definitions do not have r-values. + */ + return NULL; +} diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp new file mode 100644 index 0000000000..9a957044e7 --- /dev/null +++ b/src/glsl/ast_type.cpp @@ -0,0 +1,122 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <cstdio> +#include "ast.h" +extern "C" { +#include "program/symbol_table.h" +} + +void +ast_type_specifier::print(void) const +{ + if (type_specifier == ast_struct) { + structure->print(); + } else { + printf("%s ", type_name); + } + + if (is_array) { + printf("[ "); + + if (array_size) { + array_size->print(); + } + + printf("] "); + } +} + +ast_type_specifier::ast_type_specifier(int specifier) + : type_specifier(ast_types(specifier)), type_name(NULL), structure(NULL), + is_array(false), array_size(NULL), precision(ast_precision_high) +{ + static const char *const names[] = { + "void", + "float", + "int", + "uint", + "bool", + "vec2", + "vec3", + "vec4", + "bvec2", + "bvec3", + "bvec4", + "ivec2", + "ivec3", + "ivec4", + "uvec2", + "uvec3", + "uvec4", + "mat2", + "mat2x3", + "mat2x4", + "mat3x2", + "mat3", + "mat3x4", + "mat4x2", + "mat4x3", + "mat4", + "sampler1D", + "sampler2D", + "sampler2DRect", + "sampler3D", + "samplerCube", + "sampler1DShadow", + "sampler2DShadow", + "sampler2DRectShadow", + "samplerCubeShadow", + "sampler1DArray", + "sampler2DArray", + "sampler1DArrayShadow", + "sampler2DArrayShadow", + "isampler1D", + "isampler2D", + "isampler3D", + "isamplerCube", + "isampler1DArray", + "isampler2DArray", + "usampler1D", + "usampler2D", + "usampler3D", + "usamplerCube", + "usampler1DArray", + "usampler2DArray", + + NULL, /* ast_struct */ + NULL /* ast_type_name */ + }; + + type_name = names[specifier]; +} + +bool +ast_fully_specified_type::has_qualifiers() const +{ + return qualifier.invariant || qualifier.constant || qualifier.attribute + || qualifier.varying || qualifier.in + || qualifier.out || qualifier.centroid + || qualifier.uniform || qualifier.smooth + || qualifier.flat || qualifier.noperspective; +} diff --git a/src/glsl/autogen.sh b/src/glsl/autogen.sh new file mode 100755 index 0000000000..904cd6746c --- /dev/null +++ b/src/glsl/autogen.sh @@ -0,0 +1,12 @@ +#! /bin/sh + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir + +autoreconf -v --install || exit 1 +cd $ORIGDIR || exit $? + +$srcdir/configure --enable-maintainer-mode "$@" diff --git a/src/glsl/builtin_function.cpp b/src/glsl/builtin_function.cpp new file mode 100644 index 0000000000..892b5aa857 --- /dev/null +++ b/src/glsl/builtin_function.cpp @@ -0,0 +1,16935 @@ +/* DO NOT MODIFY - automatically generated by generate_builtins.py */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include "main/core.h" /* for struct gl_shader */ +#include "glsl_parser_extras.h" +#include "ir_reader.h" +#include "program.h" +#include "ast.h" + +extern "C" struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type); + +gl_shader * +read_builtins(GLenum target, const char *protos, const char **functions, unsigned count) +{ + gl_shader *sh = _mesa_new_shader(NULL, 0, target); + struct _mesa_glsl_parse_state *st = + new(sh) _mesa_glsl_parse_state(NULL, target, sh); + + st->language_version = 130; + st->symbols->language_version = 130; + st->ARB_texture_rectangle_enable = true; + st->EXT_texture_array_enable = true; + _mesa_glsl_initialize_types(st); + + sh->ir = new(sh) exec_list; + sh->symbols = st->symbols; + + /* Read the IR containing the prototypes */ + _mesa_glsl_read_ir(st, sh->ir, protos, true); + + /* Read ALL the function bodies, telling the IR reader not to scan for + * prototypes (we've already created them). The IR reader will skip any + * signature that does not already exist as a prototype. + */ + for (unsigned i = 0; i < count; i++) { + _mesa_glsl_read_ir(st, sh->ir, functions[i], false); + + if (st->error) { + printf("error reading builtin: %.35s ...\n", functions[i]); + talloc_free(sh); + return NULL; + } + } + + reparent_ir(sh->ir, sh); + delete st; + + return sh; +} + +static const char *builtin_abs = + "((function abs\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float abs (var_ref arg0)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 abs (var_ref arg0)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 abs (var_ref arg0)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 abs (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_acos = + "((function acos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (expression float - (constant float (1.5707963))\n" + " (call asin ((var_ref x)))))))\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (expression vec2 - (constant float (1.5707963))\n" + " (call asin ((var_ref x)))))))\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (expression vec3 - (constant float (1.5707963))\n" + " (call asin ((var_ref x)))))))\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (expression vec4 - (constant float (1.5707963))\n" + " (call asin ((var_ref x)))))))\n" + "))\n" + "" +; +static const char *builtin_all = + "((function all\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 arg0))\n" + " ((return (expression bool && (swiz x (var_ref arg0))(swiz y (var_ref arg0))))))\n" + "\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 arg0))\n" + " ((return (expression bool && (expression bool && (swiz x (var_ref arg0))(swiz y (var_ref arg0))) (swiz z (var_ref arg0))))))\n" + "\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 arg0))\n" + " ((return (expression bool && (expression bool && (expression bool && (swiz x (var_ref arg0))(swiz y (var_ref arg0))) (swiz z (var_ref arg0))) (swiz w (var_ref arg0))))))\n" + "))\n" + "" +; +static const char *builtin_any = + "((function any\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 arg0))\n" + " ((return (expression bool any (var_ref arg0)))))\n" + "\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 arg0))\n" + " ((return (expression bool any (var_ref arg0)))))\n" + "\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 arg0))\n" + " ((return (expression bool any (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_asin = + "((function asin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (expression float *\n" + " (expression float sign (var_ref x))\n" + " (expression float -\n" + " (expression float *\n" + " (constant float (3.1415926))\n" + " (constant float (0.5)))\n" + " (expression float *\n" + " (expression float sqrt\n" + " (expression float -\n" + " (constant float (1.0))\n" + " (expression float abs (var_ref x))))\n" + " (expression float +\n" + " (constant float (1.5707288))\n" + " (expression float *\n" + " (expression float abs (var_ref x))\n" + " (expression float +\n" + " (constant float (-0.2121144))\n" + " (expression float *\n" + " (constant float (0.0742610))\n" + " (expression float abs (var_ref x))))))))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (expression vec2 *\n" + " (expression vec2 sign (var_ref x))\n" + " (expression vec2 -\n" + " (expression float *\n" + " (constant float (3.1415926))\n" + " (constant float (0.5)))\n" + " (expression vec2 *\n" + " (expression vec2 sqrt\n" + " (expression vec2 -\n" + " (constant float (1.0))\n" + " (expression vec2 abs (var_ref x))))\n" + " (expression vec2 +\n" + " (constant float (1.5707288))\n" + " (expression vec2 *\n" + " (expression vec2 abs (var_ref x))\n" + " (expression vec2 +\n" + " (constant float (-0.2121144))\n" + " (expression vec2 *\n" + " (constant float (0.0742610))\n" + " (expression vec2 abs (var_ref x))))))))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (expression vec3 *\n" + " (expression vec3 sign (var_ref x))\n" + " (expression vec3 -\n" + " (expression float *\n" + " (constant float (3.1415926))\n" + " (constant float (0.5)))\n" + " (expression vec3 *\n" + " (expression vec3 sqrt\n" + " (expression vec3 -\n" + " (constant float (1.0))\n" + " (expression vec3 abs (var_ref x))))\n" + " (expression vec3 +\n" + " (constant float (1.5707288))\n" + " (expression vec3 *\n" + " (expression vec3 abs (var_ref x))\n" + " (expression vec3 +\n" + " (constant float (-0.2121144))\n" + " (expression vec3 *\n" + " (constant float (0.0742610))\n" + " (expression vec3 abs (var_ref x))))))))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (expression vec4 *\n" + " (expression vec4 sign (var_ref x))\n" + " (expression vec4 -\n" + " (expression float *\n" + " (constant float (3.1415926))\n" + " (constant float (0.5)))\n" + " (expression vec4 *\n" + " (expression vec4 sqrt\n" + " (expression vec4 -\n" + " (constant float (1.0))\n" + " (expression vec4 abs (var_ref x))))\n" + " (expression vec4 +\n" + " (constant float (1.5707288))\n" + " (expression vec4 *\n" + " (expression vec4 abs (var_ref x))\n" + " (expression vec4 +\n" + " (constant float (-0.2121144))\n" + " (expression vec4 *\n" + " (constant float (0.0742610))\n" + " (expression vec4 abs (var_ref x))))))))))))\n" + "))\n" + "" +; +static const char *builtin_atan = + "((function atan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (call asin ((expression float *\n" + " (var_ref x)\n" + " (expression float rsq\n" + " (expression float +\n" + " (expression float *\n" + " (var_ref x)\n" + " (var_ref x))\n" + " (constant float (1.0))))))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y_over_x))\n" + " ((return (call asin ((expression vec2 *\n" + " (var_ref y_over_x)\n" + " (expression vec2 rsq\n" + " (expression vec2 +\n" + " (expression vec2 *\n" + " (var_ref y_over_x)\n" + " (var_ref y_over_x))\n" + " (constant float (1.0))))))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y_over_x))\n" + " ((return (call asin ((expression vec3 *\n" + " (var_ref y_over_x)\n" + " (expression vec3 rsq\n" + " (expression vec3 +\n" + " (expression vec3 *\n" + " (var_ref y_over_x)\n" + " (var_ref y_over_x))\n" + " (constant float (1.0))))))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y_over_x))\n" + " ((return (call asin ((expression vec4 *\n" + " (var_ref y_over_x)\n" + " (expression vec4 rsq\n" + " (expression vec4 +\n" + " (expression vec4 *\n" + " (var_ref y_over_x)\n" + " (var_ref y_over_x))\n" + " (constant float (1.0))))))))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in ) float y)\n" + " (declare (in ) float x)\n" + " )\n" + " (\n" + " (declare () float r)\n" + " (declare ( ) float abs_retval)\n" + " (assign (constant bool (1)) (var_ref abs_retval) (call abs ((var_ref x) ))\n" + ") \n" + " (if (expression bool > (var_ref abs_retval) (constant float (0.000100)) ) (\n" + " (declare ( ) float atan_retval)\n" + " (assign (constant bool (1)) (var_ref atan_retval) (call atan ((expression float / (var_ref y) (var_ref x) ) ))\n" + ") \n" + " (assign (constant bool (1)) (var_ref r) (var_ref atan_retval) ) \n" + " (if (expression bool < (var_ref x) (constant float (0.000000)) ) (\n" + "\n" + "\n" + " (if (expression bool >= (var_ref y) (constant float (0.000000)) ) (\n" + " (declare ( ) float assignment_tmp)\n" + " (assign (constant bool (1)) (var_ref assignment_tmp) (expression float + (var_ref r) (constant float (3.141593)) ) ) \n" + " (assign (constant bool (1)) (var_ref r) (var_ref assignment_tmp) ) \n" + " )\n" + " (\n" + " (declare ( ) float assignment_tmp)\n" + " (assign (constant bool (1)) (var_ref assignment_tmp) (expression float - (var_ref r) (constant float (3.141593)) ) ) \n" + " (assign (constant bool (1)) (var_ref r) (var_ref assignment_tmp) ) \n" + " ))\n" + "\n" + " )\n" + " (\n" + " ))\n" + "\n" + " )\n" + " (\n" + "\n" + " (declare () float sgn)\n" + " (assign (constant bool (1)) (var_ref sgn) (expression float sign (var_ref y)))\n" + " (assign (constant bool (1)) (var_ref r) (expression float * (var_ref sgn) (constant float (1.5707965))))\n" + "\n" + " ))\n" + "\n" + " (return (var_ref r) )\n" + " ))\n" + "\n" + "\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 x))\n" + " ((declare () vec2 r)\n" + " (assign (constant bool (1))\n" + " (swiz x (var_ref r))\n" + " (call atan ((swiz x (var_ref y))\n" + " (swiz x (var_ref x)))))\n" + " (assign (constant bool (1))\n" + " (swiz y (var_ref r))\n" + " (call atan ((swiz y (var_ref y))\n" + " (swiz y (var_ref x)))))\n" + " (return (var_ref r))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 x))\n" + " ((declare () vec3 r)\n" + " (assign (constant bool (1))\n" + " (swiz x (var_ref r))\n" + " (call atan ((swiz x (var_ref y))\n" + " (swiz x (var_ref x)))))\n" + " (assign (constant bool (1))\n" + " (swiz y (var_ref r))\n" + " (call atan ((swiz y (var_ref y))\n" + " (swiz y (var_ref x)))))\n" + " (assign (constant bool (1))\n" + " (swiz z (var_ref r))\n" + " (call atan ((swiz z (var_ref y))\n" + " (swiz z (var_ref x)))))\n" + " (return (var_ref r))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 x))\n" + " ((declare () vec4 r)\n" + " (assign (constant bool (1))\n" + " (swiz x (var_ref r))\n" + " (call atan ((swiz x (var_ref y))\n" + " (swiz x (var_ref x)))))\n" + " (assign (constant bool (1))\n" + " (swiz y (var_ref r))\n" + " (call atan ((swiz y (var_ref y))\n" + " (swiz y (var_ref x)))))\n" + " (assign (constant bool (1))\n" + " (swiz z (var_ref r))\n" + " (call atan ((swiz z (var_ref y))\n" + " (swiz z (var_ref x)))))\n" + " (assign (constant bool (1))\n" + " (swiz w (var_ref r))\n" + " (call atan ((swiz w (var_ref y))\n" + " (swiz w (var_ref x)))))\n" + " (return (var_ref r)))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_ceil = + "((function ceil\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float ceil (var_ref arg0)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 ceil (var_ref arg0)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 ceil (var_ref arg0)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 ceil (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_clamp = + "((function clamp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0)\n" + " (declare (in) float arg1)\n" + " (declare (in) float arg2))\n" + " ((return (expression float max (expression float min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1)\n" + " (declare (in) vec2 arg2))\n" + " ((return (expression vec2 max (expression vec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1)\n" + " (declare (in) vec3 arg2))\n" + " ((return (expression vec3 max (expression vec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1)\n" + " (declare (in) vec4 arg2))\n" + " ((return (expression vec4 max (expression vec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) float arg1)\n" + " (declare (in) float arg2))\n" + " ((return (expression vec2 max (expression vec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) float arg1)\n" + " (declare (in) float arg2))\n" + " ((return (expression vec3 max (expression vec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) float arg1)\n" + " (declare (in) float arg2))\n" + " ((return (expression vec4 max (expression vec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int arg0)\n" + " (declare (in) int arg1)\n" + " (declare (in) int arg2))\n" + " ((return (expression int max (expression int min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) ivec2 arg1)\n" + " (declare (in) ivec2 arg2))\n" + " ((return (expression ivec2 max (expression ivec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) ivec3 arg1)\n" + " (declare (in) ivec3 arg2))\n" + " ((return (expression ivec3 max (expression ivec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) ivec4 arg1)\n" + " (declare (in) ivec4 arg2))\n" + " ((return (expression ivec4 max (expression ivec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) int arg1)\n" + " (declare (in) int arg2))\n" + " ((return (expression ivec2 max (expression ivec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) int arg1)\n" + " (declare (in) int arg2))\n" + " ((return (expression ivec3 max (expression ivec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) int arg1)\n" + " (declare (in) int arg2))\n" + " ((return (expression ivec4 max (expression ivec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature uint\n" + " (parameters\n" + " (declare (in) uint arg0)\n" + " (declare (in) uint arg1)\n" + " (declare (in) uint arg2))\n" + " ((return (expression uint max (expression uint min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uvec2 arg1)\n" + " (declare (in) uvec2 arg2))\n" + " ((return (expression uvec2 max (expression uvec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uvec3 arg1)\n" + " (declare (in) uvec3 arg2))\n" + " ((return (expression uvec3 max (expression uvec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uvec4 arg1)\n" + " (declare (in) uvec4 arg2))\n" + " ((return (expression uvec4 max (expression uvec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uint arg1)\n" + " (declare (in) uint arg2))\n" + " ((return (expression uvec2 max (expression uvec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uint arg1)\n" + " (declare (in) uint arg2))\n" + " ((return (expression uvec3 max (expression uvec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uint arg1)\n" + " (declare (in) uint arg2))\n" + " ((return (expression uvec4 max (expression uvec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1)))))\n" + "))\n" + "" +; +static const char *builtin_cos = + "((function cos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ((return (expression float cos (var_ref angle)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ((return (expression vec2 cos (var_ref angle)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ((return (expression vec3 cos (var_ref angle)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ((return (expression vec4 cos (var_ref angle)))))\n" + "))\n" + "" +; +static const char *builtin_cosh = + "((function cosh\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (expression float * (constant float (0.5))\n" + " (expression float +\n" + " (expression float exp (var_ref x))\n" + " (expression float exp (expression float neg (var_ref x))))))))\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (expression vec2 * (constant vec2 (0.5))\n" + " (expression vec2 +\n" + " (expression vec2 exp (var_ref x))\n" + " (expression vec2 exp (expression vec2 neg (var_ref x))))))))\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (expression vec3 * (constant vec3 (0.5))\n" + " (expression vec3 +\n" + " (expression vec3 exp (var_ref x))\n" + " (expression vec3 exp (expression vec3 neg (var_ref x))))))))\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (expression vec4 * (constant vec4 (0.5))\n" + " (expression vec4 +\n" + " (expression vec4 exp (var_ref x))\n" + " (expression vec4 exp (expression vec4 neg (var_ref x))))))))\n" + "))\n" + "" +; +static const char *builtin_cross = + "((function cross\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((return (expression vec3 cross (var_ref arg0) (var_ref arg1)))))\n" + "))\n" + "" +; +static const char *builtin_dFdx = + "((function dFdx\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ((return (expression float dFdx (var_ref p)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ((return (expression vec2 dFdx (var_ref p)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ((return (expression vec3 dFdx (var_ref p)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ((return (expression vec4 dFdx (var_ref p)))))\n" + "))\n" + "" +; +static const char *builtin_dFdy = + "((function dFdy\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ((return (expression float dFdy (var_ref p)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ((return (expression vec2 dFdy (var_ref p)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ((return (expression vec3 dFdy (var_ref p)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ((return (expression vec4 dFdy (var_ref p)))))\n" + "))\n" + "" +; +static const char *builtin_degrees = + "((function degrees\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float * (var_ref arg0) (constant float (57.295780))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 * (var_ref arg0) (constant float (57.295780))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 * (var_ref arg0) (constant float (57.295780))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 * (var_ref arg0) (constant float (57.295780))))))\n" + "))\n" + "" +; +static const char *builtin_distance = + "((function distance\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p0)\n" + " (declare (in) float p1))\n" + " ((declare () float p)\n" + " (assign (constant bool (1)) (var_ref p) (expression float - (var_ref p0) (var_ref p1)))\n" + " (return (expression float sqrt (expression float dot (var_ref p) (var_ref p))))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 p0)\n" + " (declare (in) vec2 p1))\n" + " ((declare () vec2 p)\n" + " (assign (constant bool (1)) (var_ref p) (expression vec2 - (var_ref p0) (var_ref p1)))\n" + " (return (expression float sqrt (expression float dot (var_ref p) (var_ref p))))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 p0)\n" + " (declare (in) vec3 p1))\n" + " ((declare () vec3 p)\n" + " (assign (constant bool (1)) (var_ref p) (expression vec3 - (var_ref p0) (var_ref p1)))\n" + " (return (expression float sqrt (expression float dot (var_ref p) (var_ref p))))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 p0)\n" + " (declare (in) vec4 p1))\n" + " ((declare () vec4 p)\n" + " (assign (constant bool (1)) (var_ref p) (expression vec4 - (var_ref p0) (var_ref p1)))\n" + " (return (expression float sqrt (expression float dot (var_ref p) (var_ref p))))))\n" + "))\n" + "" +; +static const char *builtin_dot = + "((function dot\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression float dot (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((return (expression float dot (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((return (expression float dot (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((return (expression float dot (var_ref arg0) (var_ref arg1)))))\n" + "))\n" + "" +; +static const char *builtin_equal = + "((function equal\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool == (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 arg0)\n" + " (declare (in) bvec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 arg0)\n" + " (declare (in) bvec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 arg0)\n" + " (declare (in) bvec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool == (swiz w (var_ref arg0))(swiz w (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) ivec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) ivec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) ivec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool == (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uvec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uvec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uvec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool == (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "))\n" + "" +; +static const char *builtin_exp = + "((function exp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float exp (var_ref arg0)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 exp (var_ref arg0)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 exp (var_ref arg0)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 exp (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_exp2 = + "((function exp2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float exp2 (var_ref arg0)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 exp2 (var_ref arg0)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 exp2 (var_ref arg0)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 exp2 (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_faceforward = + "((function faceforward\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float N)\n" + " (declare (in) float I)\n" + " (declare (in) float Nref))\n" + " ((if (expression bool < (expression float dot (var_ref Nref) (var_ref I)) (constant float (0)))\n" + " ((return (var_ref N)))\n" + " ((return (expression float neg (var_ref N)))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 N)\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 Nref))\n" + " ((if (expression bool < (expression float dot (var_ref Nref) (var_ref I)) (constant float (0)))\n" + " ((return (var_ref N)))\n" + " ((return (expression vec2 neg (var_ref N)))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 N)\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 Nref))\n" + " ((if (expression bool < (expression float dot (var_ref Nref) (var_ref I)) (constant float (0)))\n" + " ((return (var_ref N)))\n" + " ((return (expression vec3 neg (var_ref N)))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 N)\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 Nref))\n" + " ((if (expression bool < (expression float dot (var_ref Nref) (var_ref I)) (constant float (0)))\n" + " ((return (var_ref N)))\n" + " ((return (expression vec4 neg (var_ref N)))))))\n" + "))\n" + "" +; +static const char *builtin_floor = + "((function floor\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float floor (var_ref arg0)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 floor (var_ref arg0)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 floor (var_ref arg0)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 floor (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_fract = + "((function fract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (expression float fract (var_ref x)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (expression vec2 fract (var_ref x)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (expression vec3 fract (var_ref x)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (expression vec4 fract (var_ref x)))))\n" + "))\n" + "\n" + "" +; +static const char *builtin_ftransform = + "((declare (uniform) mat4 gl_ModelViewProjectionMatrix)\n" + " (declare (in) vec4 gl_Vertex)\n" + " (function ftransform\n" + " (signature vec4\n" + " (parameters)\n" + " ((return (expression vec4 *\n" + " (var_ref gl_ModelViewProjectionMatrix)\n" + " (var_ref gl_Vertex)))))\n" + "))\n" + "" +; +static const char *builtin_fwidth = + "((function fwidth\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ((return (expression float +\n" + " (expression float abs (expression float dFdx (var_ref p)))\n" + " (expression float abs (expression float dFdy (var_ref p)))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ((return (expression vec2 +\n" + " (expression vec2 abs (expression vec2 dFdx (var_ref p)))\n" + " (expression vec2 abs (expression vec2 dFdy (var_ref p)))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ((return (expression vec3 +\n" + " (expression vec3 abs (expression vec3 dFdx (var_ref p)))\n" + " (expression vec3 abs (expression vec3 dFdy (var_ref p)))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ((return (expression vec4 +\n" + " (expression vec4 abs (expression vec4 dFdx (var_ref p)))\n" + " (expression vec4 abs (expression vec4 dFdy (var_ref p)))))))\n" + "))\n" + "" +; +static const char *builtin_greaterThan = + "((function greaterThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool > (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) ivec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) ivec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) ivec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool > (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uvec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uvec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uvec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool > (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "))\n" + "" +; +static const char *builtin_greaterThanEqual = + "((function greaterThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool >= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) ivec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) ivec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) ivec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool >= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uvec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uvec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uvec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool >= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "))\n" + "" +; +static const char *builtin_inversesqrt = + "((function inversesqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float rsq (var_ref arg0)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 rsq (var_ref arg0)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 rsq (var_ref arg0)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 rsq (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_length = + "((function length\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float sqrt (expression float dot (var_ref arg0) (var_ref arg0))))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression float sqrt (expression float dot (var_ref arg0) (var_ref arg0))))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression float sqrt (expression float dot (var_ref arg0) (var_ref arg0))))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression float sqrt (expression float dot (var_ref arg0) (var_ref arg0))))))\n" + "))\n" + "" +; +static const char *builtin_lessThan = + "((function lessThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool < (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) ivec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) ivec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) ivec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool < (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uvec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uvec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uvec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool < (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "))\n" + "" +; +static const char *builtin_lessThanEqual = + "((function lessThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool <= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) ivec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) ivec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) ivec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool <= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uvec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uvec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uvec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool <= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "))\n" + "" +; +static const char *builtin_log = + "((function log\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float log (var_ref arg0)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 log (var_ref arg0)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 log (var_ref arg0)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 log (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_log2 = + "((function log2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float log2 (var_ref arg0)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 log2 (var_ref arg0)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 log2 (var_ref arg0)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 log2 (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_matrixCompMult = + "((function matrixCompMult\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 x)\n" + " (declare (in) mat2 y))\n" + " ((declare () mat2 z)\n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec2 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec2 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) \n" + "(return (var_ref z))))\n" + "\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 x)\n" + " (declare (in) mat3 y))\n" + " ((declare () mat3 z)\n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec3 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec3 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec3 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) \n" + "(return (var_ref z))))\n" + "\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 x)\n" + " (declare (in) mat4 y))\n" + " ((declare () mat4 z)\n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec4 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec4 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec4 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (3))) (expression vec4 * (array_ref (var_ref x) (constant int (3))) (array_ref (var_ref y) (constant int (3))))) \n" + "(return (var_ref z))))\n" + "\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat2x3 x)\n" + " (declare (in) mat2x3 y))\n" + " ((declare () mat2x3 z)\n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec3 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec3 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) \n" + "(return (var_ref z))))\n" + "\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat3x2 x)\n" + " (declare (in) mat3x2 y))\n" + " ((declare () mat3x2 z)\n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec2 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec2 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec2 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) \n" + "(return (var_ref z))))\n" + "\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat2x4 x)\n" + " (declare (in) mat2x4 y))\n" + " ((declare () mat2x4 z)\n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec4 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec4 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) \n" + "(return (var_ref z))))\n" + "\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat4x2 x)\n" + " (declare (in) mat4x2 y))\n" + " ((declare () mat4x2 z)\n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec2 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec2 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec2 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (3))) (expression vec2 * (array_ref (var_ref x) (constant int (3))) (array_ref (var_ref y) (constant int (3))))) \n" + "(return (var_ref z))))\n" + "\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat3x4 x)\n" + " (declare (in) mat3x4 y))\n" + " ((declare () mat3x4 z)\n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec4 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec4 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec4 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) \n" + "(return (var_ref z))))\n" + "\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat4x3 x)\n" + " (declare (in) mat4x3 y))\n" + " ((declare () mat4x3 z)\n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec3 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec3 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec3 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) \n" + " (assign (constant bool (1)) (array_ref (var_ref z) (constant int (3))) (expression vec3 * (array_ref (var_ref x) (constant int (3))) (array_ref (var_ref y) (constant int (3))))) \n" + "(return (var_ref z))))\n" + "))\n" + "" +; +static const char *builtin_max = + "((function max\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression float max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((return (expression vec2 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((return (expression vec3 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((return (expression vec4 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression vec2 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression vec3 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression vec4 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int arg0)\n" + " (declare (in) int arg1))\n" + " ((return (expression int max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) ivec2 arg1))\n" + " ((return (expression ivec2 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) ivec3 arg1))\n" + " ((return (expression ivec3 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) ivec4 arg1))\n" + " ((return (expression ivec4 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) int arg1))\n" + " ((return (expression ivec2 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) int arg1))\n" + " ((return (expression ivec3 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) int arg1))\n" + " ((return (expression ivec4 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uint\n" + " (parameters\n" + " (declare (in) uint arg0)\n" + " (declare (in) uint arg1))\n" + " ((return (expression uint max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uvec2 arg1))\n" + " ((return (expression uvec2 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uvec3 arg1))\n" + " ((return (expression uvec3 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uvec4 arg1))\n" + " ((return (expression uvec4 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uint arg1))\n" + " ((return (expression uvec2 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uint arg1))\n" + " ((return (expression uvec3 max (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uint arg1))\n" + " ((return (expression uvec4 max (var_ref arg0) (var_ref arg1)))))\n" + "))\n" + "" +; +static const char *builtin_min = + "((function min\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression float min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((return (expression vec2 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((return (expression vec3 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((return (expression vec4 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression vec2 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression vec3 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression vec4 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int arg0)\n" + " (declare (in) int arg1))\n" + " ((return (expression int min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) ivec2 arg1))\n" + " ((return (expression ivec2 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) ivec3 arg1))\n" + " ((return (expression ivec3 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) ivec4 arg1))\n" + " ((return (expression ivec4 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) int arg1))\n" + " ((return (expression ivec2 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) int arg1))\n" + " ((return (expression ivec3 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) int arg1))\n" + " ((return (expression ivec4 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uint\n" + " (parameters\n" + " (declare (in) uint arg0)\n" + " (declare (in) uint arg1))\n" + " ((return (expression uint min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uvec2 arg1))\n" + " ((return (expression uvec2 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uvec3 arg1))\n" + " ((return (expression uvec3 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uvec4 arg1))\n" + " ((return (expression uvec4 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uint arg1))\n" + " ((return (expression uvec2 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uint arg1))\n" + " ((return (expression uvec3 min (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uint arg1))\n" + " ((return (expression uvec4 min (var_ref arg0) (var_ref arg1)))))\n" + "))\n" + "" +; +static const char *builtin_mix = + "((function mix\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0)\n" + " (declare (in) float arg1)\n" + " (declare (in) float arg2))\n" + " ((return (expression float + (expression float * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression float * (var_ref arg1) (var_ref arg2))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1)\n" + " (declare (in) vec2 arg2))\n" + " ((return (expression vec2 + (expression vec2 * (var_ref arg0) (expression vec2 - (constant float (1.000000)) (var_ref arg2))) (expression vec2 * (var_ref arg1) (var_ref arg2))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1)\n" + " (declare (in) vec3 arg2))\n" + " ((return (expression vec3 + (expression vec3 * (var_ref arg0) (expression vec3 - (constant float (1.000000)) (var_ref arg2))) (expression vec3 * (var_ref arg1) (var_ref arg2))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1)\n" + " (declare (in) vec4 arg2))\n" + " ((return (expression vec4 + (expression vec4 * (var_ref arg0) (expression vec4 - (constant float (1.000000)) (var_ref arg2))) (expression vec4 * (var_ref arg1) (var_ref arg2))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1)\n" + " (declare (in) float arg2))\n" + " ((return (expression vec2 + (expression vec2 * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression vec2 * (var_ref arg1) (var_ref arg2))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1)\n" + " (declare (in) float arg2))\n" + " ((return (expression vec3 + (expression vec3 * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression vec3 * (var_ref arg1) (var_ref arg2))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1)\n" + " (declare (in) float arg2))\n" + " ((return (expression vec4 + (expression vec4 * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression vec4 * (var_ref arg1) (var_ref arg2))))))\n" + "\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float v1)\n" + " (declare (in) float v2)\n" + " (declare (in) bool a))\n" + " ((assign (var_ref a) (var_ref v1) (var_ref v2))\n" + " (return (var_ref v1))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 v1)\n" + " (declare (in) vec2 v2)\n" + " (declare (in) bvec2 a))\n" + " ((assign (swiz x (var_ref a)) (swiz x (var_ref v1)) (swiz x (var_ref v2)))\n" + " (assign (swiz y (var_ref a)) (swiz y (var_ref v1)) (swiz y (var_ref v2)))\n" + " (return (var_ref v1))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 v1)\n" + " (declare (in) vec3 v2)\n" + " (declare (in) bvec3 a))\n" + " ((assign (swiz x (var_ref a)) (swiz x (var_ref v1)) (swiz x (var_ref v2)))\n" + " (assign (swiz y (var_ref a)) (swiz y (var_ref v1)) (swiz y (var_ref v2)))\n" + " (assign (swiz z (var_ref a)) (swiz z (var_ref v1)) (swiz z (var_ref v2)))\n" + " (return (var_ref v1))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 v1)\n" + " (declare (in) vec4 v2)\n" + " (declare (in) bvec4 a))\n" + " ((assign (swiz x (var_ref a)) (swiz x (var_ref v1)) (swiz x (var_ref v2)))\n" + " (assign (swiz y (var_ref a)) (swiz y (var_ref v1)) (swiz y (var_ref v2)))\n" + " (assign (swiz z (var_ref a)) (swiz z (var_ref v1)) (swiz z (var_ref v2)))\n" + " (assign (swiz w (var_ref a)) (swiz w (var_ref v1)) (swiz w (var_ref v2)))\n" + " (return (var_ref v1))))\n" + "))\n" + "" +; +static const char *builtin_mod = + "((function mod\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression float % (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((return (expression vec2 % (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((return (expression vec3 % (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((return (expression vec4 % (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression vec2 % (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression vec3 % (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression vec4 % (var_ref arg0) (var_ref arg1)))))\n" + "))\n" + "" +; +static const char *builtin_noise1 = + "((function noise1\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (constant float (0)))))\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (constant float (0)))))\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (constant float (0)))))\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (constant float (0)))))\n" + "))\n" + "" +; +static const char *builtin_noise2 = + "((function noise2\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (constant vec2 (0 0)))))\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (constant vec2 (0 0)))))\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (constant vec2 (0 0)))))\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (constant vec2 (0 0)))))\n" + "))\n" + "" +; +static const char *builtin_noise3 = + "((function noise3\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (constant vec3 (0 0 0)))))\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (constant vec3 (0 0 0)))))\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (constant vec3 (0 0 0)))))\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (constant vec3 (0 0 0)))))\n" + "))\n" + "" +; +static const char *builtin_noise4 = + "((function noise4\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (constant vec4 (0 0 0 0)))))\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (constant vec4 (0 0 0 0)))))\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (constant vec4 (0 0 0 0)))))\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (constant vec4 (0 0 0 0)))))\n" + "))\n" + "" +; +static const char *builtin_normalize = + "((function normalize\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float * (var_ref arg0) (expression float rsq (expression float dot (var_ref arg0) (var_ref arg0)))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 * (var_ref arg0) (expression float rsq (expression float dot (var_ref arg0) (var_ref arg0)))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 * (var_ref arg0) (expression float rsq (expression float dot (var_ref arg0) (var_ref arg0)))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 * (var_ref arg0) (expression float rsq (expression float dot (var_ref arg0) (var_ref arg0)))))))\n" + "))\n" + "" +; +static const char *builtin_not = + "((function not\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 arg0))\n" + " ((return (expression bvec2 ! (var_ref arg0)))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 arg0))\n" + " ((return (expression bvec3 ! (var_ref arg0)))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 arg0))\n" + " ((return (expression bvec4 ! (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_notEqual = + "((function notEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool != (swiz w (var_ref arg0))(swiz w (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 arg0)\n" + " (declare (in) bvec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 arg0)\n" + " (declare (in) bvec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 arg0)\n" + " (declare (in) bvec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool != (swiz w (var_ref arg0))(swiz w (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 arg0)\n" + " (declare (in) ivec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 arg0)\n" + " (declare (in) ivec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 arg0)\n" + " (declare (in) ivec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1))))\n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool != (swiz w (var_ref arg0))(swiz w (var_ref arg1))))\n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 arg0)\n" + " (declare (in) uvec2 arg1))\n" + " ((declare () bvec2 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 arg0)\n" + " (declare (in) uvec3 arg1))\n" + " ((declare () bvec3 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 arg0)\n" + " (declare (in) uvec4 arg1))\n" + " ((declare () bvec4 temp)\n" + " (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) \n" + " (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool != (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) \n" + " (return (var_ref temp))))\n" + "))\n" + "" +; +static const char *builtin_outerProduct = + "((function outerProduct\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) vec2 u)\n" + " (declare (in) vec2 v))\n" + " ((declare () mat2 m)\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec2 * (var_ref u) (swiz x (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec2 * (var_ref u) (swiz y (var_ref v))))\n" + " (return (var_ref m))))\n" + "\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) vec3 u)\n" + " (declare (in) vec2 v))\n" + " ((declare () mat2x3 m)\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec3 * (var_ref u) (swiz x (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec3 * (var_ref u) (swiz y (var_ref v))))\n" + " (return (var_ref m))))\n" + "\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) vec4 u)\n" + " (declare (in) vec2 v))\n" + " ((declare () mat2x4 m)\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec4 * (var_ref u) (swiz x (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec4 * (var_ref u) (swiz y (var_ref v))))\n" + " (return (var_ref m))))\n" + "\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) vec2 u)\n" + " (declare (in) vec3 v))\n" + " ((declare () mat3x2 m)\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec2 * (var_ref u) (swiz x (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec2 * (var_ref u) (swiz y (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec2 * (var_ref u) (swiz z (var_ref v))))\n" + " (return (var_ref m))\n" + " ))\n" + "\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) vec3 u)\n" + " (declare (in) vec3 v))\n" + " ((declare () mat3 m)\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec3 * (var_ref u) (swiz x (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec3 * (var_ref u) (swiz y (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec3 * (var_ref u) (swiz z (var_ref v))))\n" + " (return (var_ref m))))\n" + "\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) vec4 u)\n" + " (declare (in) vec3 v))\n" + " ((declare () mat3x4 m)\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec4 * (var_ref u) (swiz x (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec4 * (var_ref u) (swiz y (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec4 * (var_ref u) (swiz z (var_ref v))))\n" + " (return (var_ref m))))\n" + "\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) vec2 u)\n" + " (declare (in) vec4 v))\n" + " ((declare () mat4x2 m)\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec2 * (var_ref u) (swiz x (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec2 * (var_ref u) (swiz y (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec2 * (var_ref u) (swiz z (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (3))) (expression vec2 * (var_ref u) (swiz w (var_ref v))))\n" + " (return (var_ref m))))\n" + "\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) vec3 u)\n" + " (declare (in) vec4 v))\n" + " ((declare () mat4x3 m)\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec3 * (var_ref u) (swiz x (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec3 * (var_ref u) (swiz y (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec3 * (var_ref u) (swiz z (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (3))) (expression vec3 * (var_ref u) (swiz w (var_ref v))))\n" + " (return (var_ref m))))\n" + "\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) vec4 u)\n" + " (declare (in) vec4 v))\n" + " ((declare () mat4 m)\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec4 * (var_ref u) (swiz x (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec4 * (var_ref u) (swiz y (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec4 * (var_ref u) (swiz z (var_ref v))))\n" + " (assign (constant bool (1)) (array_ref (var_ref m) (constant int (3))) (expression vec4 * (var_ref u) (swiz w (var_ref v))))\n" + " (return (var_ref m))))\n" + "))\n" + "" +; +static const char *builtin_pow = + "((function pow\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0)\n" + " (declare (in) float arg1))\n" + " ((return (expression float pow (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0)\n" + " (declare (in) vec2 arg1))\n" + " ((return (expression vec2 pow (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0)\n" + " (declare (in) vec3 arg1))\n" + " ((return (expression vec3 pow (var_ref arg0) (var_ref arg1)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0)\n" + " (declare (in) vec4 arg1))\n" + " ((return (expression vec4 pow (var_ref arg0) (var_ref arg1)))))\n" + "))\n" + "" +; +static const char *builtin_radians = + "((function radians\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float * (var_ref arg0) (constant float (0.017453))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 * (var_ref arg0) (constant float (0.017453))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 * (var_ref arg0) (constant float (0.017453))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 * (var_ref arg0) (constant float (0.017453))))))\n" + "))\n" + "" +; +static const char *builtin_reflect = + "((function reflect\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float i)\n" + " (declare (in) float n))\n" + " ((return (expression float -\n" + " (var_ref i)\n" + " (expression float *\n" + " (constant float (2.0))\n" + " (expression float *\n" + " (expression float dot\n" + " (var_ref n)\n" + " (var_ref i))\n" + " (var_ref n)))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 i)\n" + " (declare (in) vec2 n))\n" + " ((return (expression vec2 -\n" + " (var_ref i)\n" + " (expression vec2 *\n" + " (constant float (2.0))\n" + " (expression vec2 *\n" + " (expression float dot\n" + " (var_ref n)\n" + " (var_ref i))\n" + " (var_ref n)))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 i)\n" + " (declare (in) vec3 n))\n" + " ((return (expression vec3 -\n" + " (var_ref i)\n" + " (expression vec3 *\n" + " (constant float (2.0))\n" + " (expression vec3 *\n" + " (expression float dot\n" + " (var_ref n)\n" + " (var_ref i))\n" + " (var_ref n)))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 i)\n" + " (declare (in) vec4 n))\n" + " ((return (expression vec4 -\n" + " (var_ref i)\n" + " (expression vec4 *\n" + " (constant float (2.0))\n" + " (expression vec4 *\n" + " (expression float dot\n" + " (var_ref n)\n" + " (var_ref i))\n" + " (var_ref n)))))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_refract = + "((function refract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float i)\n" + " (declare (in) float n)\n" + " (declare (in) float eta))\n" + " ((declare () float k)\n" + " (assign (constant bool (1)) (var_ref k)\n" + " (expression float - (constant float (1.0))\n" + " (expression float * (var_ref eta)\n" + " (expression float * (var_ref eta)\n" + " (expression float - (constant float (1.0))\n" + " (expression float * \n" + " (expression float dot (var_ref n) (var_ref i))\n" + " (expression float dot (var_ref n) (var_ref i))))))))\n" + " (if (expression bool < (var_ref k) (constant float (0.0)))\n" + " ((return (constant float (0.0))))\n" + " ((return (expression float -\n" + " (expression float * (var_ref eta) (var_ref i))\n" + " (expression float *\n" + " (expression float +\n" + " (expression float * (var_ref eta)\n" + " (expression float dot (var_ref n) (var_ref i)))\n" + " (expression float sqrt (var_ref k)))\n" + " (var_ref n))))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 i)\n" + " (declare (in) vec2 n)\n" + " (declare (in) float eta))\n" + " ((declare () float k)\n" + " (assign (constant bool (1)) (var_ref k)\n" + " (expression float - (constant float (1.0))\n" + " (expression float * (var_ref eta)\n" + " (expression float * (var_ref eta)\n" + " (expression float - (constant float (1.0))\n" + " (expression float * \n" + " (expression float dot (var_ref n) (var_ref i))\n" + " (expression float dot (var_ref n) (var_ref i))))))))\n" + " (if (expression bool < (var_ref k) (constant float (0.0)))\n" + " ((return (constant vec2 (0.0 0.0))))\n" + " ((return (expression vec2 -\n" + " (expression vec2 * (var_ref eta) (var_ref i))\n" + " (expression vec2 *\n" + " (expression float +\n" + " (expression float * (var_ref eta)\n" + " (expression float dot (var_ref n) (var_ref i)))\n" + " (expression float sqrt (var_ref k)))\n" + " (var_ref n))))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 i)\n" + " (declare (in) vec3 n)\n" + " (declare (in) float eta))\n" + " ((declare () float k)\n" + " (assign (constant bool (1)) (var_ref k)\n" + " (expression float - (constant float (1.0))\n" + " (expression float * (var_ref eta)\n" + " (expression float * (var_ref eta)\n" + " (expression float - (constant float (1.0))\n" + " (expression float * \n" + " (expression float dot (var_ref n) (var_ref i))\n" + " (expression float dot (var_ref n) (var_ref i))))))))\n" + " (if (expression bool < (var_ref k) (constant float (0.0)))\n" + " ((return (constant vec3 (0.0 0.0 0.0))))\n" + " ((return (expression vec3 -\n" + " (expression vec3 * (var_ref eta) (var_ref i))\n" + " (expression vec3 *\n" + " (expression float +\n" + " (expression float * (var_ref eta)\n" + " (expression float dot (var_ref n) (var_ref i)))\n" + " (expression float sqrt (var_ref k)))\n" + " (var_ref n))))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 i)\n" + " (declare (in) vec4 n)\n" + " (declare (in) float eta))\n" + " ((declare () float k)\n" + " (assign (constant bool (1)) (var_ref k)\n" + " (expression float - (constant float (1.0))\n" + " (expression float * (var_ref eta)\n" + " (expression float * (var_ref eta)\n" + " (expression float - (constant float (1.0))\n" + " (expression float * \n" + " (expression float dot (var_ref n) (var_ref i))\n" + " (expression float dot (var_ref n) (var_ref i))))))))\n" + " (if (expression bool < (var_ref k) (constant float (0.0)))\n" + " ((return (constant vec4 (0.0 0.0 0.0 0.0))))\n" + " ((return (expression vec4 -\n" + " (expression vec4 * (var_ref eta) (var_ref i))\n" + " (expression vec4 *\n" + " (expression float +\n" + " (expression float * (var_ref eta)\n" + " (expression float dot (var_ref n) (var_ref i)))\n" + " (expression float sqrt (var_ref k)))\n" + " (var_ref n))))))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow1D = + "((function shadow1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow1DArray = + "((function shadow1DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow1DArrayLod = + "((function shadow1DArrayLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow1DLod = + "((function shadow1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow1DProj = + "((function shadow1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) (swiz z (var_ref P)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) (swiz z (var_ref P)) (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow1DProjLod = + "((function shadow1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) (swiz z (var_ref P)) (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow2D = + "((function shadow2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow2DArray = + "((function shadow2DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArrayShadow sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) 1 (swiz w (var_ref P)) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow2DLod = + "((function shadow2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow2DProj = + "((function shadow2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) (swiz z (var_ref P)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) (swiz z (var_ref P)) (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow2DProjLod = + "((function shadow2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) (swiz z (var_ref P)) (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow2DRect = + "((function shadow2DRect\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRectShadow sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) 1 (swiz z (var_ref P)) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_shadow2DRectProj = + "((function shadow2DRectProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRectShadow sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) (swiz z (var_ref P)) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_sign = + "((function sign\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (expression float sign (var_ref x)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (expression vec2 sign (var_ref x)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (expression vec3 sign (var_ref x)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (expression vec4 sign (var_ref x)))))\n" + "\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x))\n" + " ((return (expression int sign (var_ref x)))))\n" + "\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x))\n" + " ((return (expression ivec2 sign (var_ref x)))))\n" + "\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x))\n" + " ((return (expression ivec3 sign (var_ref x)))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x))\n" + " ((return (expression ivec4 sign (var_ref x)))))\n" + "))\n" + "\n" + "" +; +static const char *builtin_sin = + "((function sin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ((return (expression float sin (var_ref angle)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ((return (expression vec2 sin (var_ref angle)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ((return (expression vec3 sin (var_ref angle)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ((return (expression vec4 sin (var_ref angle)))))\n" + "))\n" + "" +; +static const char *builtin_sinh = + "((function sinh\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (expression float * (constant float (0.5))\n" + " (expression float -\n" + " (expression float exp (var_ref x))\n" + " (expression float exp (expression float neg (var_ref x))))))))\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (expression vec2 * (constant vec2 (0.5))\n" + " (expression vec2 -\n" + " (expression vec2 exp (var_ref x))\n" + " (expression vec2 exp (expression vec2 neg (var_ref x))))))))\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (expression vec3 * (constant vec3 (0.5))\n" + " (expression vec3 -\n" + " (expression vec3 exp (var_ref x))\n" + " (expression vec3 exp (expression vec3 neg (var_ref x))))))))\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (expression vec4 * (constant vec4 (0.5))\n" + " (expression vec4 -\n" + " (expression vec4 exp (var_ref x))\n" + " (expression vec4 exp (expression vec4 neg (var_ref x))))))))\n" + "))\n" + "" +; +static const char *builtin_smoothstep = + "((function smoothstep\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) float x))\n" + " ((declare () float t)\n" + "\n" + " (assign (constant bool (1)) (var_ref t)\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (var_ref x) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (return (expression float * (var_ref t) (expression float * (var_ref t) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (var_ref t))))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec2 x))\n" + " ((declare () vec2 t)\n" + " (declare () vec2 retval)\n" + "\n" + " (assign (constant bool (1)) (swiz x (var_ref t))\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (swiz x (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (assign (constant bool (1)) (swiz x (var_ref retval)) (expression float * (swiz x (var_ref t)) (expression float * (swiz x (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz x (var_ref t)))))))\n" + "\n" + " (assign (constant bool (1)) (swiz y (var_ref t))\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (swiz y (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (assign (constant bool (1)) (swiz y (var_ref retval)) (expression float * (swiz y (var_ref t)) (expression float * (swiz y (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz y (var_ref t)))))))\n" + " (return (var_ref retval))\n" + " ))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec3 x))\n" + " ((declare () vec3 t)\n" + " (declare () vec3 retval)\n" + "\n" + " (assign (constant bool (1)) (swiz x (var_ref t))\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (swiz x (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (assign (constant bool (1)) (swiz x (var_ref retval)) (expression float * (swiz x (var_ref t)) (expression float * (swiz x (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz x (var_ref t)))))))\n" + "\n" + " (assign (constant bool (1)) (swiz y (var_ref t))\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (swiz y (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (assign (constant bool (1)) (swiz y (var_ref retval)) (expression float * (swiz y (var_ref t)) (expression float * (swiz y (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz y (var_ref t)))))))\n" + "\n" + " (assign (constant bool (1)) (swiz z (var_ref t))\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (swiz z (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (assign (constant bool (1)) (swiz z (var_ref retval)) (expression float * (swiz z (var_ref t)) (expression float * (swiz z (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz z (var_ref t)))))))\n" + " (return (var_ref retval))\n" + " ))\n" + "\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec4 x))\n" + " ((declare () vec4 t)\n" + " (declare () vec4 retval)\n" + "\n" + " (assign (constant bool (1)) (swiz x (var_ref t))\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (swiz x (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (assign (constant bool (1)) (swiz x (var_ref retval)) (expression float * (swiz x (var_ref t)) (expression float * (swiz x (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz x (var_ref t)))))))\n" + "\n" + " (assign (constant bool (1)) (swiz y (var_ref t))\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (swiz y (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (assign (constant bool (1)) (swiz y (var_ref retval)) (expression float * (swiz y (var_ref t)) (expression float * (swiz y (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz y (var_ref t)))))))\n" + "\n" + " (assign (constant bool (1)) (swiz z (var_ref t))\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (swiz z (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (assign (constant bool (1)) (swiz z (var_ref retval)) (expression float * (swiz z (var_ref t)) (expression float * (swiz z (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz z (var_ref t)))))))\n" + "\n" + " (assign (constant bool (1)) (swiz w (var_ref t))\n" + " (expression float max\n" + " (expression float min\n" + " (expression float / (expression float - (swiz w (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0)))\n" + " (constant float (1.0)))\n" + " (constant float (0.0))))\n" + " (assign (constant bool (1)) (swiz w (var_ref retval)) (expression float * (swiz w (var_ref t)) (expression float * (swiz w (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz w (var_ref t)))))))\n" + " (return (var_ref retval))\n" + " ))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge0)\n" + " (declare (in) vec2 edge1)\n" + " (declare (in) vec2 x))\n" + " ((return (expression vec2 max\n" + " (expression vec2 min\n" + " (expression vec2 / (expression vec2 - (var_ref x) (var_ref edge0)) (expression vec2 - (var_ref edge1) (var_ref edge0)))\n" + " (constant vec2 (1.0 1.0)))\n" + " (constant vec2 (0.0 0.0))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge0)\n" + " (declare (in) vec3 edge1)\n" + " (declare (in) vec3 x))\n" + " ((return (expression vec3 max\n" + " (expression vec3 min\n" + " (expression vec3 / (expression vec3 - (var_ref x) (var_ref edge0)) (expression vec3 - (var_ref edge1) (var_ref edge0)))\n" + " (constant vec3 (1.0 1.0 1.0)))\n" + " (constant vec3 (0.0 0.0 0.0))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge0)\n" + " (declare (in) vec4 edge1)\n" + " (declare (in) vec4 x))\n" + " ((return (expression vec4 max\n" + " (expression vec4 min\n" + " (expression vec4 / (expression vec4 - (var_ref x) (var_ref edge0)) (expression vec4 - (var_ref edge1) (var_ref edge0)))\n" + " (constant vec4 (1.0 1.0 1.0 1.0)))\n" + " (constant vec4 (0.0 0.0 0.0 0.0))))))\n" + "))\n" + "\n" + "" +; +static const char *builtin_sqrt = + "((function sqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float arg0))\n" + " ((return (expression float sqrt (var_ref arg0)))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 arg0))\n" + " ((return (expression vec2 sqrt (var_ref arg0)))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 arg0))\n" + " ((return (expression vec3 sqrt (var_ref arg0)))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 arg0))\n" + " ((return (expression vec4 sqrt (var_ref arg0)))))\n" + "))\n" + "" +; +static const char *builtin_step = + "((function step\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) float x))\n" + " ((return (expression float b2f (expression bool >= (var_ref x) (var_ref edge))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec2 x))\n" + " ((declare () vec2 t)\n" + " (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(var_ref edge))))\n" + " (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(var_ref edge))))\n" + " (return (var_ref t))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec3 x))\n" + " ((declare () vec3 t)\n" + " (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(var_ref edge))))\n" + " (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(var_ref edge))))\n" + " (assign (constant bool (1)) (swiz z (var_ref t)) (expression float b2f (expression bool >= (swiz z (var_ref x))(var_ref edge))))\n" + " (return (var_ref t))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec4 x))\n" + " ((declare () vec4 t)\n" + " (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(var_ref edge))))\n" + " (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(var_ref edge))))\n" + " (assign (constant bool (1)) (swiz z (var_ref t)) (expression float b2f (expression bool >= (swiz z (var_ref x))(var_ref edge))))\n" + " (assign (constant bool (1)) (swiz w (var_ref t)) (expression float b2f (expression bool >= (swiz w (var_ref x))(var_ref edge))))\n" + " (return (var_ref t))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge)\n" + " (declare (in) vec2 x))\n" + " ((declare () vec2 t)\n" + " (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(swiz x (var_ref edge)))))\n" + " (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(swiz y (var_ref edge)))))\n" + " (return (var_ref t))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge)\n" + " (declare (in) vec3 x))\n" + " ((declare () vec3 t)\n" + " (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(swiz x (var_ref edge)))))\n" + " (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(swiz y (var_ref edge)))))\n" + " (assign (constant bool (1)) (swiz z (var_ref t)) (expression float b2f (expression bool >= (swiz z (var_ref x))(swiz z (var_ref edge)))))\n" + " (return (var_ref t))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge)\n" + " (declare (in) vec4 x))\n" + " ((declare () vec4 t)\n" + " (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(swiz x (var_ref edge)))))\n" + " (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(swiz y (var_ref edge)))))\n" + " (assign (constant bool (1)) (swiz z (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(swiz z (var_ref edge)))))\n" + " (assign (constant bool (1)) (swiz w (var_ref t)) (expression float b2f (expression bool >= (swiz w (var_ref x))(swiz w (var_ref edge)))))\n" + " (return (var_ref t))))\n" + "))\n" + "\n" + "" +; +static const char *builtin_tan = + "((function tan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ((return (expression float / (expression float sin (var_ref angle)) (expression float cos (var_ref angle))))))\n" + "\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ((return (expression vec2 / (expression vec2 sin (var_ref angle)) (expression vec2 cos (var_ref angle))))))\n" + "\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ((return (expression vec3 / (expression vec3 sin (var_ref angle)) (expression vec3 cos (var_ref angle))))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ((return (expression vec4 / (expression vec4 sin (var_ref angle)) (expression vec4 cos (var_ref angle))))))\n" + "))\n" + "" +; +static const char *builtin_tanh = + "((function tanh\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ((return (expression float /\n" + " (expression float -\n" + " (expression float exp (var_ref x))\n" + " (expression float exp (expression float neg (var_ref x))))\n" + " (expression float +\n" + " (expression float exp (var_ref x))\n" + " (expression float exp (expression float neg (var_ref x))))))))\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ((return (expression vec2 /\n" + " (expression vec2 -\n" + " (expression vec2 exp (var_ref x))\n" + " (expression vec2 exp (expression vec2 neg (var_ref x))))\n" + " (expression vec2 +\n" + " (expression vec2 exp (var_ref x))\n" + " (expression vec2 exp (expression vec2 neg (var_ref x))))))))\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ((return (expression vec3 /\n" + " (expression vec3 -\n" + " (expression vec3 exp (var_ref x))\n" + " (expression vec3 exp (expression vec3 neg (var_ref x))))\n" + " (expression vec3 +\n" + " (expression vec3 exp (var_ref x))\n" + " (expression vec3 exp (expression vec3 neg (var_ref x))))))))\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ((return (expression vec4 /\n" + " (expression vec4 -\n" + " (expression vec4 exp (var_ref x))\n" + " (expression vec4 exp (expression vec4 neg (var_ref x))))\n" + " (expression vec4 +\n" + " (expression vec4 exp (var_ref x))\n" + " (expression vec4 exp (expression vec4 neg (var_ref x))))))))\n" + "))\n" + "" +; +static const char *builtin_texelFetch = + "((function texelFetch\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) int P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) int P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) int P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) ivec2 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) ivec2 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) ivec2 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) ivec3 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) ivec3 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) ivec3 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) ivec2 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) ivec2 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) ivec2 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) ivec3 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) ivec3 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) ivec3 P) \n" + " (declare (in) int lod) )\n" + " ((return (txf (var_ref sampler) (var_ref P) (0 0 0) (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture = + "((function texture\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture1D = + "((function texture1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture1DArray = + "((function texture1DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture1DArrayLod = + "((function texture1DArrayLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture1DLod = + "((function texture1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture1DProj = + "((function texture1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture1DProjLod = + "((function texture1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture2D = + "((function texture2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture2DArray = + "((function texture2DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture2DArrayLod = + "((function texture2DArrayLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture2DLod = + "((function texture2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture2DProj = + "((function texture2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture2DProjLod = + "((function texture2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture2DRect = + "((function texture2DRect\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRect sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture2DRectProj = + "((function texture2DRectProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRect sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRect sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture3D = + "((function texture3D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture3DLod = + "((function texture3DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture3DProj = + "((function texture3DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_texture3DProjLod = + "((function texture3DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_textureCube = + "((function textureCube\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (var_ref P) (0 0 0) 1 () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_textureCubeLod = + "((function textureCubeLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_textureGrad = + "((function textureGrad\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float dPdx) \n" + " (declare (in) float dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float dPdx) \n" + " (declare (in) float dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float dPdx) \n" + " (declare (in) float dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (var_ref P) (0 0 0) 1 () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_textureLod = + "((function textureLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (var_ref P) (0 0 0) 1 () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_textureProj = + "((function textureProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P) )\n" + " ((return (tex (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float bias) )\n" + " ((return (txb (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref bias) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_textureProjGrad = + "((function textureProjGrad\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float dPdx) \n" + " (declare (in) float dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float dPdx) \n" + " (declare (in) float dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float dPdx) \n" + " (declare (in) float dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float dPdx) \n" + " (declare (in) float dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float dPdx) \n" + " (declare (in) float dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float dPdx) \n" + " (declare (in) float dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) vec2 dPdx) \n" + " (declare (in) vec2 dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) vec3 dPdx) \n" + " (declare (in) vec3 dPdy) )\n" + " ((return (txd (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () ((var_ref dPdx) (var_ref dPdy)) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_textureProjLod = + "((function textureProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz y (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz x (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz z (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xy (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P) \n" + " (declare (in) float lod) )\n" + " ((return (txl (var_ref sampler) (swiz xyz (var_ref P)) (0 0 0) (swiz w (var_ref P)) () (var_ref lod) ))))\n" + "\n" + "))\n" + "" +; +static const char *builtin_transpose = + "((function transpose\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 m))\n" + " ((declare () mat2 t)\n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) \n" + "(return (var_ref t))))\n" + "\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat2x3 m))\n" + " ((declare () mat3x2 t)\n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) \n" + "(return (var_ref t))))\n" + "\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat2x4 m))\n" + " ((declare () mat4x2 t)\n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (1))))) \n" + "(return (var_ref t))))\n" + "\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat3x2 m))\n" + " ((declare () mat2x3 t)\n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) \n" + "(return (var_ref t))))\n" + "\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 m))\n" + " ((declare () mat3 t)\n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (2))))) \n" + "(return (var_ref t))))\n" + "\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat3x4 m))\n" + " ((declare () mat4x3 t)\n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (2))))) \n" + "(return (var_ref t))))\n" + "\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat4x2 m))\n" + " ((declare () mat2x4 t)\n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (3))))) \n" + " (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (3))))) \n" + "(return (var_ref t))))\n" + "\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat4x3 m))\n" + " ((declare () mat3x4 t)\n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (3))))) \n" + " (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (3))))) \n" + " (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (3))))) \n" + "(return (var_ref t))))\n" + "\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 m))\n" + " ((declare () mat4 t)\n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (0))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (1))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (2))))) \n" + " (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (3))))) \n" + " (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (3))))) \n" + " (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (3))))) \n" + " (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (3))))) \n" + "(return (var_ref t))))\n" + ")\n" + "\n" + ")\n" + "\n" + "" +; +static const char *prototypes_for_110_frag = + "(\n" + "(function radians\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float degrees))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 degrees))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 degrees))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 degrees))\n" + " ()))\n" + "(function degrees\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float radians))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 radians))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 radians))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 radians))\n" + " ()))\n" + "(function sin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function cos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function tan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function asin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function acos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function atan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y_over_x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y_over_x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y_over_x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y_over_x))\n" + " ()))\n" + "(function pow\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function exp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function exp2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function inversesqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function abs\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sign\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function floor\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function ceil\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function fract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function mod\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function min\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ()))\n" + "(function max\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ()))\n" + "(function clamp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 minVal)\n" + " (declare (in) vec2 maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 minVal)\n" + " (declare (in) vec3 maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 minVal)\n" + " (declare (in) vec4 maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ()))\n" + "(function mix\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) float a))\n" + " ()))\n" + "(function step\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function smoothstep\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge0)\n" + " (declare (in) vec2 edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge0)\n" + " (declare (in) vec3 edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge0)\n" + " (declare (in) vec4 edge1)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function length\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function distance\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p0)\n" + " (declare (in) float p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 p0)\n" + " (declare (in) vec2 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 p0)\n" + " (declare (in) vec3 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 p0)\n" + " (declare (in) vec4 p1))\n" + " ()))\n" + "(function dot\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function cross\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ()))\n" + "(function normalize\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function faceforward\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float N)\n" + " (declare (in) float I)\n" + " (declare (in) float Nref))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 N)\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 Nref))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 N)\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 Nref))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 N)\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 Nref))\n" + " ()))\n" + "(function reflect\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N))\n" + " ()))\n" + "(function refract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N)\n" + " (declare (in) float eta))\n" + " ()))\n" + "(function matrixCompMult\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 x)\n" + " (declare (in) mat2 y))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 x)\n" + " (declare (in) mat3 y))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 x)\n" + " (declare (in) mat4 y))\n" + " ()))\n" + "(function lessThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function lessThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function greaterThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function greaterThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function equal\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function notEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function any\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function all\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function not\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function texture1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture3D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture3DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function textureCube\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function dFdx\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ()))\n" + "(function dFdy\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ()))\n" + "(function fwidth\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ()))\n" + "(function noise1\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise2\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise3\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise4\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())))" +; +static const char *functions_for_110_frag [] = { + builtin_abs, + builtin_acos, + builtin_all, + builtin_any, + builtin_asin, + builtin_atan, + builtin_ceil, + builtin_clamp, + builtin_cos, + builtin_cross, + builtin_dFdx, + builtin_dFdy, + builtin_degrees, + builtin_distance, + builtin_dot, + builtin_equal, + builtin_exp, + builtin_exp2, + builtin_faceforward, + builtin_floor, + builtin_fract, + builtin_fwidth, + builtin_greaterThan, + builtin_greaterThanEqual, + builtin_inversesqrt, + builtin_length, + builtin_lessThan, + builtin_lessThanEqual, + builtin_log, + builtin_log2, + builtin_matrixCompMult, + builtin_max, + builtin_min, + builtin_mix, + builtin_mod, + builtin_noise1, + builtin_noise2, + builtin_noise3, + builtin_noise4, + builtin_normalize, + builtin_not, + builtin_notEqual, + builtin_pow, + builtin_radians, + builtin_reflect, + builtin_refract, + builtin_shadow1D, + builtin_shadow1DProj, + builtin_shadow2D, + builtin_shadow2DProj, + builtin_sign, + builtin_sin, + builtin_smoothstep, + builtin_sqrt, + builtin_step, + builtin_tan, + builtin_texture1D, + builtin_texture1DProj, + builtin_texture2D, + builtin_texture2DProj, + builtin_texture3D, + builtin_texture3DProj, + builtin_textureCube, +}; +static const char *prototypes_for_110_vert = + "(\n" + "(function radians\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float degrees))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 degrees))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 degrees))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 degrees))\n" + " ()))\n" + "(function degrees\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float radians))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 radians))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 radians))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 radians))\n" + " ()))\n" + "(function sin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function cos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function tan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function asin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function acos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function atan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y_over_x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y_over_x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y_over_x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y_over_x))\n" + " ()))\n" + "(function pow\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function exp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function exp2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function inversesqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function abs\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sign\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function floor\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function ceil\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function fract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function mod\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function min\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ()))\n" + "(function max\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ()))\n" + "(function clamp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 minVal)\n" + " (declare (in) vec2 maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 minVal)\n" + " (declare (in) vec3 maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 minVal)\n" + " (declare (in) vec4 maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ()))\n" + "(function mix\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) float a))\n" + " ()))\n" + "(function step\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function smoothstep\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge0)\n" + " (declare (in) vec2 edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge0)\n" + " (declare (in) vec3 edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge0)\n" + " (declare (in) vec4 edge1)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function length\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function distance\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p0)\n" + " (declare (in) float p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 p0)\n" + " (declare (in) vec2 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 p0)\n" + " (declare (in) vec3 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 p0)\n" + " (declare (in) vec4 p1))\n" + " ()))\n" + "(function dot\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function cross\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ()))\n" + "(function normalize\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function ftransform\n" + " (signature vec4\n" + " (parameters)\n" + " ()))\n" + "(function faceforward\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float N)\n" + " (declare (in) float I)\n" + " (declare (in) float Nref))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 N)\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 Nref))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 N)\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 Nref))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 N)\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 Nref))\n" + " ()))\n" + "(function reflect\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N))\n" + " ()))\n" + "(function refract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N)\n" + " (declare (in) float eta))\n" + " ()))\n" + "(function matrixCompMult\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 x)\n" + " (declare (in) mat2 y))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 x)\n" + " (declare (in) mat3 y))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 x)\n" + " (declare (in) mat4 y))\n" + " ()))\n" + "(function lessThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function lessThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function greaterThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function greaterThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function equal\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function notEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function any\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function all\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function not\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function texture1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord))\n" + " ()))\n" + "(function texture1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function texture1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord))\n" + " ()))\n" + "(function texture2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function texture2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture3D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function texture3DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function texture3DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture3DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function textureCube\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function textureCubeLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function shadow2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function shadow1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function shadow2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function shadow1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function noise1\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise2\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise3\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise4\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())))" +; +static const char *functions_for_110_vert [] = { + builtin_abs, + builtin_acos, + builtin_all, + builtin_any, + builtin_asin, + builtin_atan, + builtin_ceil, + builtin_clamp, + builtin_cos, + builtin_cross, + builtin_degrees, + builtin_distance, + builtin_dot, + builtin_equal, + builtin_exp, + builtin_exp2, + builtin_faceforward, + builtin_floor, + builtin_fract, + builtin_ftransform, + builtin_greaterThan, + builtin_greaterThanEqual, + builtin_inversesqrt, + builtin_length, + builtin_lessThan, + builtin_lessThanEqual, + builtin_log, + builtin_log2, + builtin_matrixCompMult, + builtin_max, + builtin_min, + builtin_mix, + builtin_mod, + builtin_noise1, + builtin_noise2, + builtin_noise3, + builtin_noise4, + builtin_normalize, + builtin_not, + builtin_notEqual, + builtin_pow, + builtin_radians, + builtin_reflect, + builtin_refract, + builtin_shadow1D, + builtin_shadow1DLod, + builtin_shadow1DProj, + builtin_shadow1DProjLod, + builtin_shadow2D, + builtin_shadow2DLod, + builtin_shadow2DProj, + builtin_shadow2DProjLod, + builtin_sign, + builtin_sin, + builtin_smoothstep, + builtin_sqrt, + builtin_step, + builtin_tan, + builtin_texture1D, + builtin_texture1DLod, + builtin_texture1DProj, + builtin_texture1DProjLod, + builtin_texture2D, + builtin_texture2DLod, + builtin_texture2DProj, + builtin_texture2DProjLod, + builtin_texture3D, + builtin_texture3DLod, + builtin_texture3DProj, + builtin_texture3DProjLod, + builtin_textureCube, + builtin_textureCubeLod, +}; +static const char *prototypes_for_120_frag = + "(\n" + "(function radians\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float degrees))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 degrees))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 degrees))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 degrees))\n" + " ()))\n" + "(function degrees\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float radians))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 radians))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 radians))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 radians))\n" + " ()))\n" + "(function sin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function cos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function tan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function asin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function acos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function atan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y_over_x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y_over_x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y_over_x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y_over_x))\n" + " ()))\n" + "(function pow\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function exp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function exp2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function inversesqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function abs\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sign\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function floor\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function ceil\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function fract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function mod\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function min\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ()))\n" + "(function max\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ()))\n" + "(function clamp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 minVal)\n" + " (declare (in) vec2 maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 minVal)\n" + " (declare (in) vec3 maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 minVal)\n" + " (declare (in) vec4 maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ()))\n" + "(function mix\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) float a))\n" + " ()))\n" + "(function step\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function smoothstep\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge0)\n" + " (declare (in) vec2 edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge0)\n" + " (declare (in) vec3 edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge0)\n" + " (declare (in) vec4 edge1)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function length\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function distance\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p0)\n" + " (declare (in) float p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 p0)\n" + " (declare (in) vec2 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 p0)\n" + " (declare (in) vec3 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 p0)\n" + " (declare (in) vec4 p1))\n" + " ()))\n" + "(function dot\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function cross\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ()))\n" + "(function normalize\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function faceforward\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float N)\n" + " (declare (in) float I)\n" + " (declare (in) float Nref))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 N)\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 Nref))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 N)\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 Nref))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 N)\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 Nref))\n" + " ()))\n" + "(function reflect\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N))\n" + " ()))\n" + "(function refract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N)\n" + " (declare (in) float eta))\n" + " ()))\n" + "(function matrixCompMult\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 x)\n" + " (declare (in) mat2 y))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 x)\n" + " (declare (in) mat3 y))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 x)\n" + " (declare (in) mat4 y))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat2x3 x)\n" + " (declare (in) mat2x3 y))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat2x4 x)\n" + " (declare (in) mat2x4 y))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat3x2 x)\n" + " (declare (in) mat3x2 y))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat3x4 x)\n" + " (declare (in) mat3x4 y))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat4x2 x)\n" + " (declare (in) mat4x2 y))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat4x3 x)\n" + " (declare (in) mat4x3 y))\n" + " ()))\n" + "(function outerProduct\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec4 r))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec4 r))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec4 r))\n" + " ()))\n" + "(function transpose\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 m))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 m))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 m))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat3x2 m))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat2x3 m))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat4x2 m))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat2x4 m))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat4x3 m))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat3x4 m))\n" + " ()))\n" + "(function lessThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function lessThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function greaterThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function greaterThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function equal\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function notEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function any\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function all\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function not\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function texture1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture3D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture3DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function textureCube\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function dFdx\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ()))\n" + "(function dFdy\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ()))\n" + "(function fwidth\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ()))\n" + "(function noise1\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise2\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise3\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise4\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())))" +; +static const char *functions_for_120_frag [] = { + builtin_abs, + builtin_acos, + builtin_all, + builtin_any, + builtin_asin, + builtin_atan, + builtin_ceil, + builtin_clamp, + builtin_cos, + builtin_cross, + builtin_dFdx, + builtin_dFdy, + builtin_degrees, + builtin_distance, + builtin_dot, + builtin_equal, + builtin_exp, + builtin_exp2, + builtin_faceforward, + builtin_floor, + builtin_fract, + builtin_fwidth, + builtin_greaterThan, + builtin_greaterThanEqual, + builtin_inversesqrt, + builtin_length, + builtin_lessThan, + builtin_lessThanEqual, + builtin_log, + builtin_log2, + builtin_matrixCompMult, + builtin_max, + builtin_min, + builtin_mix, + builtin_mod, + builtin_noise1, + builtin_noise2, + builtin_noise3, + builtin_noise4, + builtin_normalize, + builtin_not, + builtin_notEqual, + builtin_outerProduct, + builtin_pow, + builtin_radians, + builtin_reflect, + builtin_refract, + builtin_shadow1D, + builtin_shadow1DProj, + builtin_shadow2D, + builtin_shadow2DProj, + builtin_sign, + builtin_sin, + builtin_smoothstep, + builtin_sqrt, + builtin_step, + builtin_tan, + builtin_texture1D, + builtin_texture1DProj, + builtin_texture2D, + builtin_texture2DProj, + builtin_texture3D, + builtin_texture3DProj, + builtin_textureCube, + builtin_transpose, +}; +static const char *prototypes_for_120_vert = + "(\n" + "(function radians\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float degrees))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 degrees))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 degrees))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 degrees))\n" + " ()))\n" + "(function degrees\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float radians))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 radians))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 radians))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 radians))\n" + " ()))\n" + "(function sin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function cos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function tan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function asin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function acos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function atan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y_over_x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y_over_x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y_over_x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y_over_x))\n" + " ()))\n" + "(function pow\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function exp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function exp2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function inversesqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function abs\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sign\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function floor\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function ceil\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function fract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function mod\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function min\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ()))\n" + "(function max\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ()))\n" + "(function clamp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 minVal)\n" + " (declare (in) vec2 maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 minVal)\n" + " (declare (in) vec3 maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 minVal)\n" + " (declare (in) vec4 maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ()))\n" + "(function mix\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) float a))\n" + " ()))\n" + "(function step\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function smoothstep\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge0)\n" + " (declare (in) vec2 edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge0)\n" + " (declare (in) vec3 edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge0)\n" + " (declare (in) vec4 edge1)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function length\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function distance\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p0)\n" + " (declare (in) float p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 p0)\n" + " (declare (in) vec2 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 p0)\n" + " (declare (in) vec3 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 p0)\n" + " (declare (in) vec4 p1))\n" + " ()))\n" + "(function dot\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function cross\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ()))\n" + "(function normalize\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function ftransform\n" + " (signature vec4\n" + " (parameters)\n" + " ()))\n" + "(function faceforward\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float N)\n" + " (declare (in) float I)\n" + " (declare (in) float Nref))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 N)\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 Nref))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 N)\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 Nref))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 N)\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 Nref))\n" + " ()))\n" + "(function reflect\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N))\n" + " ()))\n" + "(function refract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N)\n" + " (declare (in) float eta))\n" + " ()))\n" + "(function matrixCompMult\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 x)\n" + " (declare (in) mat2 y))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 x)\n" + " (declare (in) mat3 y))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 x)\n" + " (declare (in) mat4 y))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat2x3 x)\n" + " (declare (in) mat2x3 y))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat2x4 x)\n" + " (declare (in) mat2x4 y))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat3x2 x)\n" + " (declare (in) mat3x2 y))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat3x4 x)\n" + " (declare (in) mat3x4 y))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat4x2 x)\n" + " (declare (in) mat4x2 y))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat4x3 x)\n" + " (declare (in) mat4x3 y))\n" + " ()))\n" + "(function outerProduct\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec4 r))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec4 r))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec4 r))\n" + " ()))\n" + "(function transpose\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 m))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 m))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 m))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat3x2 m))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat2x3 m))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat4x2 m))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat2x4 m))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat4x3 m))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat3x4 m))\n" + " ()))\n" + "(function lessThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function lessThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function greaterThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function greaterThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ()))\n" + "(function equal\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function notEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function any\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function all\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function not\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function texture1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord))\n" + " ()))\n" + "(function texture1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function texture1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord))\n" + " ()))\n" + "(function texture2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function texture2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture3D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function texture3DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function texture3DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture3DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function textureCube\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function textureCubeLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function shadow2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function shadow1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function shadow2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function shadow1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function noise1\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise2\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise3\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise4\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())))" +; +static const char *functions_for_120_vert [] = { + builtin_abs, + builtin_acos, + builtin_all, + builtin_any, + builtin_asin, + builtin_atan, + builtin_ceil, + builtin_clamp, + builtin_cos, + builtin_cross, + builtin_degrees, + builtin_distance, + builtin_dot, + builtin_equal, + builtin_exp, + builtin_exp2, + builtin_faceforward, + builtin_floor, + builtin_fract, + builtin_ftransform, + builtin_greaterThan, + builtin_greaterThanEqual, + builtin_inversesqrt, + builtin_length, + builtin_lessThan, + builtin_lessThanEqual, + builtin_log, + builtin_log2, + builtin_matrixCompMult, + builtin_max, + builtin_min, + builtin_mix, + builtin_mod, + builtin_noise1, + builtin_noise2, + builtin_noise3, + builtin_noise4, + builtin_normalize, + builtin_not, + builtin_notEqual, + builtin_outerProduct, + builtin_pow, + builtin_radians, + builtin_reflect, + builtin_refract, + builtin_shadow1D, + builtin_shadow1DLod, + builtin_shadow1DProj, + builtin_shadow1DProjLod, + builtin_shadow2D, + builtin_shadow2DLod, + builtin_shadow2DProj, + builtin_shadow2DProjLod, + builtin_sign, + builtin_sin, + builtin_smoothstep, + builtin_sqrt, + builtin_step, + builtin_tan, + builtin_texture1D, + builtin_texture1DLod, + builtin_texture1DProj, + builtin_texture1DProjLod, + builtin_texture2D, + builtin_texture2DLod, + builtin_texture2DProj, + builtin_texture2DProjLod, + builtin_texture3D, + builtin_texture3DLod, + builtin_texture3DProj, + builtin_texture3DProjLod, + builtin_textureCube, + builtin_textureCubeLod, + builtin_transpose, +}; +static const char *prototypes_for_130_frag = + "(\n" + "(function radians\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float degrees))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 degrees))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 degrees))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 degrees))\n" + " ()))\n" + "(function degrees\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float radians))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 radians))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 radians))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 radians))\n" + " ()))\n" + "(function sin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function cos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function tan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function asin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function acos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function atan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y_over_x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y_over_x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y_over_x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y_over_x))\n" + " ()))\n" + "(function sinh\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function cosh\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function tanh\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function pow\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function exp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function exp2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function inversesqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function abs\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x))\n" + " ()))\n" + "(function sign\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x))\n" + " ()))\n" + "(function floor\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function ceil\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function fract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function mod\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function min\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature uint\n" + " (parameters\n" + " (declare (in) uint x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uint y))\n" + " ()))\n" + "(function max\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature uint\n" + " (parameters\n" + " (declare (in) uint x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uint y))\n" + " ()))\n" + "(function clamp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 minVal)\n" + " (declare (in) vec2 maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 minVal)\n" + " (declare (in) vec3 maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 minVal)\n" + " (declare (in) vec4 maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x)\n" + " (declare (in) int minVal)\n" + " (declare (in) int maxVal))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 minVal)\n" + " (declare (in) ivec2 maxVal))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 minVal)\n" + " (declare (in) ivec3 maxVal))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 minVal)\n" + " (declare (in) ivec4 maxVal))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) int minVal)\n" + " (declare (in) int maxVal))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) int minVal)\n" + " (declare (in) int maxVal))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) int minVal)\n" + " (declare (in) int maxVal))\n" + " ())\n" + " (signature uint\n" + " (parameters\n" + " (declare (in) uint x)\n" + " (declare (in) uint minVal)\n" + " (declare (in) uint maxVal))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 minVal)\n" + " (declare (in) uvec2 maxVal))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 minVal)\n" + " (declare (in) uvec3 maxVal))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 minVal)\n" + " (declare (in) uvec4 maxVal))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uint minVal)\n" + " (declare (in) uint maxVal))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uint minVal)\n" + " (declare (in) uint maxVal))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uint minVal)\n" + " (declare (in) uint maxVal))\n" + " ()))\n" + "(function mix\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) float a))\n" + " ()))\n" + "(function step\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function smoothstep\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge0)\n" + " (declare (in) vec2 edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge0)\n" + " (declare (in) vec3 edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge0)\n" + " (declare (in) vec4 edge1)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function length\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function distance\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p0)\n" + " (declare (in) float p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 p0)\n" + " (declare (in) vec2 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 p0)\n" + " (declare (in) vec3 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 p0)\n" + " (declare (in) vec4 p1))\n" + " ()))\n" + "(function dot\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function cross\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ()))\n" + "(function normalize\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function faceforward\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float N)\n" + " (declare (in) float I)\n" + " (declare (in) float Nref))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 N)\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 Nref))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 N)\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 Nref))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 N)\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 Nref))\n" + " ()))\n" + "(function reflect\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N))\n" + " ()))\n" + "(function refract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N)\n" + " (declare (in) float eta))\n" + " ()))\n" + "(function matrixCompMult\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 x)\n" + " (declare (in) mat2 y))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 x)\n" + " (declare (in) mat3 y))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 x)\n" + " (declare (in) mat4 y))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat2x3 x)\n" + " (declare (in) mat2x3 y))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat2x4 x)\n" + " (declare (in) mat2x4 y))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat3x2 x)\n" + " (declare (in) mat3x2 y))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat3x4 x)\n" + " (declare (in) mat3x4 y))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat4x2 x)\n" + " (declare (in) mat4x2 y))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat4x3 x)\n" + " (declare (in) mat4x3 y))\n" + " ()))\n" + "(function outerProduct\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec4 r))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec4 r))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec4 r))\n" + " ()))\n" + "(function transpose\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 m))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 m))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 m))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat3x2 m))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat2x3 m))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat4x2 m))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat2x4 m))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat4x3 m))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat3x4 m))\n" + " ()))\n" + "(function lessThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ()))\n" + "(function lessThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ()))\n" + "(function greaterThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ()))\n" + "(function greaterThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ()))\n" + "(function equal\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function notEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function any\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function all\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function not\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function texture\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) samplerCubeShadow sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DArrayShadow sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) samplerCubeShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function textureProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function textureLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texelFetch\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) int P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) int P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) int P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ()))\n" + "(function textureProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function textureGrad\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) samplerCubeShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DArrayShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ()))\n" + "(function textureProjGrad\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ()))\n" + "(function texture1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture3D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture3DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture3DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture3DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function textureCube\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function textureCubeLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function dFdx\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ()))\n" + "(function dFdy\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ()))\n" + "(function fwidth\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 p))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 p))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 p))\n" + " ()))\n" + "(function noise1\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise2\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise3\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise4\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())))" +; +static const char *functions_for_130_frag [] = { + builtin_abs, + builtin_acos, + builtin_all, + builtin_any, + builtin_asin, + builtin_atan, + builtin_ceil, + builtin_clamp, + builtin_cos, + builtin_cosh, + builtin_cross, + builtin_dFdx, + builtin_dFdy, + builtin_degrees, + builtin_distance, + builtin_dot, + builtin_equal, + builtin_exp, + builtin_exp2, + builtin_faceforward, + builtin_floor, + builtin_fract, + builtin_fwidth, + builtin_greaterThan, + builtin_greaterThanEqual, + builtin_inversesqrt, + builtin_length, + builtin_lessThan, + builtin_lessThanEqual, + builtin_log, + builtin_log2, + builtin_matrixCompMult, + builtin_max, + builtin_min, + builtin_mix, + builtin_mod, + builtin_noise1, + builtin_noise2, + builtin_noise3, + builtin_noise4, + builtin_normalize, + builtin_not, + builtin_notEqual, + builtin_outerProduct, + builtin_pow, + builtin_radians, + builtin_reflect, + builtin_refract, + builtin_shadow1D, + builtin_shadow1DLod, + builtin_shadow1DProj, + builtin_shadow1DProjLod, + builtin_shadow2D, + builtin_shadow2DLod, + builtin_shadow2DProj, + builtin_shadow2DProjLod, + builtin_sign, + builtin_sin, + builtin_sinh, + builtin_smoothstep, + builtin_sqrt, + builtin_step, + builtin_tan, + builtin_tanh, + builtin_texelFetch, + builtin_texture, + builtin_texture1D, + builtin_texture1DLod, + builtin_texture1DProj, + builtin_texture1DProjLod, + builtin_texture2D, + builtin_texture2DLod, + builtin_texture2DProj, + builtin_texture2DProjLod, + builtin_texture3D, + builtin_texture3DLod, + builtin_texture3DProj, + builtin_texture3DProjLod, + builtin_textureCube, + builtin_textureCubeLod, + builtin_textureGrad, + builtin_textureLod, + builtin_textureProj, + builtin_textureProjGrad, + builtin_textureProjLod, + builtin_transpose, +}; +static const char *prototypes_for_130_vert = + "(\n" + "(function radians\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float degrees))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 degrees))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 degrees))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 degrees))\n" + " ()))\n" + "(function degrees\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float radians))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 radians))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 radians))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 radians))\n" + " ()))\n" + "(function sin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function cos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function tan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function asin\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function acos\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float angle))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 angle))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 angle))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 angle))\n" + " ()))\n" + "(function atan\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float y_over_x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 y_over_x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 y_over_x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 y_over_x))\n" + " ()))\n" + "(function sinh\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function cosh\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function tanh\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function pow\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function exp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function exp2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function log2\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function sqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function inversesqrt\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function abs\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x))\n" + " ()))\n" + "(function sign\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x))\n" + " ()))\n" + "(function floor\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function ceil\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function fract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function mod\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function min\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature uint\n" + " (parameters\n" + " (declare (in) uint x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uint y))\n" + " ()))\n" + "(function max\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) int y))\n" + " ())\n" + " (signature uint\n" + " (parameters\n" + " (declare (in) uint x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uint y))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uint y))\n" + " ()))\n" + "(function clamp\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 minVal)\n" + " (declare (in) vec2 maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 minVal)\n" + " (declare (in) vec3 maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 minVal)\n" + " (declare (in) vec4 maxVal))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) float minVal)\n" + " (declare (in) float maxVal))\n" + " ())\n" + " (signature int\n" + " (parameters\n" + " (declare (in) int x)\n" + " (declare (in) int minVal)\n" + " (declare (in) int maxVal))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 minVal)\n" + " (declare (in) ivec2 maxVal))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 minVal)\n" + " (declare (in) ivec3 maxVal))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 minVal)\n" + " (declare (in) ivec4 maxVal))\n" + " ())\n" + " (signature ivec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) int minVal)\n" + " (declare (in) int maxVal))\n" + " ())\n" + " (signature ivec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) int minVal)\n" + " (declare (in) int maxVal))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) int minVal)\n" + " (declare (in) int maxVal))\n" + " ())\n" + " (signature uint\n" + " (parameters\n" + " (declare (in) uint x)\n" + " (declare (in) uint minVal)\n" + " (declare (in) uint maxVal))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 minVal)\n" + " (declare (in) uvec2 maxVal))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 minVal)\n" + " (declare (in) uvec3 maxVal))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 minVal)\n" + " (declare (in) uvec4 maxVal))\n" + " ())\n" + " (signature uvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uint minVal)\n" + " (declare (in) uint maxVal))\n" + " ())\n" + " (signature uvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uint minVal)\n" + " (declare (in) uint maxVal))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uint minVal)\n" + " (declare (in) uint maxVal))\n" + " ()))\n" + "(function mix\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) vec2 a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) vec3 a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) vec4 a))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y)\n" + " (declare (in) float a))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y)\n" + " (declare (in) float a))\n" + " ()))\n" + "(function step\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function smoothstep\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 edge0)\n" + " (declare (in) vec2 edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 edge0)\n" + " (declare (in) vec3 edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 edge0)\n" + " (declare (in) vec4 edge1)\n" + " (declare (in) vec4 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float edge0)\n" + " (declare (in) float edge1)\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function length\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function distance\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float p0)\n" + " (declare (in) float p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 p0)\n" + " (declare (in) vec2 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 p0)\n" + " (declare (in) vec3 p1))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 p0)\n" + " (declare (in) vec4 p1))\n" + " ()))\n" + "(function dot\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x)\n" + " (declare (in) float y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ()))\n" + "(function cross\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ()))\n" + "(function normalize\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function ftransform\n" + " (signature vec4\n" + " (parameters)\n" + " ()))\n" + "(function faceforward\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float N)\n" + " (declare (in) float I)\n" + " (declare (in) float Nref))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 N)\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 Nref))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 N)\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 Nref))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 N)\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 Nref))\n" + " ()))\n" + "(function reflect\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N))\n" + " ()))\n" + "(function refract\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float I)\n" + " (declare (in) float N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 I)\n" + " (declare (in) vec2 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 I)\n" + " (declare (in) vec3 N)\n" + " (declare (in) float eta))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 I)\n" + " (declare (in) vec4 N)\n" + " (declare (in) float eta))\n" + " ()))\n" + "(function matrixCompMult\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 x)\n" + " (declare (in) mat2 y))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 x)\n" + " (declare (in) mat3 y))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 x)\n" + " (declare (in) mat4 y))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat2x3 x)\n" + " (declare (in) mat2x3 y))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat2x4 x)\n" + " (declare (in) mat2x4 y))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat3x2 x)\n" + " (declare (in) mat3x2 y))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat3x4 x)\n" + " (declare (in) mat3x4 y))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat4x2 x)\n" + " (declare (in) mat4x2 y))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat4x3 x)\n" + " (declare (in) mat4x3 y))\n" + " ()))\n" + "(function outerProduct\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec4 r))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec2 r))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) vec2 c)\n" + " (declare (in) vec4 r))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) vec4 c)\n" + " (declare (in) vec3 r))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) vec3 c)\n" + " (declare (in) vec4 r))\n" + " ()))\n" + "(function transpose\n" + " (signature mat2\n" + " (parameters\n" + " (declare (in) mat2 m))\n" + " ())\n" + " (signature mat3\n" + " (parameters\n" + " (declare (in) mat3 m))\n" + " ())\n" + " (signature mat4\n" + " (parameters\n" + " (declare (in) mat4 m))\n" + " ())\n" + " (signature mat2x3\n" + " (parameters\n" + " (declare (in) mat3x2 m))\n" + " ())\n" + " (signature mat3x2\n" + " (parameters\n" + " (declare (in) mat2x3 m))\n" + " ())\n" + " (signature mat2x4\n" + " (parameters\n" + " (declare (in) mat4x2 m))\n" + " ())\n" + " (signature mat4x2\n" + " (parameters\n" + " (declare (in) mat2x4 m))\n" + " ())\n" + " (signature mat3x4\n" + " (parameters\n" + " (declare (in) mat4x3 m))\n" + " ())\n" + " (signature mat4x3\n" + " (parameters\n" + " (declare (in) mat3x4 m))\n" + " ()))\n" + "(function lessThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ()))\n" + "(function lessThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ()))\n" + "(function greaterThan\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ()))\n" + "(function greaterThanEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ()))\n" + "(function equal\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function notEqual\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) vec2 x)\n" + " (declare (in) vec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) vec3 x)\n" + " (declare (in) vec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) vec4 x)\n" + " (declare (in) vec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) ivec2 x)\n" + " (declare (in) ivec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) ivec3 x)\n" + " (declare (in) ivec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) ivec4 x)\n" + " (declare (in) ivec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) uvec2 x)\n" + " (declare (in) uvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) uvec3 x)\n" + " (declare (in) uvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) uvec4 x)\n" + " (declare (in) uvec4 y))\n" + " ())\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x)\n" + " (declare (in) bvec2 y))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x)\n" + " (declare (in) bvec3 y))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x)\n" + " (declare (in) bvec4 y))\n" + " ()))\n" + "(function any\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function all\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bool\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function not\n" + " (signature bvec2\n" + " (parameters\n" + " (declare (in) bvec2 x))\n" + " ())\n" + " (signature bvec3\n" + " (parameters\n" + " (declare (in) bvec3 x))\n" + " ())\n" + " (signature bvec4\n" + " (parameters\n" + " (declare (in) bvec4 x))\n" + " ()))\n" + "(function texture\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) samplerCubeShadow sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DArrayShadow sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) samplerCubeShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function textureProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function textureLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texelFetch\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) int P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) int P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) int P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) ivec2 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) ivec3 P)\n" + " (declare (in) int lod))\n" + " ()))\n" + "(function textureProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function textureGrad\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) float P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usamplerCube sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) samplerCubeShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1DArray sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2DArray sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DArrayShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ()))\n" + "(function textureProjGrad\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec2 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler1D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec3 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler2D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature ivec4\n" + " (parameters\n" + " (declare (in) isampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature uvec4\n" + " (parameters\n" + " (declare (in) usampler3D sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec3 dPdx)\n" + " (declare (in) vec3 dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) float dPdx)\n" + " (declare (in) float dPdy))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 P)\n" + " (declare (in) vec2 dPdx)\n" + " (declare (in) vec2 dPdy))\n" + " ()))\n" + "(function texture1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) float coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture3D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture3DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture3DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture3DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler3D sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function textureCube\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function textureCubeLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) samplerCube sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow1D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow2D\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow1DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow2DProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow1DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow2DLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow1DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow2DProjLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DShadow sampler)\n" + " (declare (in) vec4 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function noise1\n" + " (signature float\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature float\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise2\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec2\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise3\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec3\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ()))\n" + "(function noise4\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) float x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec2 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec3 x))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) vec4 x))\n" + " ())))" +; +static const char *functions_for_130_vert [] = { + builtin_abs, + builtin_acos, + builtin_all, + builtin_any, + builtin_asin, + builtin_atan, + builtin_ceil, + builtin_clamp, + builtin_cos, + builtin_cosh, + builtin_cross, + builtin_degrees, + builtin_distance, + builtin_dot, + builtin_equal, + builtin_exp, + builtin_exp2, + builtin_faceforward, + builtin_floor, + builtin_fract, + builtin_ftransform, + builtin_greaterThan, + builtin_greaterThanEqual, + builtin_inversesqrt, + builtin_length, + builtin_lessThan, + builtin_lessThanEqual, + builtin_log, + builtin_log2, + builtin_matrixCompMult, + builtin_max, + builtin_min, + builtin_mix, + builtin_mod, + builtin_noise1, + builtin_noise2, + builtin_noise3, + builtin_noise4, + builtin_normalize, + builtin_not, + builtin_notEqual, + builtin_outerProduct, + builtin_pow, + builtin_radians, + builtin_reflect, + builtin_refract, + builtin_shadow1D, + builtin_shadow1DLod, + builtin_shadow1DProj, + builtin_shadow1DProjLod, + builtin_shadow2D, + builtin_shadow2DLod, + builtin_shadow2DProj, + builtin_shadow2DProjLod, + builtin_sign, + builtin_sin, + builtin_sinh, + builtin_smoothstep, + builtin_sqrt, + builtin_step, + builtin_tan, + builtin_tanh, + builtin_texelFetch, + builtin_texture, + builtin_texture1D, + builtin_texture1DLod, + builtin_texture1DProj, + builtin_texture1DProjLod, + builtin_texture2D, + builtin_texture2DLod, + builtin_texture2DProj, + builtin_texture2DProjLod, + builtin_texture3D, + builtin_texture3DLod, + builtin_texture3DProj, + builtin_texture3DProjLod, + builtin_textureCube, + builtin_textureCubeLod, + builtin_textureGrad, + builtin_textureLod, + builtin_textureProj, + builtin_textureProjGrad, + builtin_textureProjLod, + builtin_transpose, +}; +static const char *prototypes_for_ARB_texture_rectangle_frag = + "(\n" + "(function texture2DRect\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRect sampler)\n" + " (declare (in) vec2 coord))\n" + " ()))\n" + "(function texture2DRectProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRect sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRect sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function shadow2DRect\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRectShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function shadow2DRectProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRectShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())))" +; +static const char *functions_for_ARB_texture_rectangle_frag [] = { + builtin_shadow2DRect, + builtin_shadow2DRectProj, + builtin_texture2DRect, + builtin_texture2DRectProj, +}; +static const char *prototypes_for_ARB_texture_rectangle_vert = + "(\n" + "(function texture2DRect\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRect sampler)\n" + " (declare (in) vec2 coord))\n" + " ()))\n" + "(function texture2DRectProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRect sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRect sampler)\n" + " (declare (in) vec4 coord))\n" + " ()))\n" + "(function shadow2DRect\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRectShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function shadow2DRectProj\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DRectShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())))" +; +static const char *functions_for_ARB_texture_rectangle_vert [] = { + builtin_shadow2DRect, + builtin_shadow2DRectProj, + builtin_texture2DRect, + builtin_texture2DRectProj, +}; +static const char *prototypes_for_EXT_texture_array_frag = + "(\n" + "(function texture1DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function texture2DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow1DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ())\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float bias))\n" + " ()))\n" + "(function shadow2DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArrayShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())))" +; +static const char *functions_for_EXT_texture_array_frag [] = { + builtin_shadow1DArray, + builtin_shadow2DArray, + builtin_texture1DArray, + builtin_texture2DArray, +}; +static const char *prototypes_for_EXT_texture_array_vert = + "(\n" + "(function texture1DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 coord))\n" + " ()))\n" + "(function texture1DArrayLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArray sampler)\n" + " (declare (in) vec2 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function texture2DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function texture2DArrayLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArray sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow1DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 coord))\n" + " ()))\n" + "(function shadow1DArrayLod\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler1DArrayShadow sampler)\n" + " (declare (in) vec3 coord)\n" + " (declare (in) float lod))\n" + " ()))\n" + "(function shadow2DArray\n" + " (signature vec4\n" + " (parameters\n" + " (declare (in) sampler2DArrayShadow sampler)\n" + " (declare (in) vec4 coord))\n" + " ())))" +; +static const char *functions_for_EXT_texture_array_vert [] = { + builtin_shadow1DArray, + builtin_shadow1DArrayLod, + builtin_shadow2DArray, + builtin_texture1DArray, + builtin_texture1DArrayLod, + builtin_texture2DArray, + builtin_texture2DArrayLod, +}; +static gl_shader *builtin_profiles[10]; + +void *builtin_mem_ctx = NULL; + +void +_mesa_glsl_release_functions(void) +{ + talloc_free(builtin_mem_ctx); + builtin_mem_ctx = NULL; +} + +static void +_mesa_read_profile(struct _mesa_glsl_parse_state *state, + exec_list *instructions, + int profile_index, + const char *prototypes, + const char **functions, + int count) +{ + gl_shader *sh = builtin_profiles[profile_index]; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, prototypes, functions, count); + talloc_steal(builtin_mem_ctx, sh); + builtin_profiles[profile_index] = sh; + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; +} + +void +_mesa_glsl_initialize_functions(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + if (builtin_mem_ctx == NULL) { + builtin_mem_ctx = talloc_init("GLSL built-in functions"); + memset(&builtin_profiles, 0, sizeof(builtin_profiles)); + } + + state->num_builtins_to_link = 0; + + if (state->target == fragment_shader && state->language_version == 110) { + _mesa_read_profile(state, instructions, 0, + prototypes_for_110_frag, + functions_for_110_frag, + Elements(functions_for_110_frag)); + } + + if (state->target == vertex_shader && state->language_version == 110) { + _mesa_read_profile(state, instructions, 1, + prototypes_for_110_vert, + functions_for_110_vert, + Elements(functions_for_110_vert)); + } + + if (state->target == fragment_shader && state->language_version == 120) { + _mesa_read_profile(state, instructions, 2, + prototypes_for_120_frag, + functions_for_120_frag, + Elements(functions_for_120_frag)); + } + + if (state->target == vertex_shader && state->language_version == 120) { + _mesa_read_profile(state, instructions, 3, + prototypes_for_120_vert, + functions_for_120_vert, + Elements(functions_for_120_vert)); + } + + if (state->target == fragment_shader && state->language_version == 130) { + _mesa_read_profile(state, instructions, 4, + prototypes_for_130_frag, + functions_for_130_frag, + Elements(functions_for_130_frag)); + } + + if (state->target == vertex_shader && state->language_version == 130) { + _mesa_read_profile(state, instructions, 5, + prototypes_for_130_vert, + functions_for_130_vert, + Elements(functions_for_130_vert)); + } + + if (state->target == fragment_shader && state->ARB_texture_rectangle_enable) { + _mesa_read_profile(state, instructions, 6, + prototypes_for_ARB_texture_rectangle_frag, + functions_for_ARB_texture_rectangle_frag, + Elements(functions_for_ARB_texture_rectangle_frag)); + } + + if (state->target == vertex_shader && state->ARB_texture_rectangle_enable) { + _mesa_read_profile(state, instructions, 7, + prototypes_for_ARB_texture_rectangle_vert, + functions_for_ARB_texture_rectangle_vert, + Elements(functions_for_ARB_texture_rectangle_vert)); + } + + if (state->target == fragment_shader && state->EXT_texture_array_enable) { + _mesa_read_profile(state, instructions, 8, + prototypes_for_EXT_texture_array_frag, + functions_for_EXT_texture_array_frag, + Elements(functions_for_EXT_texture_array_frag)); + } + + if (state->target == vertex_shader && state->EXT_texture_array_enable) { + _mesa_read_profile(state, instructions, 9, + prototypes_for_EXT_texture_array_vert, + functions_for_EXT_texture_array_vert, + Elements(functions_for_EXT_texture_array_vert)); + } + +} diff --git a/src/glsl/builtin_types.h b/src/glsl/builtin_types.h new file mode 100644 index 0000000000..7b94aac666 --- /dev/null +++ b/src/glsl/builtin_types.h @@ -0,0 +1,290 @@ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +const glsl_type glsl_type::_error_type = + glsl_type(GL_INVALID_ENUM, GLSL_TYPE_ERROR, 0, 0, ""); + +const glsl_type glsl_type::void_type = + glsl_type(GL_INVALID_ENUM, GLSL_TYPE_VOID, 0, 0, "void"); + +const glsl_type *const glsl_type::error_type = & glsl_type::_error_type; + +/** \name Core built-in types + * + * These types exist in all versions of GLSL. + */ +/*@{*/ + +const glsl_type glsl_type::builtin_core_types[] = { + glsl_type(GL_BOOL, GLSL_TYPE_BOOL, 1, 1, "bool"), + glsl_type(GL_BOOL_VEC2, GLSL_TYPE_BOOL, 2, 1, "bvec2"), + glsl_type(GL_BOOL_VEC3, GLSL_TYPE_BOOL, 3, 1, "bvec3"), + glsl_type(GL_BOOL_VEC4, GLSL_TYPE_BOOL, 4, 1, "bvec4"), + glsl_type(GL_INT, GLSL_TYPE_INT, 1, 1, "int"), + glsl_type(GL_INT_VEC2, GLSL_TYPE_INT, 2, 1, "ivec2"), + glsl_type(GL_INT_VEC3, GLSL_TYPE_INT, 3, 1, "ivec3"), + glsl_type(GL_INT_VEC4, GLSL_TYPE_INT, 4, 1, "ivec4"), + glsl_type(GL_FLOAT, GLSL_TYPE_FLOAT, 1, 1, "float"), + glsl_type(GL_FLOAT_VEC2, GLSL_TYPE_FLOAT, 2, 1, "vec2"), + glsl_type(GL_FLOAT_VEC3, GLSL_TYPE_FLOAT, 3, 1, "vec3"), + glsl_type(GL_FLOAT_VEC4, GLSL_TYPE_FLOAT, 4, 1, "vec4"), + glsl_type(GL_FLOAT_MAT2, GLSL_TYPE_FLOAT, 2, 2, "mat2"), + glsl_type(GL_FLOAT_MAT3, GLSL_TYPE_FLOAT, 3, 3, "mat3"), + glsl_type(GL_FLOAT_MAT4, GLSL_TYPE_FLOAT, 4, 4, "mat4"), + glsl_type(GL_SAMPLER_1D, GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_FLOAT, + "sampler1D"), + glsl_type(GL_SAMPLER_1D_SHADOW, GLSL_SAMPLER_DIM_1D, 1, 0, GLSL_TYPE_FLOAT, + "sampler1DShadow"), + glsl_type(GL_SAMPLER_2D, GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_FLOAT, + "sampler2D"), + glsl_type(GL_SAMPLER_2D_SHADOW, GLSL_SAMPLER_DIM_2D, 1, 0, GLSL_TYPE_FLOAT, + "sampler2DShadow"), + glsl_type(GL_SAMPLER_3D, GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_FLOAT, + "sampler3D"), + glsl_type(GL_SAMPLER_CUBE, GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_FLOAT, + "samplerCube"), +}; + +const glsl_type *const glsl_type::bool_type = & builtin_core_types[0]; +const glsl_type *const glsl_type::int_type = & builtin_core_types[4]; +const glsl_type *const glsl_type::ivec4_type = & builtin_core_types[7]; +const glsl_type *const glsl_type::float_type = & builtin_core_types[8]; +const glsl_type *const glsl_type::vec2_type = & builtin_core_types[9]; +const glsl_type *const glsl_type::vec3_type = & builtin_core_types[10]; +const glsl_type *const glsl_type::vec4_type = & builtin_core_types[11]; +const glsl_type *const glsl_type::mat2_type = & builtin_core_types[12]; +const glsl_type *const glsl_type::mat3_type = & builtin_core_types[13]; +const glsl_type *const glsl_type::mat4_type = & builtin_core_types[14]; +/*@}*/ + +/** \name GLSL structures that have not been deprecated. + */ +/*@{*/ + +static const struct glsl_struct_field gl_DepthRangeParameters_fields[] = { + { glsl_type::float_type, "near" }, + { glsl_type::float_type, "far" }, + { glsl_type::float_type, "diff" }, +}; + +const glsl_type glsl_type::builtin_structure_types[] = { + glsl_type(gl_DepthRangeParameters_fields, + Elements(gl_DepthRangeParameters_fields), + "gl_DepthRangeParameters"), +}; +/*@}*/ + +/** \name GLSL 1.00 / 1.10 structures that are deprecated in GLSL 1.30 + */ +/*@{*/ + +static const struct glsl_struct_field gl_PointParameters_fields[] = { + { glsl_type::float_type, "size" }, + { glsl_type::float_type, "sizeMin" }, + { glsl_type::float_type, "sizeMax" }, + { glsl_type::float_type, "fadeThresholdSize" }, + { glsl_type::float_type, "distanceConstantAttenuation" }, + { glsl_type::float_type, "distanceLinearAttenuation" }, + { glsl_type::float_type, "distanceQuadraticAttenuation" }, +}; + +static const struct glsl_struct_field gl_MaterialParameters_fields[] = { + { glsl_type::vec4_type, "emission" }, + { glsl_type::vec4_type, "ambient" }, + { glsl_type::vec4_type, "diffuse" }, + { glsl_type::vec4_type, "specular" }, + { glsl_type::float_type, "shininess" }, +}; + +static const struct glsl_struct_field gl_LightSourceParameters_fields[] = { + { glsl_type::vec4_type, "ambient" }, + { glsl_type::vec4_type, "diffuse" }, + { glsl_type::vec4_type, "specular" }, + { glsl_type::vec4_type, "position" }, + { glsl_type::vec4_type, "halfVector" }, + { glsl_type::vec3_type, "spotDirection" }, + { glsl_type::float_type, "spotExponent" }, + { glsl_type::float_type, "spotCutoff" }, + { glsl_type::float_type, "spotCosCutoff" }, + { glsl_type::float_type, "constantAttenuation" }, + { glsl_type::float_type, "linearAttenuation" }, + { glsl_type::float_type, "quadraticAttenuation" }, +}; + +static const struct glsl_struct_field gl_LightModelParameters_fields[] = { + { glsl_type::vec4_type, "ambient" }, +}; + +static const struct glsl_struct_field gl_LightModelProducts_fields[] = { + { glsl_type::vec4_type, "sceneColor" }, +}; + +static const struct glsl_struct_field gl_LightProducts_fields[] = { + { glsl_type::vec4_type, "ambient" }, + { glsl_type::vec4_type, "diffuse" }, + { glsl_type::vec4_type, "specular" }, +}; + +static const struct glsl_struct_field gl_FogParameters_fields[] = { + { glsl_type::vec4_type, "color" }, + { glsl_type::float_type, "density" }, + { glsl_type::float_type, "start" }, + { glsl_type::float_type, "end" }, + { glsl_type::float_type, "scale" }, +}; + +const glsl_type glsl_type::builtin_110_deprecated_structure_types[] = { + glsl_type(gl_PointParameters_fields, + Elements(gl_PointParameters_fields), + "gl_PointParameters"), + glsl_type(gl_MaterialParameters_fields, + Elements(gl_MaterialParameters_fields), + "gl_MaterialParameters"), + glsl_type(gl_LightSourceParameters_fields, + Elements(gl_LightSourceParameters_fields), + "gl_LightSourceParameters"), + glsl_type(gl_LightModelParameters_fields, + Elements(gl_LightModelParameters_fields), + "gl_LightModelParameters"), + glsl_type(gl_LightModelProducts_fields, + Elements(gl_LightModelProducts_fields), + "gl_LightModelProducts"), + glsl_type(gl_LightProducts_fields, + Elements(gl_LightProducts_fields), + "gl_LightProducts"), + glsl_type(gl_FogParameters_fields, + Elements(gl_FogParameters_fields), + "gl_FogParameters"), +}; +/*@}*/ + +/** \name Types added in GLSL 1.20 + */ +/*@{*/ + +const glsl_type glsl_type::builtin_120_types[] = { + glsl_type(GL_FLOAT_MAT2x3, GLSL_TYPE_FLOAT, 3, 2, "mat2x3"), + glsl_type(GL_FLOAT_MAT2x4, GLSL_TYPE_FLOAT, 4, 2, "mat2x4"), + glsl_type(GL_FLOAT_MAT3x2, GLSL_TYPE_FLOAT, 2, 3, "mat3x2"), + glsl_type(GL_FLOAT_MAT3x4, GLSL_TYPE_FLOAT, 4, 3, "mat3x4"), + glsl_type(GL_FLOAT_MAT4x2, GLSL_TYPE_FLOAT, 2, 4, "mat4x2"), + glsl_type(GL_FLOAT_MAT4x3, GLSL_TYPE_FLOAT, 3, 4, "mat4x3"), +}; +const glsl_type *const glsl_type::mat2x3_type = & builtin_120_types[0]; +const glsl_type *const glsl_type::mat2x4_type = & builtin_120_types[1]; +const glsl_type *const glsl_type::mat3x2_type = & builtin_120_types[2]; +const glsl_type *const glsl_type::mat3x4_type = & builtin_120_types[3]; +const glsl_type *const glsl_type::mat4x2_type = & builtin_120_types[4]; +const glsl_type *const glsl_type::mat4x3_type = & builtin_120_types[5]; +/*@}*/ + +/** \name Types added in GLSL 1.30 + */ +/*@{*/ + +const glsl_type glsl_type::builtin_130_types[] = { + glsl_type(GL_UNSIGNED_INT, GLSL_TYPE_UINT, 1, 1, "uint"), + glsl_type(GL_UNSIGNED_INT_VEC2, GLSL_TYPE_UINT, 2, 1, "uvec2"), + glsl_type(GL_UNSIGNED_INT_VEC3, GLSL_TYPE_UINT, 3, 1, "uvec3"), + glsl_type(GL_UNSIGNED_INT_VEC4, GLSL_TYPE_UINT, 4, 1, "uvec4"), + + /* 1D and 2D texture arrays - several of these are included only in + * builtin_EXT_texture_array_types. + */ + glsl_type(GL_INT_SAMPLER_1D_ARRAY, + GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_INT, "isampler1DArray"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_1D_ARRAY, + GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_UINT, "usampler1DArray"), + glsl_type(GL_INT_SAMPLER_2D_ARRAY, + GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_INT, "isampler2DArray"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, + GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_UINT, "usampler2DArray"), + + /* cube shadow samplers */ + glsl_type(GL_SAMPLER_CUBE_SHADOW, + GLSL_SAMPLER_DIM_CUBE, 1, 0, GLSL_TYPE_FLOAT, "samplerCubeShadow"), + + /* signed and unsigned integer samplers */ + glsl_type(GL_INT_SAMPLER_1D, + GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_INT, "isampler1D"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_1D, + GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_UINT, "usampler1D"), + glsl_type(GL_INT_SAMPLER_2D, + GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_INT, "isampler2D"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_2D, + GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_UINT, "usampler2D"), + glsl_type(GL_INT_SAMPLER_3D, + GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_INT, "isampler3D"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_3D, + GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_UINT, "usampler3D"), + glsl_type(GL_INT_SAMPLER_CUBE, + GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_INT, "isamplerCube"), + glsl_type(GL_INT_SAMPLER_CUBE, + GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_UINT, "usamplerCube"), +}; + +const glsl_type *const glsl_type::uint_type = & builtin_130_types[0]; +const glsl_type *const glsl_type::uvec4_type = & builtin_130_types[3]; +/*@}*/ + +/** \name Sampler types added by GL_ARB_texture_rectangle + */ +/*@{*/ + +const glsl_type glsl_type::builtin_ARB_texture_rectangle_types[] = { + glsl_type(GL_SAMPLER_2D_RECT, + GLSL_SAMPLER_DIM_RECT, 0, 0, GLSL_TYPE_FLOAT, "sampler2DRect"), + glsl_type(GL_SAMPLER_2D_RECT_SHADOW, + GLSL_SAMPLER_DIM_RECT, 1, 0, GLSL_TYPE_FLOAT, "sampler2DRectShadow"), +}; +/*@}*/ + +/** \name Sampler types added by GL_EXT_texture_array + */ +/*@{*/ + +const glsl_type glsl_type::builtin_EXT_texture_array_types[] = { + glsl_type(GL_SAMPLER_1D_ARRAY, + GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_FLOAT, "sampler1DArray"), + glsl_type(GL_SAMPLER_1D_ARRAY_SHADOW, + GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_FLOAT, "sampler2DArray"), + glsl_type(GL_SAMPLER_2D_ARRAY, + GLSL_SAMPLER_DIM_1D, 1, 1, GLSL_TYPE_FLOAT, "sampler1DArrayShadow"), + glsl_type(GL_SAMPLER_2D_ARRAY_SHADOW, + GLSL_SAMPLER_DIM_2D, 1, 1, GLSL_TYPE_FLOAT, "sampler2DArrayShadow"), +}; +/*@}*/ + +/** \name Sampler types added by GL_EXT_texture_buffer_object + */ +/*@{*/ + +const glsl_type glsl_type::builtin_EXT_texture_buffer_object_types[] = { + glsl_type(GL_SAMPLER_BUFFER, + GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_FLOAT, "samplerBuffer"), + glsl_type(GL_INT_SAMPLER_BUFFER, + GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_INT, "isamplerBuffer"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_BUFFER, + GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_UINT, "usamplerBuffer"), +}; +/*@}*/ diff --git a/src/glsl/builtin_variables.h b/src/glsl/builtin_variables.h new file mode 100644 index 0000000000..a7dbe480e9 --- /dev/null +++ b/src/glsl/builtin_variables.h @@ -0,0 +1,98 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "main/core.h" /* for slot numbers */ + +struct builtin_variable { + enum ir_variable_mode mode; + int slot; + const char *type; + const char *name; +}; + +static const builtin_variable builtin_core_vs_variables[] = { + { ir_var_out, VERT_RESULT_HPOS, "vec4", "gl_Position" }, + { ir_var_out, VERT_RESULT_PSIZ, "float", "gl_PointSize" }, +}; + +static const builtin_variable builtin_core_fs_variables[] = { + { ir_var_in, FRAG_ATTRIB_WPOS, "vec4", "gl_FragCoord" }, + { ir_var_in, FRAG_ATTRIB_FACE, "bool", "gl_FrontFacing" }, + { ir_var_out, FRAG_RESULT_COLOR, "vec4", "gl_FragColor" }, + { ir_var_out, FRAG_RESULT_DEPTH, "float", "gl_FragDepth" }, +}; + +static const builtin_variable builtin_110_deprecated_fs_variables[] = { + { ir_var_in, FRAG_ATTRIB_COL0, "vec4", "gl_Color" }, + { ir_var_in, FRAG_ATTRIB_COL1, "vec4", "gl_SecondaryColor" }, + { ir_var_in, FRAG_ATTRIB_FOGC, "float", "gl_FogFragCoord" }, +}; + +static const builtin_variable builtin_110_deprecated_vs_variables[] = { + { ir_var_in, VERT_ATTRIB_POS, "vec4", "gl_Vertex" }, + { ir_var_in, VERT_ATTRIB_NORMAL, "vec3", "gl_Normal" }, + { ir_var_in, VERT_ATTRIB_COLOR0, "vec4", "gl_Color" }, + { ir_var_in, VERT_ATTRIB_COLOR1, "vec4", "gl_SecondaryColor" }, + { ir_var_in, VERT_ATTRIB_TEX0, "vec4", "gl_MultiTexCoord0" }, + { ir_var_in, VERT_ATTRIB_TEX1, "vec4", "gl_MultiTexCoord1" }, + { ir_var_in, VERT_ATTRIB_TEX2, "vec4", "gl_MultiTexCoord2" }, + { ir_var_in, VERT_ATTRIB_TEX3, "vec4", "gl_MultiTexCoord3" }, + { ir_var_in, VERT_ATTRIB_TEX4, "vec4", "gl_MultiTexCoord4" }, + { ir_var_in, VERT_ATTRIB_TEX5, "vec4", "gl_MultiTexCoord5" }, + { ir_var_in, VERT_ATTRIB_TEX6, "vec4", "gl_MultiTexCoord6" }, + { ir_var_in, VERT_ATTRIB_TEX7, "vec4", "gl_MultiTexCoord7" }, + { ir_var_in, VERT_ATTRIB_FOG, "float", "gl_FogCoord" }, + { ir_var_out, VERT_RESULT_HPOS, "vec4", "gl_ClipVertex" }, + { ir_var_out, VERT_RESULT_COL0, "vec4", "gl_FrontColor" }, + { ir_var_out, VERT_RESULT_BFC0, "vec4", "gl_BackColor" }, + { ir_var_out, VERT_RESULT_COL1, "vec4", "gl_FrontSecondaryColor" }, + { ir_var_out, VERT_RESULT_BFC1, "vec4", "gl_BackSecondaryColor" }, + { ir_var_out, VERT_RESULT_FOGC, "float", "gl_FogFragCoord" }, +}; + +static const builtin_variable builtin_120_fs_variables[] = { + { ir_var_in, FRAG_ATTRIB_PNTC, "vec2", "gl_PointCoord" }, +}; + +static const builtin_variable builtin_130_vs_variables[] = { + { ir_var_in, -1, "int", "gl_VertexID" }, +}; + +static const builtin_variable builtin_110_deprecated_uniforms[] = { + { ir_var_uniform, -1, "mat4", "gl_ModelViewMatrix" }, + { ir_var_uniform, -1, "mat4", "gl_ProjectionMatrix" }, + { ir_var_uniform, -1, "mat4", "gl_ModelViewProjectionMatrix" }, + { ir_var_uniform, -1, "mat3", "gl_NormalMatrix" }, + { ir_var_uniform, -1, "mat4", "gl_ModelViewMatrixInverse" }, + { ir_var_uniform, -1, "mat4", "gl_ProjectionMatrixInverse" }, + { ir_var_uniform, -1, "mat4", "gl_ModelViewProjectionMatrixInverse" }, + { ir_var_uniform, -1, "mat4", "gl_ModelViewMatrixTranspose" }, + { ir_var_uniform, -1, "mat4", "gl_ProjectionMatrixTranspose" }, + { ir_var_uniform, -1, "mat4", "gl_ModelViewProjectionMatrixTranspose" }, + { ir_var_uniform, -1, "mat4", "gl_ModelViewMatrixInverseTranspose" }, + { ir_var_uniform, -1, "mat4", "gl_ProjectionMatrixInverseTranspose" }, + { ir_var_uniform, -1, "mat4", "gl_ModelViewProjectionMatrixInverseTranspose" }, + { ir_var_uniform, -1, "float", "gl_NormalScale" }, + { ir_var_uniform, -1, "gl_LightModelParameters", "gl_LightModel"}, +}; + diff --git a/src/glsl/builtins/ir/abs b/src/glsl/builtins/ir/abs new file mode 100644 index 0000000000..904845307c --- /dev/null +++ b/src/glsl/builtins/ir/abs @@ -0,0 +1,21 @@ +((function abs + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float abs (var_ref arg0))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 abs (var_ref arg0))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 abs (var_ref arg0))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 abs (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/acos b/src/glsl/builtins/ir/acos new file mode 100644 index 0000000000..d1cfebeff8 --- /dev/null +++ b/src/glsl/builtins/ir/acos @@ -0,0 +1,22 @@ +((function acos + (signature float + (parameters + (declare (in) float x)) + ((return (expression float - (constant float (1.5707963)) + (call asin ((var_ref x))))))) + (signature vec2 + (parameters + (declare (in) vec2 x)) + ((return (expression vec2 - (constant float (1.5707963)) + (call asin ((var_ref x))))))) + (signature vec3 + (parameters + (declare (in) vec3 x)) + ((return (expression vec3 - (constant float (1.5707963)) + (call asin ((var_ref x))))))) + (signature vec4 + (parameters + (declare (in) vec4 x)) + ((return (expression vec4 - (constant float (1.5707963)) + (call asin ((var_ref x))))))) +)) diff --git a/src/glsl/builtins/ir/all b/src/glsl/builtins/ir/all new file mode 100644 index 0000000000..2cac0dfb68 --- /dev/null +++ b/src/glsl/builtins/ir/all @@ -0,0 +1,16 @@ +((function all + (signature bool + (parameters + (declare (in) bvec2 arg0)) + ((return (expression bool && (swiz x (var_ref arg0))(swiz y (var_ref arg0)))))) + + (signature bool + (parameters + (declare (in) bvec3 arg0)) + ((return (expression bool && (expression bool && (swiz x (var_ref arg0))(swiz y (var_ref arg0))) (swiz z (var_ref arg0)))))) + + (signature bool + (parameters + (declare (in) bvec4 arg0)) + ((return (expression bool && (expression bool && (expression bool && (swiz x (var_ref arg0))(swiz y (var_ref arg0))) (swiz z (var_ref arg0))) (swiz w (var_ref arg0)))))) +)) diff --git a/src/glsl/builtins/ir/any b/src/glsl/builtins/ir/any new file mode 100644 index 0000000000..cc6038a315 --- /dev/null +++ b/src/glsl/builtins/ir/any @@ -0,0 +1,16 @@ +((function any + (signature bool + (parameters + (declare (in) bvec2 arg0)) + ((return (expression bool any (var_ref arg0))))) + + (signature bool + (parameters + (declare (in) bvec3 arg0)) + ((return (expression bool any (var_ref arg0))))) + + (signature bool + (parameters + (declare (in) bvec4 arg0)) + ((return (expression bool any (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/asin b/src/glsl/builtins/ir/asin new file mode 100644 index 0000000000..e230ad614e --- /dev/null +++ b/src/glsl/builtins/ir/asin @@ -0,0 +1,97 @@ +((function asin + (signature float + (parameters + (declare (in) float x)) + ((return (expression float * + (expression float sign (var_ref x)) + (expression float - + (expression float * + (constant float (3.1415926)) + (constant float (0.5))) + (expression float * + (expression float sqrt + (expression float - + (constant float (1.0)) + (expression float abs (var_ref x)))) + (expression float + + (constant float (1.5707288)) + (expression float * + (expression float abs (var_ref x)) + (expression float + + (constant float (-0.2121144)) + (expression float * + (constant float (0.0742610)) + (expression float abs (var_ref x)))))))))))) + + (signature vec2 + (parameters + (declare (in) vec2 x)) + ((return (expression vec2 * + (expression vec2 sign (var_ref x)) + (expression vec2 - + (expression float * + (constant float (3.1415926)) + (constant float (0.5))) + (expression vec2 * + (expression vec2 sqrt + (expression vec2 - + (constant float (1.0)) + (expression vec2 abs (var_ref x)))) + (expression vec2 + + (constant float (1.5707288)) + (expression vec2 * + (expression vec2 abs (var_ref x)) + (expression vec2 + + (constant float (-0.2121144)) + (expression vec2 * + (constant float (0.0742610)) + (expression vec2 abs (var_ref x)))))))))))) + + (signature vec3 + (parameters + (declare (in) vec3 x)) + ((return (expression vec3 * + (expression vec3 sign (var_ref x)) + (expression vec3 - + (expression float * + (constant float (3.1415926)) + (constant float (0.5))) + (expression vec3 * + (expression vec3 sqrt + (expression vec3 - + (constant float (1.0)) + (expression vec3 abs (var_ref x)))) + (expression vec3 + + (constant float (1.5707288)) + (expression vec3 * + (expression vec3 abs (var_ref x)) + (expression vec3 + + (constant float (-0.2121144)) + (expression vec3 * + (constant float (0.0742610)) + (expression vec3 abs (var_ref x)))))))))))) + + (signature vec4 + (parameters + (declare (in) vec4 x)) + ((return (expression vec4 * + (expression vec4 sign (var_ref x)) + (expression vec4 - + (expression float * + (constant float (3.1415926)) + (constant float (0.5))) + (expression vec4 * + (expression vec4 sqrt + (expression vec4 - + (constant float (1.0)) + (expression vec4 abs (var_ref x)))) + (expression vec4 + + (constant float (1.5707288)) + (expression vec4 * + (expression vec4 abs (var_ref x)) + (expression vec4 + + (constant float (-0.2121144)) + (expression vec4 * + (constant float (0.0742610)) + (expression vec4 abs (var_ref x)))))))))))) +)) diff --git a/src/glsl/builtins/ir/atan b/src/glsl/builtins/ir/atan new file mode 100644 index 0000000000..04e1898f9f --- /dev/null +++ b/src/glsl/builtins/ir/atan @@ -0,0 +1,150 @@ +((function atan + (signature float + (parameters + (declare (in) float x)) + ((return (call asin ((expression float * + (var_ref x) + (expression float rsq + (expression float + + (expression float * + (var_ref x) + (var_ref x)) + (constant float (1.0)))))))))) + + (signature vec2 + (parameters + (declare (in) vec2 y_over_x)) + ((return (call asin ((expression vec2 * + (var_ref y_over_x) + (expression vec2 rsq + (expression vec2 + + (expression vec2 * + (var_ref y_over_x) + (var_ref y_over_x)) + (constant float (1.0)))))))))) + + (signature vec3 + (parameters + (declare (in) vec3 y_over_x)) + ((return (call asin ((expression vec3 * + (var_ref y_over_x) + (expression vec3 rsq + (expression vec3 + + (expression vec3 * + (var_ref y_over_x) + (var_ref y_over_x)) + (constant float (1.0)))))))))) + + (signature vec4 + (parameters + (declare (in) vec4 y_over_x)) + ((return (call asin ((expression vec4 * + (var_ref y_over_x) + (expression vec4 rsq + (expression vec4 + + (expression vec4 * + (var_ref y_over_x) + (var_ref y_over_x)) + (constant float (1.0)))))))))) + + (signature float + (parameters + (declare (in ) float y) + (declare (in ) float x) + ) + ( + (declare () float r) + (declare ( ) float abs_retval) + (assign (constant bool (1)) (var_ref abs_retval) (call abs ((var_ref x) )) +) + (if (expression bool > (var_ref abs_retval) (constant float (0.000100)) ) ( + (declare ( ) float atan_retval) + (assign (constant bool (1)) (var_ref atan_retval) (call atan ((expression float / (var_ref y) (var_ref x) ) )) +) + (assign (constant bool (1)) (var_ref r) (var_ref atan_retval) ) + (if (expression bool < (var_ref x) (constant float (0.000000)) ) ( + (if (expression bool >= (var_ref y) (constant float (0.000000)) ) ( + (declare ( ) float assignment_tmp) + (assign (constant bool (1)) (var_ref assignment_tmp) (expression float + (var_ref r) (constant float (3.141593)) ) ) + (assign (constant bool (1)) (var_ref r) (var_ref assignment_tmp) ) + ) + ( + (declare ( ) float assignment_tmp) + (assign (constant bool (1)) (var_ref assignment_tmp) (expression float - (var_ref r) (constant float (3.141593)) ) ) + (assign (constant bool (1)) (var_ref r) (var_ref assignment_tmp) ) + )) + + ) + ( + )) + + ) + ( + (declare () float sgn) + (assign (constant bool (1)) (var_ref sgn) (expression float sign (var_ref y))) + (assign (constant bool (1)) (var_ref r) (expression float * (var_ref sgn) (constant float (1.5707965)))) + )) + + (return (var_ref r) ) + )) + + + + (signature vec2 + (parameters + (declare (in) vec2 y) + (declare (in) vec2 x)) + ((declare () vec2 r) + (assign (constant bool (1)) + (swiz x (var_ref r)) + (call atan ((swiz x (var_ref y)) + (swiz x (var_ref x))))) + (assign (constant bool (1)) + (swiz y (var_ref r)) + (call atan ((swiz y (var_ref y)) + (swiz y (var_ref x))))) + (return (var_ref r)))) + + (signature vec3 + (parameters + (declare (in) vec3 y) + (declare (in) vec3 x)) + ((declare () vec3 r) + (assign (constant bool (1)) + (swiz x (var_ref r)) + (call atan ((swiz x (var_ref y)) + (swiz x (var_ref x))))) + (assign (constant bool (1)) + (swiz y (var_ref r)) + (call atan ((swiz y (var_ref y)) + (swiz y (var_ref x))))) + (assign (constant bool (1)) + (swiz z (var_ref r)) + (call atan ((swiz z (var_ref y)) + (swiz z (var_ref x))))) + (return (var_ref r)))) + + (signature vec4 + (parameters + (declare (in) vec4 y) + (declare (in) vec4 x)) + ((declare () vec4 r) + (assign (constant bool (1)) + (swiz x (var_ref r)) + (call atan ((swiz x (var_ref y)) + (swiz x (var_ref x))))) + (assign (constant bool (1)) + (swiz y (var_ref r)) + (call atan ((swiz y (var_ref y)) + (swiz y (var_ref x))))) + (assign (constant bool (1)) + (swiz z (var_ref r)) + (call atan ((swiz z (var_ref y)) + (swiz z (var_ref x))))) + (assign (constant bool (1)) + (swiz w (var_ref r)) + (call atan ((swiz w (var_ref y)) + (swiz w (var_ref x))))) + (return (var_ref r))))) + +)) diff --git a/src/glsl/builtins/ir/ceil b/src/glsl/builtins/ir/ceil new file mode 100644 index 0000000000..a26a775049 --- /dev/null +++ b/src/glsl/builtins/ir/ceil @@ -0,0 +1,21 @@ +((function ceil + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float ceil (var_ref arg0))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 ceil (var_ref arg0))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 ceil (var_ref arg0))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 ceil (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/clamp b/src/glsl/builtins/ir/clamp new file mode 100644 index 0000000000..2bdc466b26 --- /dev/null +++ b/src/glsl/builtins/ir/clamp @@ -0,0 +1,148 @@ +((function clamp + (signature float + (parameters + (declare (in) float arg0) + (declare (in) float arg1) + (declare (in) float arg2)) + ((return (expression float max (expression float min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1) + (declare (in) vec2 arg2)) + ((return (expression vec2 max (expression vec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1) + (declare (in) vec3 arg2)) + ((return (expression vec3 max (expression vec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1) + (declare (in) vec4 arg2)) + ((return (expression vec4 max (expression vec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) float arg1) + (declare (in) float arg2)) + ((return (expression vec2 max (expression vec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) float arg1) + (declare (in) float arg2)) + ((return (expression vec3 max (expression vec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) float arg1) + (declare (in) float arg2)) + ((return (expression vec4 max (expression vec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature int + (parameters + (declare (in) int arg0) + (declare (in) int arg1) + (declare (in) int arg2)) + ((return (expression int max (expression int min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature ivec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) ivec2 arg1) + (declare (in) ivec2 arg2)) + ((return (expression ivec2 max (expression ivec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature ivec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) ivec3 arg1) + (declare (in) ivec3 arg2)) + ((return (expression ivec3 max (expression ivec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature ivec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) ivec4 arg1) + (declare (in) ivec4 arg2)) + ((return (expression ivec4 max (expression ivec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature ivec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) int arg1) + (declare (in) int arg2)) + ((return (expression ivec2 max (expression ivec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature ivec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) int arg1) + (declare (in) int arg2)) + ((return (expression ivec3 max (expression ivec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature ivec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) int arg1) + (declare (in) int arg2)) + ((return (expression ivec4 max (expression ivec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature uint + (parameters + (declare (in) uint arg0) + (declare (in) uint arg1) + (declare (in) uint arg2)) + ((return (expression uint max (expression uint min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature uvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uvec2 arg1) + (declare (in) uvec2 arg2)) + ((return (expression uvec2 max (expression uvec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature uvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uvec3 arg1) + (declare (in) uvec3 arg2)) + ((return (expression uvec3 max (expression uvec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature uvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uvec4 arg1) + (declare (in) uvec4 arg2)) + ((return (expression uvec4 max (expression uvec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature uvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uint arg1) + (declare (in) uint arg2)) + ((return (expression uvec2 max (expression uvec2 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature uvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uint arg1) + (declare (in) uint arg2)) + ((return (expression uvec3 max (expression uvec3 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) + + (signature uvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uint arg1) + (declare (in) uint arg2)) + ((return (expression uvec4 max (expression uvec4 min (var_ref arg0) (var_ref arg2)) (var_ref arg1))))) +)) diff --git a/src/glsl/builtins/ir/cos b/src/glsl/builtins/ir/cos new file mode 100644 index 0000000000..88f266eccb --- /dev/null +++ b/src/glsl/builtins/ir/cos @@ -0,0 +1,21 @@ +((function cos + (signature float + (parameters + (declare (in) float angle)) + ((return (expression float cos (var_ref angle))))) + + (signature vec2 + (parameters + (declare (in) vec2 angle)) + ((return (expression vec2 cos (var_ref angle))))) + + (signature vec3 + (parameters + (declare (in) vec3 angle)) + ((return (expression vec3 cos (var_ref angle))))) + + (signature vec4 + (parameters + (declare (in) vec4 angle)) + ((return (expression vec4 cos (var_ref angle))))) +)) diff --git a/src/glsl/builtins/ir/cosh b/src/glsl/builtins/ir/cosh new file mode 100644 index 0000000000..45e0ae427d --- /dev/null +++ b/src/glsl/builtins/ir/cosh @@ -0,0 +1,30 @@ +((function cosh + (signature float + (parameters + (declare (in) float x)) + ((return (expression float * (constant float (0.5)) + (expression float + + (expression float exp (var_ref x)) + (expression float exp (expression float neg (var_ref x)))))))) + (signature vec2 + (parameters + (declare (in) vec2 x)) + ((return (expression vec2 * (constant vec2 (0.5)) + (expression vec2 + + (expression vec2 exp (var_ref x)) + (expression vec2 exp (expression vec2 neg (var_ref x)))))))) + (signature vec3 + (parameters + (declare (in) vec3 x)) + ((return (expression vec3 * (constant vec3 (0.5)) + (expression vec3 + + (expression vec3 exp (var_ref x)) + (expression vec3 exp (expression vec3 neg (var_ref x)))))))) + (signature vec4 + (parameters + (declare (in) vec4 x)) + ((return (expression vec4 * (constant vec4 (0.5)) + (expression vec4 + + (expression vec4 exp (var_ref x)) + (expression vec4 exp (expression vec4 neg (var_ref x)))))))) +)) diff --git a/src/glsl/builtins/ir/cross b/src/glsl/builtins/ir/cross new file mode 100644 index 0000000000..24717a2183 --- /dev/null +++ b/src/glsl/builtins/ir/cross @@ -0,0 +1,7 @@ +((function cross + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((return (expression vec3 cross (var_ref arg0) (var_ref arg1))))) +)) diff --git a/src/glsl/builtins/ir/dFdx b/src/glsl/builtins/ir/dFdx new file mode 100644 index 0000000000..30594d33c7 --- /dev/null +++ b/src/glsl/builtins/ir/dFdx @@ -0,0 +1,21 @@ +((function dFdx + (signature float + (parameters + (declare (in) float p)) + ((return (expression float dFdx (var_ref p))))) + + (signature vec2 + (parameters + (declare (in) vec2 p)) + ((return (expression vec2 dFdx (var_ref p))))) + + (signature vec3 + (parameters + (declare (in) vec3 p)) + ((return (expression vec3 dFdx (var_ref p))))) + + (signature vec4 + (parameters + (declare (in) vec4 p)) + ((return (expression vec4 dFdx (var_ref p))))) +)) diff --git a/src/glsl/builtins/ir/dFdy b/src/glsl/builtins/ir/dFdy new file mode 100644 index 0000000000..fb5798d3cb --- /dev/null +++ b/src/glsl/builtins/ir/dFdy @@ -0,0 +1,21 @@ +((function dFdy + (signature float + (parameters + (declare (in) float p)) + ((return (expression float dFdy (var_ref p))))) + + (signature vec2 + (parameters + (declare (in) vec2 p)) + ((return (expression vec2 dFdy (var_ref p))))) + + (signature vec3 + (parameters + (declare (in) vec3 p)) + ((return (expression vec3 dFdy (var_ref p))))) + + (signature vec4 + (parameters + (declare (in) vec4 p)) + ((return (expression vec4 dFdy (var_ref p))))) +)) diff --git a/src/glsl/builtins/ir/degrees b/src/glsl/builtins/ir/degrees new file mode 100644 index 0000000000..dc0d7b9e20 --- /dev/null +++ b/src/glsl/builtins/ir/degrees @@ -0,0 +1,21 @@ +((function degrees + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float * (var_ref arg0) (constant float (57.295780)))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 * (var_ref arg0) (constant float (57.295780)))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 * (var_ref arg0) (constant float (57.295780)))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 * (var_ref arg0) (constant float (57.295780)))))) +)) diff --git a/src/glsl/builtins/ir/distance b/src/glsl/builtins/ir/distance new file mode 100644 index 0000000000..a2309c484f --- /dev/null +++ b/src/glsl/builtins/ir/distance @@ -0,0 +1,33 @@ +((function distance + (signature float + (parameters + (declare (in) float p0) + (declare (in) float p1)) + ((declare () float p) + (assign (constant bool (1)) (var_ref p) (expression float - (var_ref p0) (var_ref p1))) + (return (expression float sqrt (expression float dot (var_ref p) (var_ref p)))))) + + (signature float + (parameters + (declare (in) vec2 p0) + (declare (in) vec2 p1)) + ((declare () vec2 p) + (assign (constant bool (1)) (var_ref p) (expression vec2 - (var_ref p0) (var_ref p1))) + (return (expression float sqrt (expression float dot (var_ref p) (var_ref p)))))) + + (signature float + (parameters + (declare (in) vec3 p0) + (declare (in) vec3 p1)) + ((declare () vec3 p) + (assign (constant bool (1)) (var_ref p) (expression vec3 - (var_ref p0) (var_ref p1))) + (return (expression float sqrt (expression float dot (var_ref p) (var_ref p)))))) + + (signature float + (parameters + (declare (in) vec4 p0) + (declare (in) vec4 p1)) + ((declare () vec4 p) + (assign (constant bool (1)) (var_ref p) (expression vec4 - (var_ref p0) (var_ref p1))) + (return (expression float sqrt (expression float dot (var_ref p) (var_ref p)))))) +)) diff --git a/src/glsl/builtins/ir/dot b/src/glsl/builtins/ir/dot new file mode 100644 index 0000000000..a91a6d2c56 --- /dev/null +++ b/src/glsl/builtins/ir/dot @@ -0,0 +1,25 @@ +((function dot + (signature float + (parameters + (declare (in) float arg0) + (declare (in) float arg1)) + ((return (expression float dot (var_ref arg0) (var_ref arg1))))) + + (signature float + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((return (expression float dot (var_ref arg0) (var_ref arg1))))) + + (signature float + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((return (expression float dot (var_ref arg0) (var_ref arg1))))) + + (signature float + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((return (expression float dot (var_ref arg0) (var_ref arg1))))) +)) diff --git a/src/glsl/builtins/ir/equal b/src/glsl/builtins/ir/equal new file mode 100644 index 0000000000..c394776770 --- /dev/null +++ b/src/glsl/builtins/ir/equal @@ -0,0 +1,121 @@ +((function equal + (signature bvec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool == (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) bvec2 arg0) + (declare (in) bvec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) bvec3 arg0) + (declare (in) bvec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) bvec4 arg0) + (declare (in) bvec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool == (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) ivec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) ivec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) ivec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool == (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uvec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uvec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uvec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool == (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool == (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool == (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool == (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) +)) diff --git a/src/glsl/builtins/ir/exp b/src/glsl/builtins/ir/exp new file mode 100644 index 0000000000..a73bd6a7f8 --- /dev/null +++ b/src/glsl/builtins/ir/exp @@ -0,0 +1,21 @@ +((function exp + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float exp (var_ref arg0))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 exp (var_ref arg0))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 exp (var_ref arg0))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 exp (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/exp2 b/src/glsl/builtins/ir/exp2 new file mode 100644 index 0000000000..a842d3fe65 --- /dev/null +++ b/src/glsl/builtins/ir/exp2 @@ -0,0 +1,21 @@ +((function exp2 + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float exp2 (var_ref arg0))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 exp2 (var_ref arg0))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 exp2 (var_ref arg0))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 exp2 (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/faceforward b/src/glsl/builtins/ir/faceforward new file mode 100644 index 0000000000..d170397238 --- /dev/null +++ b/src/glsl/builtins/ir/faceforward @@ -0,0 +1,37 @@ +((function faceforward + (signature float + (parameters + (declare (in) float N) + (declare (in) float I) + (declare (in) float Nref)) + ((if (expression bool < (expression float dot (var_ref Nref) (var_ref I)) (constant float (0))) + ((return (var_ref N))) + ((return (expression float neg (var_ref N))))))) + + (signature vec2 + (parameters + (declare (in) vec2 N) + (declare (in) vec2 I) + (declare (in) vec2 Nref)) + ((if (expression bool < (expression float dot (var_ref Nref) (var_ref I)) (constant float (0))) + ((return (var_ref N))) + ((return (expression vec2 neg (var_ref N))))))) + + (signature vec3 + (parameters + (declare (in) vec3 N) + (declare (in) vec3 I) + (declare (in) vec3 Nref)) + ((if (expression bool < (expression float dot (var_ref Nref) (var_ref I)) (constant float (0))) + ((return (var_ref N))) + ((return (expression vec3 neg (var_ref N))))))) + + (signature vec4 + (parameters + (declare (in) vec4 N) + (declare (in) vec4 I) + (declare (in) vec4 Nref)) + ((if (expression bool < (expression float dot (var_ref Nref) (var_ref I)) (constant float (0))) + ((return (var_ref N))) + ((return (expression vec4 neg (var_ref N))))))) +)) diff --git a/src/glsl/builtins/ir/floor b/src/glsl/builtins/ir/floor new file mode 100644 index 0000000000..8dd8052799 --- /dev/null +++ b/src/glsl/builtins/ir/floor @@ -0,0 +1,21 @@ +((function floor + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float floor (var_ref arg0))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 floor (var_ref arg0))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 floor (var_ref arg0))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 floor (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/fract b/src/glsl/builtins/ir/fract new file mode 100644 index 0000000000..3f0763d1b3 --- /dev/null +++ b/src/glsl/builtins/ir/fract @@ -0,0 +1,22 @@ +((function fract + (signature float + (parameters + (declare (in) float x)) + ((return (expression float fract (var_ref x))))) + + (signature vec2 + (parameters + (declare (in) vec2 x)) + ((return (expression vec2 fract (var_ref x))))) + + (signature vec3 + (parameters + (declare (in) vec3 x)) + ((return (expression vec3 fract (var_ref x))))) + + (signature vec4 + (parameters + (declare (in) vec4 x)) + ((return (expression vec4 fract (var_ref x))))) +)) + diff --git a/src/glsl/builtins/ir/ftransform b/src/glsl/builtins/ir/ftransform new file mode 100644 index 0000000000..9ca63dc1e3 --- /dev/null +++ b/src/glsl/builtins/ir/ftransform @@ -0,0 +1,9 @@ +((declare (uniform) mat4 gl_ModelViewProjectionMatrix) + (declare (in) vec4 gl_Vertex) + (function ftransform + (signature vec4 + (parameters) + ((return (expression vec4 * + (var_ref gl_ModelViewProjectionMatrix) + (var_ref gl_Vertex))))) +)) diff --git a/src/glsl/builtins/ir/fwidth b/src/glsl/builtins/ir/fwidth new file mode 100644 index 0000000000..385e05d6a1 --- /dev/null +++ b/src/glsl/builtins/ir/fwidth @@ -0,0 +1,29 @@ +((function fwidth + (signature float + (parameters + (declare (in) float p)) + ((return (expression float + + (expression float abs (expression float dFdx (var_ref p))) + (expression float abs (expression float dFdy (var_ref p))))))) + + (signature vec2 + (parameters + (declare (in) vec2 p)) + ((return (expression vec2 + + (expression vec2 abs (expression vec2 dFdx (var_ref p))) + (expression vec2 abs (expression vec2 dFdy (var_ref p))))))) + + (signature vec3 + (parameters + (declare (in) vec3 p)) + ((return (expression vec3 + + (expression vec3 abs (expression vec3 dFdx (var_ref p))) + (expression vec3 abs (expression vec3 dFdy (var_ref p))))))) + + (signature vec4 + (parameters + (declare (in) vec4 p)) + ((return (expression vec4 + + (expression vec4 abs (expression vec4 dFdx (var_ref p))) + (expression vec4 abs (expression vec4 dFdy (var_ref p))))))) +)) diff --git a/src/glsl/builtins/ir/greaterThan b/src/glsl/builtins/ir/greaterThan new file mode 100644 index 0000000000..ce7bd29bed --- /dev/null +++ b/src/glsl/builtins/ir/greaterThan @@ -0,0 +1,91 @@ +((function greaterThan + (signature bvec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool > (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) ivec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) ivec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) ivec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool > (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uvec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uvec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uvec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool > (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool > (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool > (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool > (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) +)) diff --git a/src/glsl/builtins/ir/greaterThanEqual b/src/glsl/builtins/ir/greaterThanEqual new file mode 100644 index 0000000000..de1a9f9516 --- /dev/null +++ b/src/glsl/builtins/ir/greaterThanEqual @@ -0,0 +1,91 @@ +((function greaterThanEqual + (signature bvec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool >= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) ivec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) ivec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) ivec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool >= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uvec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uvec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uvec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool >= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool >= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool >= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool >= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) +)) diff --git a/src/glsl/builtins/ir/inversesqrt b/src/glsl/builtins/ir/inversesqrt new file mode 100644 index 0000000000..5b66d2b369 --- /dev/null +++ b/src/glsl/builtins/ir/inversesqrt @@ -0,0 +1,21 @@ +((function inversesqrt + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float rsq (var_ref arg0))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 rsq (var_ref arg0))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 rsq (var_ref arg0))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 rsq (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/length b/src/glsl/builtins/ir/length new file mode 100644 index 0000000000..89ff7f3ef1 --- /dev/null +++ b/src/glsl/builtins/ir/length @@ -0,0 +1,21 @@ +((function length + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float sqrt (expression float dot (var_ref arg0) (var_ref arg0)))))) + + (signature float + (parameters + (declare (in) vec2 arg0)) + ((return (expression float sqrt (expression float dot (var_ref arg0) (var_ref arg0)))))) + + (signature float + (parameters + (declare (in) vec3 arg0)) + ((return (expression float sqrt (expression float dot (var_ref arg0) (var_ref arg0)))))) + + (signature float + (parameters + (declare (in) vec4 arg0)) + ((return (expression float sqrt (expression float dot (var_ref arg0) (var_ref arg0)))))) +)) diff --git a/src/glsl/builtins/ir/lessThan b/src/glsl/builtins/ir/lessThan new file mode 100644 index 0000000000..52113b7046 --- /dev/null +++ b/src/glsl/builtins/ir/lessThan @@ -0,0 +1,91 @@ +((function lessThan + (signature bvec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool < (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) ivec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) ivec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) ivec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool < (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uvec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uvec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uvec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool < (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool < (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool < (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool < (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) +)) diff --git a/src/glsl/builtins/ir/lessThanEqual b/src/glsl/builtins/ir/lessThanEqual new file mode 100644 index 0000000000..4b240be5d1 --- /dev/null +++ b/src/glsl/builtins/ir/lessThanEqual @@ -0,0 +1,91 @@ +((function lessThanEqual + (signature bvec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool <= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) ivec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) ivec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) ivec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool <= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uvec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uvec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uvec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool <= (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool <= (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool <= (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool <= (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) +)) diff --git a/src/glsl/builtins/ir/log b/src/glsl/builtins/ir/log new file mode 100644 index 0000000000..d168abb5a7 --- /dev/null +++ b/src/glsl/builtins/ir/log @@ -0,0 +1,21 @@ +((function log + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float log (var_ref arg0))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 log (var_ref arg0))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 log (var_ref arg0))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 log (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/log2 b/src/glsl/builtins/ir/log2 new file mode 100644 index 0000000000..b96c6276f0 --- /dev/null +++ b/src/glsl/builtins/ir/log2 @@ -0,0 +1,21 @@ +((function log2 + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float log2 (var_ref arg0))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 log2 (var_ref arg0))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 log2 (var_ref arg0))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 log2 (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/matrixCompMult b/src/glsl/builtins/ir/matrixCompMult new file mode 100644 index 0000000000..538da18a79 --- /dev/null +++ b/src/glsl/builtins/ir/matrixCompMult @@ -0,0 +1,91 @@ +((function matrixCompMult + (signature mat2 + (parameters + (declare (in) mat2 x) + (declare (in) mat2 y)) + ((declare () mat2 z) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec2 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec2 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) +(return (var_ref z)))) + + (signature mat3 + (parameters + (declare (in) mat3 x) + (declare (in) mat3 y)) + ((declare () mat3 z) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec3 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec3 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec3 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) +(return (var_ref z)))) + + (signature mat4 + (parameters + (declare (in) mat4 x) + (declare (in) mat4 y)) + ((declare () mat4 z) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec4 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec4 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec4 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (3))) (expression vec4 * (array_ref (var_ref x) (constant int (3))) (array_ref (var_ref y) (constant int (3))))) +(return (var_ref z)))) + + (signature mat2x3 + (parameters + (declare (in) mat2x3 x) + (declare (in) mat2x3 y)) + ((declare () mat2x3 z) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec3 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec3 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) +(return (var_ref z)))) + + (signature mat3x2 + (parameters + (declare (in) mat3x2 x) + (declare (in) mat3x2 y)) + ((declare () mat3x2 z) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec2 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec2 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec2 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) +(return (var_ref z)))) + + (signature mat2x4 + (parameters + (declare (in) mat2x4 x) + (declare (in) mat2x4 y)) + ((declare () mat2x4 z) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec4 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec4 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) +(return (var_ref z)))) + + (signature mat4x2 + (parameters + (declare (in) mat4x2 x) + (declare (in) mat4x2 y)) + ((declare () mat4x2 z) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec2 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec2 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec2 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (3))) (expression vec2 * (array_ref (var_ref x) (constant int (3))) (array_ref (var_ref y) (constant int (3))))) +(return (var_ref z)))) + + (signature mat3x4 + (parameters + (declare (in) mat3x4 x) + (declare (in) mat3x4 y)) + ((declare () mat3x4 z) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec4 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec4 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec4 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) +(return (var_ref z)))) + + (signature mat4x3 + (parameters + (declare (in) mat4x3 x) + (declare (in) mat4x3 y)) + ((declare () mat4x3 z) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (0))) (expression vec3 * (array_ref (var_ref x) (constant int (0))) (array_ref (var_ref y) (constant int (0))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (1))) (expression vec3 * (array_ref (var_ref x) (constant int (1))) (array_ref (var_ref y) (constant int (1))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (2))) (expression vec3 * (array_ref (var_ref x) (constant int (2))) (array_ref (var_ref y) (constant int (2))))) + (assign (constant bool (1)) (array_ref (var_ref z) (constant int (3))) (expression vec3 * (array_ref (var_ref x) (constant int (3))) (array_ref (var_ref y) (constant int (3))))) +(return (var_ref z)))) +)) diff --git a/src/glsl/builtins/ir/max b/src/glsl/builtins/ir/max new file mode 100644 index 0000000000..2b5a02868c --- /dev/null +++ b/src/glsl/builtins/ir/max @@ -0,0 +1,127 @@ +((function max + (signature float + (parameters + (declare (in) float arg0) + (declare (in) float arg1)) + ((return (expression float max (var_ref arg0) (var_ref arg1))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((return (expression vec2 max (var_ref arg0) (var_ref arg1))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((return (expression vec3 max (var_ref arg0) (var_ref arg1))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((return (expression vec4 max (var_ref arg0) (var_ref arg1))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) float arg1)) + ((return (expression vec2 max (var_ref arg0) (var_ref arg1))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) float arg1)) + ((return (expression vec3 max (var_ref arg0) (var_ref arg1))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) float arg1)) + ((return (expression vec4 max (var_ref arg0) (var_ref arg1))))) + + (signature int + (parameters + (declare (in) int arg0) + (declare (in) int arg1)) + ((return (expression int max (var_ref arg0) (var_ref arg1))))) + + (signature ivec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) ivec2 arg1)) + ((return (expression ivec2 max (var_ref arg0) (var_ref arg1))))) + + (signature ivec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) ivec3 arg1)) + ((return (expression ivec3 max (var_ref arg0) (var_ref arg1))))) + + (signature ivec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) ivec4 arg1)) + ((return (expression ivec4 max (var_ref arg0) (var_ref arg1))))) + + (signature ivec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) int arg1)) + ((return (expression ivec2 max (var_ref arg0) (var_ref arg1))))) + + (signature ivec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) int arg1)) + ((return (expression ivec3 max (var_ref arg0) (var_ref arg1))))) + + (signature ivec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) int arg1)) + ((return (expression ivec4 max (var_ref arg0) (var_ref arg1))))) + + (signature uint + (parameters + (declare (in) uint arg0) + (declare (in) uint arg1)) + ((return (expression uint max (var_ref arg0) (var_ref arg1))))) + + (signature uvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uvec2 arg1)) + ((return (expression uvec2 max (var_ref arg0) (var_ref arg1))))) + + (signature uvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uvec3 arg1)) + ((return (expression uvec3 max (var_ref arg0) (var_ref arg1))))) + + (signature uvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uvec4 arg1)) + ((return (expression uvec4 max (var_ref arg0) (var_ref arg1))))) + + (signature uvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uint arg1)) + ((return (expression uvec2 max (var_ref arg0) (var_ref arg1))))) + + (signature uvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uint arg1)) + ((return (expression uvec3 max (var_ref arg0) (var_ref arg1))))) + + (signature uvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uint arg1)) + ((return (expression uvec4 max (var_ref arg0) (var_ref arg1))))) +)) diff --git a/src/glsl/builtins/ir/min b/src/glsl/builtins/ir/min new file mode 100644 index 0000000000..2deef1118a --- /dev/null +++ b/src/glsl/builtins/ir/min @@ -0,0 +1,127 @@ +((function min + (signature float + (parameters + (declare (in) float arg0) + (declare (in) float arg1)) + ((return (expression float min (var_ref arg0) (var_ref arg1))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((return (expression vec2 min (var_ref arg0) (var_ref arg1))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((return (expression vec3 min (var_ref arg0) (var_ref arg1))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((return (expression vec4 min (var_ref arg0) (var_ref arg1))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) float arg1)) + ((return (expression vec2 min (var_ref arg0) (var_ref arg1))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) float arg1)) + ((return (expression vec3 min (var_ref arg0) (var_ref arg1))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) float arg1)) + ((return (expression vec4 min (var_ref arg0) (var_ref arg1))))) + + (signature int + (parameters + (declare (in) int arg0) + (declare (in) int arg1)) + ((return (expression int min (var_ref arg0) (var_ref arg1))))) + + (signature ivec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) ivec2 arg1)) + ((return (expression ivec2 min (var_ref arg0) (var_ref arg1))))) + + (signature ivec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) ivec3 arg1)) + ((return (expression ivec3 min (var_ref arg0) (var_ref arg1))))) + + (signature ivec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) ivec4 arg1)) + ((return (expression ivec4 min (var_ref arg0) (var_ref arg1))))) + + (signature ivec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) int arg1)) + ((return (expression ivec2 min (var_ref arg0) (var_ref arg1))))) + + (signature ivec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) int arg1)) + ((return (expression ivec3 min (var_ref arg0) (var_ref arg1))))) + + (signature ivec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) int arg1)) + ((return (expression ivec4 min (var_ref arg0) (var_ref arg1))))) + + (signature uint + (parameters + (declare (in) uint arg0) + (declare (in) uint arg1)) + ((return (expression uint min (var_ref arg0) (var_ref arg1))))) + + (signature uvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uvec2 arg1)) + ((return (expression uvec2 min (var_ref arg0) (var_ref arg1))))) + + (signature uvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uvec3 arg1)) + ((return (expression uvec3 min (var_ref arg0) (var_ref arg1))))) + + (signature uvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uvec4 arg1)) + ((return (expression uvec4 min (var_ref arg0) (var_ref arg1))))) + + (signature uvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uint arg1)) + ((return (expression uvec2 min (var_ref arg0) (var_ref arg1))))) + + (signature uvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uint arg1)) + ((return (expression uvec3 min (var_ref arg0) (var_ref arg1))))) + + (signature uvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uint arg1)) + ((return (expression uvec4 min (var_ref arg0) (var_ref arg1))))) +)) diff --git a/src/glsl/builtins/ir/mix b/src/glsl/builtins/ir/mix new file mode 100644 index 0000000000..6bc6f0a43e --- /dev/null +++ b/src/glsl/builtins/ir/mix @@ -0,0 +1,88 @@ +((function mix + (signature float + (parameters + (declare (in) float arg0) + (declare (in) float arg1) + (declare (in) float arg2)) + ((return (expression float + (expression float * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression float * (var_ref arg1) (var_ref arg2)))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1) + (declare (in) vec2 arg2)) + ((return (expression vec2 + (expression vec2 * (var_ref arg0) (expression vec2 - (constant float (1.000000)) (var_ref arg2))) (expression vec2 * (var_ref arg1) (var_ref arg2)))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1) + (declare (in) vec3 arg2)) + ((return (expression vec3 + (expression vec3 * (var_ref arg0) (expression vec3 - (constant float (1.000000)) (var_ref arg2))) (expression vec3 * (var_ref arg1) (var_ref arg2)))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1) + (declare (in) vec4 arg2)) + ((return (expression vec4 + (expression vec4 * (var_ref arg0) (expression vec4 - (constant float (1.000000)) (var_ref arg2))) (expression vec4 * (var_ref arg1) (var_ref arg2)))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1) + (declare (in) float arg2)) + ((return (expression vec2 + (expression vec2 * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression vec2 * (var_ref arg1) (var_ref arg2)))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1) + (declare (in) float arg2)) + ((return (expression vec3 + (expression vec3 * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression vec3 * (var_ref arg1) (var_ref arg2)))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1) + (declare (in) float arg2)) + ((return (expression vec4 + (expression vec4 * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression vec4 * (var_ref arg1) (var_ref arg2)))))) + + (signature float + (parameters + (declare (in) float v1) + (declare (in) float v2) + (declare (in) bool a)) + ((assign (var_ref a) (var_ref v1) (var_ref v2)) + (return (var_ref v1)))) + + (signature vec2 + (parameters + (declare (in) vec2 v1) + (declare (in) vec2 v2) + (declare (in) bvec2 a)) + ((assign (swiz x (var_ref a)) (swiz x (var_ref v1)) (swiz x (var_ref v2))) + (assign (swiz y (var_ref a)) (swiz y (var_ref v1)) (swiz y (var_ref v2))) + (return (var_ref v1)))) + + (signature vec3 + (parameters + (declare (in) vec3 v1) + (declare (in) vec3 v2) + (declare (in) bvec3 a)) + ((assign (swiz x (var_ref a)) (swiz x (var_ref v1)) (swiz x (var_ref v2))) + (assign (swiz y (var_ref a)) (swiz y (var_ref v1)) (swiz y (var_ref v2))) + (assign (swiz z (var_ref a)) (swiz z (var_ref v1)) (swiz z (var_ref v2))) + (return (var_ref v1)))) + + (signature vec4 + (parameters + (declare (in) vec4 v1) + (declare (in) vec4 v2) + (declare (in) bvec4 a)) + ((assign (swiz x (var_ref a)) (swiz x (var_ref v1)) (swiz x (var_ref v2))) + (assign (swiz y (var_ref a)) (swiz y (var_ref v1)) (swiz y (var_ref v2))) + (assign (swiz z (var_ref a)) (swiz z (var_ref v1)) (swiz z (var_ref v2))) + (assign (swiz w (var_ref a)) (swiz w (var_ref v1)) (swiz w (var_ref v2))) + (return (var_ref v1)))) +)) diff --git a/src/glsl/builtins/ir/mod b/src/glsl/builtins/ir/mod new file mode 100644 index 0000000000..aeaea240e2 --- /dev/null +++ b/src/glsl/builtins/ir/mod @@ -0,0 +1,43 @@ +((function mod + (signature float + (parameters + (declare (in) float arg0) + (declare (in) float arg1)) + ((return (expression float % (var_ref arg0) (var_ref arg1))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((return (expression vec2 % (var_ref arg0) (var_ref arg1))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((return (expression vec3 % (var_ref arg0) (var_ref arg1))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((return (expression vec4 % (var_ref arg0) (var_ref arg1))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) float arg1)) + ((return (expression vec2 % (var_ref arg0) (var_ref arg1))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) float arg1)) + ((return (expression vec3 % (var_ref arg0) (var_ref arg1))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) float arg1)) + ((return (expression vec4 % (var_ref arg0) (var_ref arg1))))) +)) diff --git a/src/glsl/builtins/ir/noise1 b/src/glsl/builtins/ir/noise1 new file mode 100644 index 0000000000..eb7be35857 --- /dev/null +++ b/src/glsl/builtins/ir/noise1 @@ -0,0 +1,18 @@ +((function noise1 + (signature float + (parameters + (declare (in) float x)) + ((return (constant float (0))))) + (signature float + (parameters + (declare (in) vec2 x)) + ((return (constant float (0))))) + (signature float + (parameters + (declare (in) vec3 x)) + ((return (constant float (0))))) + (signature float + (parameters + (declare (in) vec4 x)) + ((return (constant float (0))))) +)) diff --git a/src/glsl/builtins/ir/noise2 b/src/glsl/builtins/ir/noise2 new file mode 100644 index 0000000000..ae4443a704 --- /dev/null +++ b/src/glsl/builtins/ir/noise2 @@ -0,0 +1,18 @@ +((function noise2 + (signature vec2 + (parameters + (declare (in) float x)) + ((return (constant vec2 (0 0))))) + (signature vec2 + (parameters + (declare (in) vec2 x)) + ((return (constant vec2 (0 0))))) + (signature vec2 + (parameters + (declare (in) vec3 x)) + ((return (constant vec2 (0 0))))) + (signature vec2 + (parameters + (declare (in) vec4 x)) + ((return (constant vec2 (0 0))))) +)) diff --git a/src/glsl/builtins/ir/noise3 b/src/glsl/builtins/ir/noise3 new file mode 100644 index 0000000000..30d9681890 --- /dev/null +++ b/src/glsl/builtins/ir/noise3 @@ -0,0 +1,18 @@ +((function noise3 + (signature vec3 + (parameters + (declare (in) float x)) + ((return (constant vec3 (0 0 0))))) + (signature vec3 + (parameters + (declare (in) vec2 x)) + ((return (constant vec3 (0 0 0))))) + (signature vec3 + (parameters + (declare (in) vec3 x)) + ((return (constant vec3 (0 0 0))))) + (signature vec3 + (parameters + (declare (in) vec4 x)) + ((return (constant vec3 (0 0 0))))) +)) diff --git a/src/glsl/builtins/ir/noise4 b/src/glsl/builtins/ir/noise4 new file mode 100644 index 0000000000..913bef2aa1 --- /dev/null +++ b/src/glsl/builtins/ir/noise4 @@ -0,0 +1,18 @@ +((function noise4 + (signature vec4 + (parameters + (declare (in) float x)) + ((return (constant vec4 (0 0 0 0))))) + (signature vec4 + (parameters + (declare (in) vec2 x)) + ((return (constant vec4 (0 0 0 0))))) + (signature vec4 + (parameters + (declare (in) vec3 x)) + ((return (constant vec4 (0 0 0 0))))) + (signature vec4 + (parameters + (declare (in) vec4 x)) + ((return (constant vec4 (0 0 0 0))))) +)) diff --git a/src/glsl/builtins/ir/normalize b/src/glsl/builtins/ir/normalize new file mode 100644 index 0000000000..be88a9830d --- /dev/null +++ b/src/glsl/builtins/ir/normalize @@ -0,0 +1,21 @@ +((function normalize + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float * (var_ref arg0) (expression float rsq (expression float dot (var_ref arg0) (var_ref arg0))))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 * (var_ref arg0) (expression float rsq (expression float dot (var_ref arg0) (var_ref arg0))))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 * (var_ref arg0) (expression float rsq (expression float dot (var_ref arg0) (var_ref arg0))))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 * (var_ref arg0) (expression float rsq (expression float dot (var_ref arg0) (var_ref arg0))))))) +)) diff --git a/src/glsl/builtins/ir/not b/src/glsl/builtins/ir/not new file mode 100644 index 0000000000..b696b06557 --- /dev/null +++ b/src/glsl/builtins/ir/not @@ -0,0 +1,16 @@ +((function not + (signature bvec2 + (parameters + (declare (in) bvec2 arg0)) + ((return (expression bvec2 ! (var_ref arg0))))) + + (signature bvec3 + (parameters + (declare (in) bvec3 arg0)) + ((return (expression bvec3 ! (var_ref arg0))))) + + (signature bvec4 + (parameters + (declare (in) bvec4 arg0)) + ((return (expression bvec4 ! (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/notEqual b/src/glsl/builtins/ir/notEqual new file mode 100644 index 0000000000..eeeda79042 --- /dev/null +++ b/src/glsl/builtins/ir/notEqual @@ -0,0 +1,121 @@ +((function notEqual + (signature bvec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool != (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) bvec2 arg0) + (declare (in) bvec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) bvec3 arg0) + (declare (in) bvec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) bvec4 arg0) + (declare (in) bvec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool != (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) ivec2 arg0) + (declare (in) ivec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) ivec3 arg0) + (declare (in) ivec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) ivec4 arg0) + (declare (in) ivec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool != (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec2 + (parameters + (declare (in) uvec2 arg0) + (declare (in) uvec2 arg1)) + ((declare () bvec2 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec3 + (parameters + (declare (in) uvec3 arg0) + (declare (in) uvec3 arg1)) + ((declare () bvec3 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (return (var_ref temp)))) + + (signature bvec4 + (parameters + (declare (in) uvec4 arg0) + (declare (in) uvec4 arg1)) + ((declare () bvec4 temp) + (assign (constant bool (1)) (swiz x (var_ref temp)) (expression bool != (swiz x (var_ref arg0))(swiz x (var_ref arg1)))) + (assign (constant bool (1)) (swiz y (var_ref temp)) (expression bool != (swiz y (var_ref arg0))(swiz y (var_ref arg1)))) + (assign (constant bool (1)) (swiz z (var_ref temp)) (expression bool != (swiz z (var_ref arg0))(swiz z (var_ref arg1)))) + (assign (constant bool (1)) (swiz w (var_ref temp)) (expression bool != (swiz w (var_ref arg0))(swiz w (var_ref arg1)))) + (return (var_ref temp)))) +)) diff --git a/src/glsl/builtins/ir/outerProduct b/src/glsl/builtins/ir/outerProduct new file mode 100644 index 0000000000..69ae741e17 --- /dev/null +++ b/src/glsl/builtins/ir/outerProduct @@ -0,0 +1,92 @@ +((function outerProduct + (signature mat2 + (parameters + (declare (in) vec2 u) + (declare (in) vec2 v)) + ((declare () mat2 m) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec2 * (var_ref u) (swiz x (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec2 * (var_ref u) (swiz y (var_ref v)))) + (return (var_ref m)))) + + (signature mat2x3 + (parameters + (declare (in) vec3 u) + (declare (in) vec2 v)) + ((declare () mat2x3 m) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec3 * (var_ref u) (swiz x (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec3 * (var_ref u) (swiz y (var_ref v)))) + (return (var_ref m)))) + + (signature mat2x4 + (parameters + (declare (in) vec4 u) + (declare (in) vec2 v)) + ((declare () mat2x4 m) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec4 * (var_ref u) (swiz x (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec4 * (var_ref u) (swiz y (var_ref v)))) + (return (var_ref m)))) + + (signature mat3x2 + (parameters + (declare (in) vec2 u) + (declare (in) vec3 v)) + ((declare () mat3x2 m) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec2 * (var_ref u) (swiz x (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec2 * (var_ref u) (swiz y (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec2 * (var_ref u) (swiz z (var_ref v)))) + (return (var_ref m)) + )) + + (signature mat3 + (parameters + (declare (in) vec3 u) + (declare (in) vec3 v)) + ((declare () mat3 m) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec3 * (var_ref u) (swiz x (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec3 * (var_ref u) (swiz y (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec3 * (var_ref u) (swiz z (var_ref v)))) + (return (var_ref m)))) + + (signature mat3x4 + (parameters + (declare (in) vec4 u) + (declare (in) vec3 v)) + ((declare () mat3x4 m) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec4 * (var_ref u) (swiz x (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec4 * (var_ref u) (swiz y (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec4 * (var_ref u) (swiz z (var_ref v)))) + (return (var_ref m)))) + + (signature mat4x2 + (parameters + (declare (in) vec2 u) + (declare (in) vec4 v)) + ((declare () mat4x2 m) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec2 * (var_ref u) (swiz x (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec2 * (var_ref u) (swiz y (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec2 * (var_ref u) (swiz z (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (3))) (expression vec2 * (var_ref u) (swiz w (var_ref v)))) + (return (var_ref m)))) + + (signature mat4x3 + (parameters + (declare (in) vec3 u) + (declare (in) vec4 v)) + ((declare () mat4x3 m) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec3 * (var_ref u) (swiz x (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec3 * (var_ref u) (swiz y (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec3 * (var_ref u) (swiz z (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (3))) (expression vec3 * (var_ref u) (swiz w (var_ref v)))) + (return (var_ref m)))) + + (signature mat4 + (parameters + (declare (in) vec4 u) + (declare (in) vec4 v)) + ((declare () mat4 m) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (0))) (expression vec4 * (var_ref u) (swiz x (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (1))) (expression vec4 * (var_ref u) (swiz y (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (2))) (expression vec4 * (var_ref u) (swiz z (var_ref v)))) + (assign (constant bool (1)) (array_ref (var_ref m) (constant int (3))) (expression vec4 * (var_ref u) (swiz w (var_ref v)))) + (return (var_ref m)))) +)) diff --git a/src/glsl/builtins/ir/pow b/src/glsl/builtins/ir/pow new file mode 100644 index 0000000000..a61bc4418e --- /dev/null +++ b/src/glsl/builtins/ir/pow @@ -0,0 +1,25 @@ +((function pow + (signature float + (parameters + (declare (in) float arg0) + (declare (in) float arg1)) + ((return (expression float pow (var_ref arg0) (var_ref arg1))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0) + (declare (in) vec2 arg1)) + ((return (expression vec2 pow (var_ref arg0) (var_ref arg1))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0) + (declare (in) vec3 arg1)) + ((return (expression vec3 pow (var_ref arg0) (var_ref arg1))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0) + (declare (in) vec4 arg1)) + ((return (expression vec4 pow (var_ref arg0) (var_ref arg1))))) +)) diff --git a/src/glsl/builtins/ir/radians b/src/glsl/builtins/ir/radians new file mode 100644 index 0000000000..6a0f5d2e21 --- /dev/null +++ b/src/glsl/builtins/ir/radians @@ -0,0 +1,21 @@ +((function radians + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float * (var_ref arg0) (constant float (0.017453)))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 * (var_ref arg0) (constant float (0.017453)))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 * (var_ref arg0) (constant float (0.017453)))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 * (var_ref arg0) (constant float (0.017453)))))) +)) diff --git a/src/glsl/builtins/ir/reflect b/src/glsl/builtins/ir/reflect new file mode 100644 index 0000000000..8238fdc93f --- /dev/null +++ b/src/glsl/builtins/ir/reflect @@ -0,0 +1,58 @@ +((function reflect + (signature float + (parameters + (declare (in) float i) + (declare (in) float n)) + ((return (expression float - + (var_ref i) + (expression float * + (constant float (2.0)) + (expression float * + (expression float dot + (var_ref n) + (var_ref i)) + (var_ref n))))))) + + (signature vec2 + (parameters + (declare (in) vec2 i) + (declare (in) vec2 n)) + ((return (expression vec2 - + (var_ref i) + (expression vec2 * + (constant float (2.0)) + (expression vec2 * + (expression float dot + (var_ref n) + (var_ref i)) + (var_ref n))))))) + + (signature vec3 + (parameters + (declare (in) vec3 i) + (declare (in) vec3 n)) + ((return (expression vec3 - + (var_ref i) + (expression vec3 * + (constant float (2.0)) + (expression vec3 * + (expression float dot + (var_ref n) + (var_ref i)) + (var_ref n))))))) + + (signature vec4 + (parameters + (declare (in) vec4 i) + (declare (in) vec4 n)) + ((return (expression vec4 - + (var_ref i) + (expression vec4 * + (constant float (2.0)) + (expression vec4 * + (expression float dot + (var_ref n) + (var_ref i)) + (var_ref n))))))) + +)) diff --git a/src/glsl/builtins/ir/refract b/src/glsl/builtins/ir/refract new file mode 100644 index 0000000000..522ab41173 --- /dev/null +++ b/src/glsl/builtins/ir/refract @@ -0,0 +1,102 @@ +((function refract + (signature float + (parameters + (declare (in) float i) + (declare (in) float n) + (declare (in) float eta)) + ((declare () float k) + (assign (constant bool (1)) (var_ref k) + (expression float - (constant float (1.0)) + (expression float * (var_ref eta) + (expression float * (var_ref eta) + (expression float - (constant float (1.0)) + (expression float * + (expression float dot (var_ref n) (var_ref i)) + (expression float dot (var_ref n) (var_ref i)))))))) + (if (expression bool < (var_ref k) (constant float (0.0))) + ((return (constant float (0.0)))) + ((return (expression float - + (expression float * (var_ref eta) (var_ref i)) + (expression float * + (expression float + + (expression float * (var_ref eta) + (expression float dot (var_ref n) (var_ref i))) + (expression float sqrt (var_ref k))) + (var_ref n)))))))) + + (signature vec2 + (parameters + (declare (in) vec2 i) + (declare (in) vec2 n) + (declare (in) float eta)) + ((declare () float k) + (assign (constant bool (1)) (var_ref k) + (expression float - (constant float (1.0)) + (expression float * (var_ref eta) + (expression float * (var_ref eta) + (expression float - (constant float (1.0)) + (expression float * + (expression float dot (var_ref n) (var_ref i)) + (expression float dot (var_ref n) (var_ref i)))))))) + (if (expression bool < (var_ref k) (constant float (0.0))) + ((return (constant vec2 (0.0 0.0)))) + ((return (expression vec2 - + (expression vec2 * (var_ref eta) (var_ref i)) + (expression vec2 * + (expression float + + (expression float * (var_ref eta) + (expression float dot (var_ref n) (var_ref i))) + (expression float sqrt (var_ref k))) + (var_ref n)))))))) + + (signature vec3 + (parameters + (declare (in) vec3 i) + (declare (in) vec3 n) + (declare (in) float eta)) + ((declare () float k) + (assign (constant bool (1)) (var_ref k) + (expression float - (constant float (1.0)) + (expression float * (var_ref eta) + (expression float * (var_ref eta) + (expression float - (constant float (1.0)) + (expression float * + (expression float dot (var_ref n) (var_ref i)) + (expression float dot (var_ref n) (var_ref i)))))))) + (if (expression bool < (var_ref k) (constant float (0.0))) + ((return (constant vec3 (0.0 0.0 0.0)))) + ((return (expression vec3 - + (expression vec3 * (var_ref eta) (var_ref i)) + (expression vec3 * + (expression float + + (expression float * (var_ref eta) + (expression float dot (var_ref n) (var_ref i))) + (expression float sqrt (var_ref k))) + (var_ref n)))))))) + + (signature vec4 + (parameters + (declare (in) vec4 i) + (declare (in) vec4 n) + (declare (in) float eta)) + ((declare () float k) + (assign (constant bool (1)) (var_ref k) + (expression float - (constant float (1.0)) + (expression float * (var_ref eta) + (expression float * (var_ref eta) + (expression float - (constant float (1.0)) + (expression float * + (expression float dot (var_ref n) (var_ref i)) + (expression float dot (var_ref n) (var_ref i)))))))) + (if (expression bool < (var_ref k) (constant float (0.0))) + ((return (constant vec4 (0.0 0.0 0.0 0.0)))) + ((return (expression vec4 - + (expression vec4 * (var_ref eta) (var_ref i)) + (expression vec4 * + (expression float + + (expression float * (var_ref eta) + (expression float dot (var_ref n) (var_ref i))) + (expression float sqrt (var_ref k))) + (var_ref n)))))))) + +)) diff --git a/src/glsl/builtins/ir/sign b/src/glsl/builtins/ir/sign new file mode 100644 index 0000000000..1f51718dab --- /dev/null +++ b/src/glsl/builtins/ir/sign @@ -0,0 +1,42 @@ +((function sign + (signature float + (parameters + (declare (in) float x)) + ((return (expression float sign (var_ref x))))) + + (signature vec2 + (parameters + (declare (in) vec2 x)) + ((return (expression vec2 sign (var_ref x))))) + + (signature vec3 + (parameters + (declare (in) vec3 x)) + ((return (expression vec3 sign (var_ref x))))) + + (signature vec4 + (parameters + (declare (in) vec4 x)) + ((return (expression vec4 sign (var_ref x))))) + + (signature int + (parameters + (declare (in) int x)) + ((return (expression int sign (var_ref x))))) + + (signature ivec2 + (parameters + (declare (in) ivec2 x)) + ((return (expression ivec2 sign (var_ref x))))) + + (signature ivec3 + (parameters + (declare (in) ivec3 x)) + ((return (expression ivec3 sign (var_ref x))))) + + (signature ivec4 + (parameters + (declare (in) ivec4 x)) + ((return (expression ivec4 sign (var_ref x))))) +)) + diff --git a/src/glsl/builtins/ir/sin b/src/glsl/builtins/ir/sin new file mode 100644 index 0000000000..e6009d8ef1 --- /dev/null +++ b/src/glsl/builtins/ir/sin @@ -0,0 +1,21 @@ +((function sin + (signature float + (parameters + (declare (in) float angle)) + ((return (expression float sin (var_ref angle))))) + + (signature vec2 + (parameters + (declare (in) vec2 angle)) + ((return (expression vec2 sin (var_ref angle))))) + + (signature vec3 + (parameters + (declare (in) vec3 angle)) + ((return (expression vec3 sin (var_ref angle))))) + + (signature vec4 + (parameters + (declare (in) vec4 angle)) + ((return (expression vec4 sin (var_ref angle))))) +)) diff --git a/src/glsl/builtins/ir/sinh b/src/glsl/builtins/ir/sinh new file mode 100644 index 0000000000..7ad4f58e20 --- /dev/null +++ b/src/glsl/builtins/ir/sinh @@ -0,0 +1,30 @@ +((function sinh + (signature float + (parameters + (declare (in) float x)) + ((return (expression float * (constant float (0.5)) + (expression float - + (expression float exp (var_ref x)) + (expression float exp (expression float neg (var_ref x)))))))) + (signature vec2 + (parameters + (declare (in) vec2 x)) + ((return (expression vec2 * (constant vec2 (0.5)) + (expression vec2 - + (expression vec2 exp (var_ref x)) + (expression vec2 exp (expression vec2 neg (var_ref x)))))))) + (signature vec3 + (parameters + (declare (in) vec3 x)) + ((return (expression vec3 * (constant vec3 (0.5)) + (expression vec3 - + (expression vec3 exp (var_ref x)) + (expression vec3 exp (expression vec3 neg (var_ref x)))))))) + (signature vec4 + (parameters + (declare (in) vec4 x)) + ((return (expression vec4 * (constant vec4 (0.5)) + (expression vec4 - + (expression vec4 exp (var_ref x)) + (expression vec4 exp (expression vec4 neg (var_ref x)))))))) +)) diff --git a/src/glsl/builtins/ir/smoothstep b/src/glsl/builtins/ir/smoothstep new file mode 100644 index 0000000000..663eec6341 --- /dev/null +++ b/src/glsl/builtins/ir/smoothstep @@ -0,0 +1,153 @@ +((function smoothstep + (signature float + (parameters + (declare (in) float edge0) + (declare (in) float edge1) + (declare (in) float x)) + ((declare () float t) + + (assign (constant bool (1)) (var_ref t) + (expression float max + (expression float min + (expression float / (expression float - (var_ref x) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (return (expression float * (var_ref t) (expression float * (var_ref t) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (var_ref t)))))))) + + (signature vec2 + (parameters + (declare (in) float edge0) + (declare (in) float edge1) + (declare (in) vec2 x)) + ((declare () vec2 t) + (declare () vec2 retval) + + (assign (constant bool (1)) (swiz x (var_ref t)) + (expression float max + (expression float min + (expression float / (expression float - (swiz x (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (assign (constant bool (1)) (swiz x (var_ref retval)) (expression float * (swiz x (var_ref t)) (expression float * (swiz x (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz x (var_ref t))))))) + + (assign (constant bool (1)) (swiz y (var_ref t)) + (expression float max + (expression float min + (expression float / (expression float - (swiz y (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (assign (constant bool (1)) (swiz y (var_ref retval)) (expression float * (swiz y (var_ref t)) (expression float * (swiz y (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz y (var_ref t))))))) + (return (var_ref retval)) + )) + + (signature vec3 + (parameters + (declare (in) float edge0) + (declare (in) float edge1) + (declare (in) vec3 x)) + ((declare () vec3 t) + (declare () vec3 retval) + + (assign (constant bool (1)) (swiz x (var_ref t)) + (expression float max + (expression float min + (expression float / (expression float - (swiz x (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (assign (constant bool (1)) (swiz x (var_ref retval)) (expression float * (swiz x (var_ref t)) (expression float * (swiz x (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz x (var_ref t))))))) + + (assign (constant bool (1)) (swiz y (var_ref t)) + (expression float max + (expression float min + (expression float / (expression float - (swiz y (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (assign (constant bool (1)) (swiz y (var_ref retval)) (expression float * (swiz y (var_ref t)) (expression float * (swiz y (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz y (var_ref t))))))) + + (assign (constant bool (1)) (swiz z (var_ref t)) + (expression float max + (expression float min + (expression float / (expression float - (swiz z (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (assign (constant bool (1)) (swiz z (var_ref retval)) (expression float * (swiz z (var_ref t)) (expression float * (swiz z (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz z (var_ref t))))))) + (return (var_ref retval)) + )) + + + (signature vec4 + (parameters + (declare (in) float edge0) + (declare (in) float edge1) + (declare (in) vec4 x)) + ((declare () vec4 t) + (declare () vec4 retval) + + (assign (constant bool (1)) (swiz x (var_ref t)) + (expression float max + (expression float min + (expression float / (expression float - (swiz x (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (assign (constant bool (1)) (swiz x (var_ref retval)) (expression float * (swiz x (var_ref t)) (expression float * (swiz x (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz x (var_ref t))))))) + + (assign (constant bool (1)) (swiz y (var_ref t)) + (expression float max + (expression float min + (expression float / (expression float - (swiz y (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (assign (constant bool (1)) (swiz y (var_ref retval)) (expression float * (swiz y (var_ref t)) (expression float * (swiz y (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz y (var_ref t))))))) + + (assign (constant bool (1)) (swiz z (var_ref t)) + (expression float max + (expression float min + (expression float / (expression float - (swiz z (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (assign (constant bool (1)) (swiz z (var_ref retval)) (expression float * (swiz z (var_ref t)) (expression float * (swiz z (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz z (var_ref t))))))) + + (assign (constant bool (1)) (swiz w (var_ref t)) + (expression float max + (expression float min + (expression float / (expression float - (swiz w (var_ref x)) (var_ref edge0)) (expression float - (var_ref edge1) (var_ref edge0))) + (constant float (1.0))) + (constant float (0.0)))) + (assign (constant bool (1)) (swiz w (var_ref retval)) (expression float * (swiz w (var_ref t)) (expression float * (swiz w (var_ref t)) (expression float - (constant float (3.000000)) (expression float * (constant float (2.000000)) (swiz w (var_ref t))))))) + (return (var_ref retval)) + )) + + (signature vec2 + (parameters + (declare (in) vec2 edge0) + (declare (in) vec2 edge1) + (declare (in) vec2 x)) + ((return (expression vec2 max + (expression vec2 min + (expression vec2 / (expression vec2 - (var_ref x) (var_ref edge0)) (expression vec2 - (var_ref edge1) (var_ref edge0))) + (constant vec2 (1.0 1.0))) + (constant vec2 (0.0 0.0)))))) + + (signature vec3 + (parameters + (declare (in) vec3 edge0) + (declare (in) vec3 edge1) + (declare (in) vec3 x)) + ((return (expression vec3 max + (expression vec3 min + (expression vec3 / (expression vec3 - (var_ref x) (var_ref edge0)) (expression vec3 - (var_ref edge1) (var_ref edge0))) + (constant vec3 (1.0 1.0 1.0))) + (constant vec3 (0.0 0.0 0.0)))))) + + (signature vec4 + (parameters + (declare (in) vec4 edge0) + (declare (in) vec4 edge1) + (declare (in) vec4 x)) + ((return (expression vec4 max + (expression vec4 min + (expression vec4 / (expression vec4 - (var_ref x) (var_ref edge0)) (expression vec4 - (var_ref edge1) (var_ref edge0))) + (constant vec4 (1.0 1.0 1.0 1.0))) + (constant vec4 (0.0 0.0 0.0 0.0)))))) +)) + diff --git a/src/glsl/builtins/ir/sqrt b/src/glsl/builtins/ir/sqrt new file mode 100644 index 0000000000..0302d164ae --- /dev/null +++ b/src/glsl/builtins/ir/sqrt @@ -0,0 +1,21 @@ +((function sqrt + (signature float + (parameters + (declare (in) float arg0)) + ((return (expression float sqrt (var_ref arg0))))) + + (signature vec2 + (parameters + (declare (in) vec2 arg0)) + ((return (expression vec2 sqrt (var_ref arg0))))) + + (signature vec3 + (parameters + (declare (in) vec3 arg0)) + ((return (expression vec3 sqrt (var_ref arg0))))) + + (signature vec4 + (parameters + (declare (in) vec4 arg0)) + ((return (expression vec4 sqrt (var_ref arg0))))) +)) diff --git a/src/glsl/builtins/ir/step b/src/glsl/builtins/ir/step new file mode 100644 index 0000000000..ce6f435422 --- /dev/null +++ b/src/glsl/builtins/ir/step @@ -0,0 +1,68 @@ +((function step + (signature float + (parameters + (declare (in) float edge) + (declare (in) float x)) + ((return (expression float b2f (expression bool >= (var_ref x) (var_ref edge)))))) + + (signature vec2 + (parameters + (declare (in) float edge) + (declare (in) vec2 x)) + ((declare () vec2 t) + (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(var_ref edge)))) + (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(var_ref edge)))) + (return (var_ref t)))) + + (signature vec3 + (parameters + (declare (in) float edge) + (declare (in) vec3 x)) + ((declare () vec3 t) + (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(var_ref edge)))) + (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(var_ref edge)))) + (assign (constant bool (1)) (swiz z (var_ref t)) (expression float b2f (expression bool >= (swiz z (var_ref x))(var_ref edge)))) + (return (var_ref t)))) + + (signature vec4 + (parameters + (declare (in) float edge) + (declare (in) vec4 x)) + ((declare () vec4 t) + (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(var_ref edge)))) + (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(var_ref edge)))) + (assign (constant bool (1)) (swiz z (var_ref t)) (expression float b2f (expression bool >= (swiz z (var_ref x))(var_ref edge)))) + (assign (constant bool (1)) (swiz w (var_ref t)) (expression float b2f (expression bool >= (swiz w (var_ref x))(var_ref edge)))) + (return (var_ref t)))) + + (signature vec2 + (parameters + (declare (in) vec2 edge) + (declare (in) vec2 x)) + ((declare () vec2 t) + (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(swiz x (var_ref edge))))) + (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(swiz y (var_ref edge))))) + (return (var_ref t)))) + + (signature vec3 + (parameters + (declare (in) vec3 edge) + (declare (in) vec3 x)) + ((declare () vec3 t) + (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(swiz x (var_ref edge))))) + (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(swiz y (var_ref edge))))) + (assign (constant bool (1)) (swiz z (var_ref t)) (expression float b2f (expression bool >= (swiz z (var_ref x))(swiz z (var_ref edge))))) + (return (var_ref t)))) + + (signature vec4 + (parameters + (declare (in) vec4 edge) + (declare (in) vec4 x)) + ((declare () vec4 t) + (assign (constant bool (1)) (swiz x (var_ref t)) (expression float b2f (expression bool >= (swiz x (var_ref x))(swiz x (var_ref edge))))) + (assign (constant bool (1)) (swiz y (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(swiz y (var_ref edge))))) + (assign (constant bool (1)) (swiz z (var_ref t)) (expression float b2f (expression bool >= (swiz y (var_ref x))(swiz z (var_ref edge))))) + (assign (constant bool (1)) (swiz w (var_ref t)) (expression float b2f (expression bool >= (swiz w (var_ref x))(swiz w (var_ref edge))))) + (return (var_ref t)))) +)) + diff --git a/src/glsl/builtins/ir/tan b/src/glsl/builtins/ir/tan new file mode 100644 index 0000000000..9979863185 --- /dev/null +++ b/src/glsl/builtins/ir/tan @@ -0,0 +1,21 @@ +((function tan + (signature float + (parameters + (declare (in) float angle)) + ((return (expression float / (expression float sin (var_ref angle)) (expression float cos (var_ref angle)))))) + + (signature vec2 + (parameters + (declare (in) vec2 angle)) + ((return (expression vec2 / (expression vec2 sin (var_ref angle)) (expression vec2 cos (var_ref angle)))))) + + (signature vec3 + (parameters + (declare (in) vec3 angle)) + ((return (expression vec3 / (expression vec3 sin (var_ref angle)) (expression vec3 cos (var_ref angle)))))) + + (signature vec4 + (parameters + (declare (in) vec4 angle)) + ((return (expression vec4 / (expression vec4 sin (var_ref angle)) (expression vec4 cos (var_ref angle)))))) +)) diff --git a/src/glsl/builtins/ir/tanh b/src/glsl/builtins/ir/tanh new file mode 100644 index 0000000000..3b7271bf77 --- /dev/null +++ b/src/glsl/builtins/ir/tanh @@ -0,0 +1,42 @@ +((function tanh + (signature float + (parameters + (declare (in) float x)) + ((return (expression float / + (expression float - + (expression float exp (var_ref x)) + (expression float exp (expression float neg (var_ref x)))) + (expression float + + (expression float exp (var_ref x)) + (expression float exp (expression float neg (var_ref x)))))))) + (signature vec2 + (parameters + (declare (in) vec2 x)) + ((return (expression vec2 / + (expression vec2 - + (expression vec2 exp (var_ref x)) + (expression vec2 exp (expression vec2 neg (var_ref x)))) + (expression vec2 + + (expression vec2 exp (var_ref x)) + (expression vec2 exp (expression vec2 neg (var_ref x)))))))) + (signature vec3 + (parameters + (declare (in) vec3 x)) + ((return (expression vec3 / + (expression vec3 - + (expression vec3 exp (var_ref x)) + (expression vec3 exp (expression vec3 neg (var_ref x)))) + (expression vec3 + + (expression vec3 exp (var_ref x)) + (expression vec3 exp (expression vec3 neg (var_ref x)))))))) + (signature vec4 + (parameters + (declare (in) vec4 x)) + ((return (expression vec4 / + (expression vec4 - + (expression vec4 exp (var_ref x)) + (expression vec4 exp (expression vec4 neg (var_ref x)))) + (expression vec4 + + (expression vec4 exp (var_ref x)) + (expression vec4 exp (expression vec4 neg (var_ref x)))))))) +)) diff --git a/src/glsl/builtins/ir/transpose b/src/glsl/builtins/ir/transpose new file mode 100644 index 0000000000..416a0ee467 --- /dev/null +++ b/src/glsl/builtins/ir/transpose @@ -0,0 +1,139 @@ +((function transpose + (signature mat2 + (parameters + (declare (in) mat2 m)) + ((declare () mat2 t) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) +(return (var_ref t)))) + + (signature mat3x2 + (parameters + (declare (in) mat2x3 m)) + ((declare () mat3x2 t) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) +(return (var_ref t)))) + + (signature mat4x2 + (parameters + (declare (in) mat2x4 m)) + ((declare () mat4x2 t) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (1))))) +(return (var_ref t)))) + + (signature mat2x3 + (parameters + (declare (in) mat3x2 m)) + ((declare () mat2x3 t) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) +(return (var_ref t)))) + + (signature mat3 + (parameters + (declare (in) mat3 m)) + ((declare () mat3 t) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (2))))) +(return (var_ref t)))) + + (signature mat4x3 + (parameters + (declare (in) mat3x4 m)) + ((declare () mat4x3 t) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (2))))) +(return (var_ref t)))) + + (signature mat2x4 + (parameters + (declare (in) mat4x2 m)) + ((declare () mat2x4 t) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (3))))) + (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (3))))) +(return (var_ref t)))) + + (signature mat3x4 + (parameters + (declare (in) mat4x3 m)) + ((declare () mat3x4 t) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (3))))) + (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (3))))) + (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (3))))) +(return (var_ref t)))) + + (signature mat4 + (parameters + (declare (in) mat4 m)) + ((declare () mat4 t) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz x (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (0))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz y (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (1))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz z (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (2))))) + (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (0)))) (swiz x (array_ref (var_ref m) (constant int (3))))) + (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (1)))) (swiz y (array_ref (var_ref m) (constant int (3))))) + (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (2)))) (swiz z (array_ref (var_ref m) (constant int (3))))) + (assign (constant bool (1)) (swiz w (array_ref (var_ref t) (constant int (3)))) (swiz w (array_ref (var_ref m) (constant int (3))))) +(return (var_ref t)))) +) + +) + diff --git a/src/glsl/builtins/profiles/110.frag b/src/glsl/builtins/profiles/110.frag new file mode 100644 index 0000000000..25bc62c093 --- /dev/null +++ b/src/glsl/builtins/profiles/110.frag @@ -0,0 +1,364 @@ +#version 110 +/* + * 8.1 - Angle and Trigonometry Functions + */ +float radians(float degrees); +vec2 radians(vec2 degrees); +vec3 radians(vec3 degrees); +vec4 radians(vec4 degrees); + +float degrees(float radians); +vec2 degrees(vec2 radians); +vec3 degrees(vec3 radians); +vec4 degrees(vec4 radians); + +float sin(float angle); +vec2 sin(vec2 angle); +vec3 sin(vec3 angle); +vec4 sin(vec4 angle); + +float cos(float angle); +vec2 cos(vec2 angle); +vec3 cos(vec3 angle); +vec4 cos(vec4 angle); + +float tan(float angle); +vec2 tan(vec2 angle); +vec3 tan(vec3 angle); +vec4 tan(vec4 angle); + +float asin(float angle); +vec2 asin(vec2 angle); +vec3 asin(vec3 angle); +vec4 asin(vec4 angle); + +float acos(float angle); +vec2 acos(vec2 angle); +vec3 acos(vec3 angle); +vec4 acos(vec4 angle); + +float atan(float y, float x); +vec2 atan(vec2 y, vec2 x); +vec3 atan(vec3 y, vec3 x); +vec4 atan(vec4 y, vec4 x); + +float atan(float y_over_x); +vec2 atan(vec2 y_over_x); +vec3 atan(vec3 y_over_x); +vec4 atan(vec4 y_over_x); + +/* + * 8.2 - Exponential Functions + */ +float pow(float x, float y); +vec2 pow(vec2 x, vec2 y); +vec3 pow(vec3 x, vec3 y); +vec4 pow(vec4 x, vec4 y); + +float exp(float x); +vec2 exp(vec2 x); +vec3 exp(vec3 x); +vec4 exp(vec4 x); + +float log(float x); +vec2 log(vec2 x); +vec3 log(vec3 x); +vec4 log(vec4 x); + +float exp2(float x); +vec2 exp2(vec2 x); +vec3 exp2(vec3 x); +vec4 exp2(vec4 x); + +float log2(float x); +vec2 log2(vec2 x); +vec3 log2(vec3 x); +vec4 log2(vec4 x); + +float sqrt(float x); +vec2 sqrt(vec2 x); +vec3 sqrt(vec3 x); +vec4 sqrt(vec4 x); + +float inversesqrt(float x); +vec2 inversesqrt(vec2 x); +vec3 inversesqrt(vec3 x); +vec4 inversesqrt(vec4 x); + +/* + * 8.3 - Common Functions + */ +float abs(float x); +vec2 abs(vec2 x); +vec3 abs(vec3 x); +vec4 abs(vec4 x); + +float sign(float x); +vec2 sign(vec2 x); +vec3 sign(vec3 x); +vec4 sign(vec4 x); + +float floor(float x); +vec2 floor(vec2 x); +vec3 floor(vec3 x); +vec4 floor(vec4 x); + +float ceil(float x); +vec2 ceil(vec2 x); +vec3 ceil(vec3 x); +vec4 ceil(vec4 x); + +float fract(float x); +vec2 fract(vec2 x); +vec3 fract(vec3 x); +vec4 fract(vec4 x); + +float mod(float x, float y); +vec2 mod(vec2 x, float y); +vec3 mod(vec3 x, float y); +vec4 mod(vec4 x, float y); + +vec2 mod(vec2 x, vec2 y); +vec3 mod(vec3 x, vec3 y); +vec4 mod(vec4 x, vec4 y); + +float min(float x, float y); +vec2 min(vec2 x, vec2 y); +vec3 min(vec3 x, vec3 y); +vec4 min(vec4 x, vec4 y); + +vec2 min(vec2 x, float y); +vec3 min(vec3 x, float y); +vec4 min(vec4 x, float y); + +float max(float x, float y); +vec2 max(vec2 x, vec2 y); +vec3 max(vec3 x, vec3 y); +vec4 max(vec4 x, vec4 y); + +vec2 max(vec2 x, float y); +vec3 max(vec3 x, float y); +vec4 max(vec4 x, float y); + +float clamp(float x, float minVal, float maxVal); +vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal); +vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal); +vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal); + +vec2 clamp(vec2 x, float minVal, float maxVal); +vec3 clamp(vec3 x, float minVal, float maxVal); +vec4 clamp(vec4 x, float minVal, float maxVal); + +float mix(float x, float y, float a); +vec2 mix(vec2 x, vec2 y, vec2 a); +vec3 mix(vec3 x, vec3 y, vec3 a); +vec4 mix(vec4 x, vec4 y, vec4 a); + +vec2 mix(vec2 x, vec2 y, float a); +vec3 mix(vec3 x, vec3 y, float a); +vec4 mix(vec4 x, vec4 y, float a); + +float step(float edge, float x); +vec2 step(vec2 edge, vec2 x); +vec3 step(vec3 edge, vec3 x); +vec4 step(vec4 edge, vec4 x); + +vec2 step(float edge, vec2 x); +vec3 step(float edge, vec3 x); +vec4 step(float edge, vec4 x); + +float smoothstep(float edge0, float edge1, float x); +vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x); +vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x); +vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x); + +vec2 smoothstep(float edge0, float edge1, vec2 x); +vec3 smoothstep(float edge0, float edge1, vec3 x); +vec4 smoothstep(float edge0, float edge1, vec4 x); + +/* + * 8.4 - Geometric Functions + */ +float length(float x); +float length(vec2 x); +float length(vec3 x); +float length(vec4 x); + +float distance(float p0, float p1); +float distance(vec2 p0, vec2 p1); +float distance(vec3 p0, vec3 p1); +float distance(vec4 p0, vec4 p1); + +float dot(float x, float y); +float dot(vec2 x, vec2 y); +float dot(vec3 x, vec3 y); +float dot(vec4 x, vec4 y); + +vec3 cross(vec3 x, vec3 y); + +float normalize(float x); +vec2 normalize(vec2 x); +vec3 normalize(vec3 x); +vec4 normalize(vec4 x); + +float faceforward(float N, float I, float Nref); +vec2 faceforward(vec2 N, vec2 I, vec2 Nref); +vec3 faceforward(vec3 N, vec3 I, vec3 Nref); +vec4 faceforward(vec4 N, vec4 I, vec4 Nref); + +float reflect(float I, float N); +vec2 reflect(vec2 I, vec2 N); +vec3 reflect(vec3 I, vec3 N); +vec4 reflect(vec4 I, vec4 N); + +float refract(float I, float N, float eta); +vec2 refract(vec2 I, vec2 N, float eta); +vec3 refract(vec3 I, vec3 N, float eta); +vec4 refract(vec4 I, vec4 N, float eta); + + +/* + * 8.5 - Matrix Functions + */ +mat2 matrixCompMult(mat2 x, mat2 y); +mat3 matrixCompMult(mat3 x, mat3 y); +mat4 matrixCompMult(mat4 x, mat4 y); + +/* + * 8.6 - Vector Relational Functions + */ +bvec2 lessThan( vec2 x, vec2 y); +bvec3 lessThan( vec3 x, vec3 y); +bvec4 lessThan( vec4 x, vec4 y); +bvec2 lessThan(ivec2 x, ivec2 y); +bvec3 lessThan(ivec3 x, ivec3 y); +bvec4 lessThan(ivec4 x, ivec4 y); + +bvec2 lessThanEqual( vec2 x, vec2 y); +bvec3 lessThanEqual( vec3 x, vec3 y); +bvec4 lessThanEqual( vec4 x, vec4 y); +bvec2 lessThanEqual(ivec2 x, ivec2 y); +bvec3 lessThanEqual(ivec3 x, ivec3 y); +bvec4 lessThanEqual(ivec4 x, ivec4 y); + +bvec2 greaterThan( vec2 x, vec2 y); +bvec3 greaterThan( vec3 x, vec3 y); +bvec4 greaterThan( vec4 x, vec4 y); +bvec2 greaterThan(ivec2 x, ivec2 y); +bvec3 greaterThan(ivec3 x, ivec3 y); +bvec4 greaterThan(ivec4 x, ivec4 y); + +bvec2 greaterThanEqual( vec2 x, vec2 y); +bvec3 greaterThanEqual( vec3 x, vec3 y); +bvec4 greaterThanEqual( vec4 x, vec4 y); +bvec2 greaterThanEqual(ivec2 x, ivec2 y); +bvec3 greaterThanEqual(ivec3 x, ivec3 y); +bvec4 greaterThanEqual(ivec4 x, ivec4 y); + +bvec2 equal( vec2 x, vec2 y); +bvec3 equal( vec3 x, vec3 y); +bvec4 equal( vec4 x, vec4 y); +bvec2 equal(ivec2 x, ivec2 y); +bvec3 equal(ivec3 x, ivec3 y); +bvec4 equal(ivec4 x, ivec4 y); +bvec2 equal(bvec2 x, bvec2 y); +bvec3 equal(bvec3 x, bvec3 y); +bvec4 equal(bvec4 x, bvec4 y); + +bvec2 notEqual( vec2 x, vec2 y); +bvec3 notEqual( vec3 x, vec3 y); +bvec4 notEqual( vec4 x, vec4 y); +bvec2 notEqual(ivec2 x, ivec2 y); +bvec3 notEqual(ivec3 x, ivec3 y); +bvec4 notEqual(ivec4 x, ivec4 y); +bvec2 notEqual(bvec2 x, bvec2 y); +bvec3 notEqual(bvec3 x, bvec3 y); +bvec4 notEqual(bvec4 x, bvec4 y); + +bool any(bvec2 x); +bool any(bvec3 x); +bool any(bvec4 x); + +bool all(bvec2 x); +bool all(bvec3 x); +bool all(bvec4 x); + +bvec2 not(bvec2 x); +bvec3 not(bvec3 x); +bvec4 not(bvec4 x); + +/* + * 8.7 - Texture Lookup Functions + */ +vec4 texture1D (sampler1D sampler, float coord); +vec4 texture1DProj (sampler1D sampler, vec2 coord); +vec4 texture1DProj (sampler1D sampler, vec4 coord); +vec4 texture1D (sampler1D sampler, float coord, float bias); +vec4 texture1DProj (sampler1D sampler, vec2 coord, float bias); +vec4 texture1DProj (sampler1D sampler, vec4 coord, float bias); + +vec4 texture2D (sampler2D sampler, vec2 coord); +vec4 texture2DProj (sampler2D sampler, vec3 coord); +vec4 texture2DProj (sampler2D sampler, vec4 coord); +vec4 texture2D (sampler2D sampler, vec2 coord, float bias); +vec4 texture2DProj (sampler2D sampler, vec3 coord, float bias); +vec4 texture2DProj (sampler2D sampler, vec4 coord, float bias); + +vec4 texture3D (sampler3D sampler, vec3 coord); +vec4 texture3DProj (sampler3D sampler, vec4 coord); +vec4 texture3D (sampler3D sampler, vec3 coord, float bias); +vec4 texture3DProj (sampler3D sampler, vec4 coord, float bias); + +vec4 textureCube (samplerCube sampler, vec3 coord); +vec4 textureCube (samplerCube sampler, vec3 coord, float bias); + +vec4 shadow1D (sampler1DShadow sampler, vec3 coord); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord); +vec4 shadow1D (sampler1DShadow sampler, vec3 coord, float bias); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord, float bias); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord, float bias); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord, float bias); + + +/* + * 8.8 - Fragment Processing Functions + */ +float dFdx(float p); +vec2 dFdx(vec2 p); +vec3 dFdx(vec3 p); +vec4 dFdx(vec4 p); + +float dFdy(float p); +vec2 dFdy(vec2 p); +vec3 dFdy(vec3 p); +vec4 dFdy(vec4 p); + +float fwidth(float p); +vec2 fwidth(vec2 p); +vec3 fwidth(vec3 p); +vec4 fwidth(vec4 p); + +/* + * 8.9 - Noise Functions + */ +float noise1(float x); +float noise1(vec2 x); +float noise1(vec3 x); +float noise1(vec4 x); + +vec2 noise2(float x); +vec2 noise2(vec2 x); +vec2 noise2(vec3 x); +vec2 noise2(vec4 x); + +vec3 noise3(float x); +vec3 noise3(vec2 x); +vec3 noise3(vec3 x); +vec3 noise3(vec4 x); + +vec4 noise4(float x); +vec4 noise4(vec2 x); +vec4 noise4(vec3 x); +vec4 noise4(vec4 x); diff --git a/src/glsl/builtins/profiles/110.vert b/src/glsl/builtins/profiles/110.vert new file mode 100644 index 0000000000..545e59c539 --- /dev/null +++ b/src/glsl/builtins/profiles/110.vert @@ -0,0 +1,351 @@ +#version 110 +/* + * 8.1 - Angle and Trigonometry Functions + */ +float radians(float degrees); +vec2 radians(vec2 degrees); +vec3 radians(vec3 degrees); +vec4 radians(vec4 degrees); + +float degrees(float radians); +vec2 degrees(vec2 radians); +vec3 degrees(vec3 radians); +vec4 degrees(vec4 radians); + +float sin(float angle); +vec2 sin(vec2 angle); +vec3 sin(vec3 angle); +vec4 sin(vec4 angle); + +float cos(float angle); +vec2 cos(vec2 angle); +vec3 cos(vec3 angle); +vec4 cos(vec4 angle); + +float tan(float angle); +vec2 tan(vec2 angle); +vec3 tan(vec3 angle); +vec4 tan(vec4 angle); + +float asin(float angle); +vec2 asin(vec2 angle); +vec3 asin(vec3 angle); +vec4 asin(vec4 angle); + +float acos(float angle); +vec2 acos(vec2 angle); +vec3 acos(vec3 angle); +vec4 acos(vec4 angle); + +float atan(float y, float x); +vec2 atan(vec2 y, vec2 x); +vec3 atan(vec3 y, vec3 x); +vec4 atan(vec4 y, vec4 x); + +float atan(float y_over_x); +vec2 atan(vec2 y_over_x); +vec3 atan(vec3 y_over_x); +vec4 atan(vec4 y_over_x); + +/* + * 8.2 - Exponential Functions + */ +float pow(float x, float y); +vec2 pow(vec2 x, vec2 y); +vec3 pow(vec3 x, vec3 y); +vec4 pow(vec4 x, vec4 y); + +float exp(float x); +vec2 exp(vec2 x); +vec3 exp(vec3 x); +vec4 exp(vec4 x); + +float log(float x); +vec2 log(vec2 x); +vec3 log(vec3 x); +vec4 log(vec4 x); + +float exp2(float x); +vec2 exp2(vec2 x); +vec3 exp2(vec3 x); +vec4 exp2(vec4 x); + +float log2(float x); +vec2 log2(vec2 x); +vec3 log2(vec3 x); +vec4 log2(vec4 x); + +float sqrt(float x); +vec2 sqrt(vec2 x); +vec3 sqrt(vec3 x); +vec4 sqrt(vec4 x); + +float inversesqrt(float x); +vec2 inversesqrt(vec2 x); +vec3 inversesqrt(vec3 x); +vec4 inversesqrt(vec4 x); + +/* + * 8.3 - Common Functions + */ +float abs(float x); +vec2 abs(vec2 x); +vec3 abs(vec3 x); +vec4 abs(vec4 x); + +float sign(float x); +vec2 sign(vec2 x); +vec3 sign(vec3 x); +vec4 sign(vec4 x); + +float floor(float x); +vec2 floor(vec2 x); +vec3 floor(vec3 x); +vec4 floor(vec4 x); + +float ceil(float x); +vec2 ceil(vec2 x); +vec3 ceil(vec3 x); +vec4 ceil(vec4 x); + +float fract(float x); +vec2 fract(vec2 x); +vec3 fract(vec3 x); +vec4 fract(vec4 x); + +float mod(float x, float y); +vec2 mod(vec2 x, float y); +vec3 mod(vec3 x, float y); +vec4 mod(vec4 x, float y); + +vec2 mod(vec2 x, vec2 y); +vec3 mod(vec3 x, vec3 y); +vec4 mod(vec4 x, vec4 y); + +float min(float x, float y); +vec2 min(vec2 x, vec2 y); +vec3 min(vec3 x, vec3 y); +vec4 min(vec4 x, vec4 y); + +vec2 min(vec2 x, float y); +vec3 min(vec3 x, float y); +vec4 min(vec4 x, float y); + +float max(float x, float y); +vec2 max(vec2 x, vec2 y); +vec3 max(vec3 x, vec3 y); +vec4 max(vec4 x, vec4 y); + +vec2 max(vec2 x, float y); +vec3 max(vec3 x, float y); +vec4 max(vec4 x, float y); + +float clamp(float x, float minVal, float maxVal); +vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal); +vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal); +vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal); + +vec2 clamp(vec2 x, float minVal, float maxVal); +vec3 clamp(vec3 x, float minVal, float maxVal); +vec4 clamp(vec4 x, float minVal, float maxVal); + +float mix(float x, float y, float a); +vec2 mix(vec2 x, vec2 y, vec2 a); +vec3 mix(vec3 x, vec3 y, vec3 a); +vec4 mix(vec4 x, vec4 y, vec4 a); + +vec2 mix(vec2 x, vec2 y, float a); +vec3 mix(vec3 x, vec3 y, float a); +vec4 mix(vec4 x, vec4 y, float a); + +float step(float edge, float x); +vec2 step(vec2 edge, vec2 x); +vec3 step(vec3 edge, vec3 x); +vec4 step(vec4 edge, vec4 x); + +vec2 step(float edge, vec2 x); +vec3 step(float edge, vec3 x); +vec4 step(float edge, vec4 x); + +float smoothstep(float edge0, float edge1, float x); +vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x); +vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x); +vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x); + +vec2 smoothstep(float edge0, float edge1, vec2 x); +vec3 smoothstep(float edge0, float edge1, vec3 x); +vec4 smoothstep(float edge0, float edge1, vec4 x); + +/* + * 8.4 - Geometric Functions + */ +float length(float x); +float length(vec2 x); +float length(vec3 x); +float length(vec4 x); + +float distance(float p0, float p1); +float distance(vec2 p0, vec2 p1); +float distance(vec3 p0, vec3 p1); +float distance(vec4 p0, vec4 p1); + +float dot(float x, float y); +float dot(vec2 x, vec2 y); +float dot(vec3 x, vec3 y); +float dot(vec4 x, vec4 y); + +vec3 cross(vec3 x, vec3 y); + +float normalize(float x); +vec2 normalize(vec2 x); +vec3 normalize(vec3 x); +vec4 normalize(vec4 x); + +vec4 ftransform(); + +float faceforward(float N, float I, float Nref); +vec2 faceforward(vec2 N, vec2 I, vec2 Nref); +vec3 faceforward(vec3 N, vec3 I, vec3 Nref); +vec4 faceforward(vec4 N, vec4 I, vec4 Nref); + +float reflect(float I, float N); +vec2 reflect(vec2 I, vec2 N); +vec3 reflect(vec3 I, vec3 N); +vec4 reflect(vec4 I, vec4 N); + +float refract(float I, float N, float eta); +vec2 refract(vec2 I, vec2 N, float eta); +vec3 refract(vec3 I, vec3 N, float eta); +vec4 refract(vec4 I, vec4 N, float eta); + + +/* + * 8.5 - Matrix Functions + */ +mat2 matrixCompMult(mat2 x, mat2 y); +mat3 matrixCompMult(mat3 x, mat3 y); +mat4 matrixCompMult(mat4 x, mat4 y); + +/* + * 8.6 - Vector Relational Functions + */ +bvec2 lessThan( vec2 x, vec2 y); +bvec3 lessThan( vec3 x, vec3 y); +bvec4 lessThan( vec4 x, vec4 y); +bvec2 lessThan(ivec2 x, ivec2 y); +bvec3 lessThan(ivec3 x, ivec3 y); +bvec4 lessThan(ivec4 x, ivec4 y); + +bvec2 lessThanEqual( vec2 x, vec2 y); +bvec3 lessThanEqual( vec3 x, vec3 y); +bvec4 lessThanEqual( vec4 x, vec4 y); +bvec2 lessThanEqual(ivec2 x, ivec2 y); +bvec3 lessThanEqual(ivec3 x, ivec3 y); +bvec4 lessThanEqual(ivec4 x, ivec4 y); + +bvec2 greaterThan( vec2 x, vec2 y); +bvec3 greaterThan( vec3 x, vec3 y); +bvec4 greaterThan( vec4 x, vec4 y); +bvec2 greaterThan(ivec2 x, ivec2 y); +bvec3 greaterThan(ivec3 x, ivec3 y); +bvec4 greaterThan(ivec4 x, ivec4 y); + +bvec2 greaterThanEqual( vec2 x, vec2 y); +bvec3 greaterThanEqual( vec3 x, vec3 y); +bvec4 greaterThanEqual( vec4 x, vec4 y); +bvec2 greaterThanEqual(ivec2 x, ivec2 y); +bvec3 greaterThanEqual(ivec3 x, ivec3 y); +bvec4 greaterThanEqual(ivec4 x, ivec4 y); + +bvec2 equal( vec2 x, vec2 y); +bvec3 equal( vec3 x, vec3 y); +bvec4 equal( vec4 x, vec4 y); +bvec2 equal(ivec2 x, ivec2 y); +bvec3 equal(ivec3 x, ivec3 y); +bvec4 equal(ivec4 x, ivec4 y); +bvec2 equal(bvec2 x, bvec2 y); +bvec3 equal(bvec3 x, bvec3 y); +bvec4 equal(bvec4 x, bvec4 y); + +bvec2 notEqual( vec2 x, vec2 y); +bvec3 notEqual( vec3 x, vec3 y); +bvec4 notEqual( vec4 x, vec4 y); +bvec2 notEqual(ivec2 x, ivec2 y); +bvec3 notEqual(ivec3 x, ivec3 y); +bvec4 notEqual(ivec4 x, ivec4 y); +bvec2 notEqual(bvec2 x, bvec2 y); +bvec3 notEqual(bvec3 x, bvec3 y); +bvec4 notEqual(bvec4 x, bvec4 y); + +bool any(bvec2 x); +bool any(bvec3 x); +bool any(bvec4 x); + +bool all(bvec2 x); +bool all(bvec3 x); +bool all(bvec4 x); + +bvec2 not(bvec2 x); +bvec3 not(bvec3 x); +bvec4 not(bvec4 x); + +/* + * 8.7 - Texture Lookup Functions + */ +vec4 texture1D (sampler1D sampler, float coord); +vec4 texture1DProj (sampler1D sampler, vec2 coord); +vec4 texture1DProj (sampler1D sampler, vec4 coord); +vec4 texture1DLod (sampler1D sampler, float coord, float lod); +vec4 texture1DProjLod(sampler1D sampler, vec2 coord, float lod); +vec4 texture1DProjLod(sampler1D sampler, vec4 coord, float lod); + +vec4 texture2D (sampler2D sampler, vec2 coord); +vec4 texture2DProj (sampler2D sampler, vec3 coord); +vec4 texture2DProj (sampler2D sampler, vec4 coord); +vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod); +vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod); +vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod); + +vec4 texture3D (sampler3D sampler, vec3 coord); +vec4 texture3DProj (sampler3D sampler, vec4 coord); +vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod); +vec4 texture3DProjLod(sampler3D sampler, vec4 coord, float lod); + +vec4 textureCube (samplerCube sampler, vec3 coord); +vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod); + +vec4 shadow1D (sampler1DShadow sampler, vec3 coord); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord); +vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod); +vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod); +vec4 shadow1DProjLod(sampler1DShadow sampler, vec4 coord, float lod); +vec4 shadow2DProjLod(sampler2DShadow sampler, vec4 coord, float lod); + +/* + * 8.8 - Fragment Processing Functions (none in vertex shader) + */ + +/* + * 8.9 - Noise Functions + */ +float noise1(float x); +float noise1(vec2 x); +float noise1(vec3 x); +float noise1(vec4 x); + +vec2 noise2(float x); +vec2 noise2(vec2 x); +vec2 noise2(vec3 x); +vec2 noise2(vec4 x); + +vec3 noise3(float x); +vec3 noise3(vec2 x); +vec3 noise3(vec3 x); +vec3 noise3(vec4 x); + +vec4 noise4(float x); +vec4 noise4(vec2 x); +vec4 noise4(vec3 x); +vec4 noise4(vec4 x); diff --git a/src/glsl/builtins/profiles/120.frag b/src/glsl/builtins/profiles/120.frag new file mode 100644 index 0000000000..a207435f33 --- /dev/null +++ b/src/glsl/builtins/profiles/120.frag @@ -0,0 +1,396 @@ +#version 120 +/* + * 8.1 - Angle and Trigonometry Functions + */ +float radians(float degrees); +vec2 radians(vec2 degrees); +vec3 radians(vec3 degrees); +vec4 radians(vec4 degrees); + +float degrees(float radians); +vec2 degrees(vec2 radians); +vec3 degrees(vec3 radians); +vec4 degrees(vec4 radians); + +float sin(float angle); +vec2 sin(vec2 angle); +vec3 sin(vec3 angle); +vec4 sin(vec4 angle); + +float cos(float angle); +vec2 cos(vec2 angle); +vec3 cos(vec3 angle); +vec4 cos(vec4 angle); + +float tan(float angle); +vec2 tan(vec2 angle); +vec3 tan(vec3 angle); +vec4 tan(vec4 angle); + +float asin(float angle); +vec2 asin(vec2 angle); +vec3 asin(vec3 angle); +vec4 asin(vec4 angle); + +float acos(float angle); +vec2 acos(vec2 angle); +vec3 acos(vec3 angle); +vec4 acos(vec4 angle); + +float atan(float y, float x); +vec2 atan(vec2 y, vec2 x); +vec3 atan(vec3 y, vec3 x); +vec4 atan(vec4 y, vec4 x); + +float atan(float y_over_x); +vec2 atan(vec2 y_over_x); +vec3 atan(vec3 y_over_x); +vec4 atan(vec4 y_over_x); + +/* + * 8.2 - Exponential Functions + */ +float pow(float x, float y); +vec2 pow(vec2 x, vec2 y); +vec3 pow(vec3 x, vec3 y); +vec4 pow(vec4 x, vec4 y); + +float exp(float x); +vec2 exp(vec2 x); +vec3 exp(vec3 x); +vec4 exp(vec4 x); + +float log(float x); +vec2 log(vec2 x); +vec3 log(vec3 x); +vec4 log(vec4 x); + +float exp2(float x); +vec2 exp2(vec2 x); +vec3 exp2(vec3 x); +vec4 exp2(vec4 x); + +float log2(float x); +vec2 log2(vec2 x); +vec3 log2(vec3 x); +vec4 log2(vec4 x); + +float sqrt(float x); +vec2 sqrt(vec2 x); +vec3 sqrt(vec3 x); +vec4 sqrt(vec4 x); + +float inversesqrt(float x); +vec2 inversesqrt(vec2 x); +vec3 inversesqrt(vec3 x); +vec4 inversesqrt(vec4 x); + +/* + * 8.3 - Common Functions + */ +float abs(float x); +vec2 abs(vec2 x); +vec3 abs(vec3 x); +vec4 abs(vec4 x); + +float sign(float x); +vec2 sign(vec2 x); +vec3 sign(vec3 x); +vec4 sign(vec4 x); + +float floor(float x); +vec2 floor(vec2 x); +vec3 floor(vec3 x); +vec4 floor(vec4 x); + +float ceil(float x); +vec2 ceil(vec2 x); +vec3 ceil(vec3 x); +vec4 ceil(vec4 x); + +float fract(float x); +vec2 fract(vec2 x); +vec3 fract(vec3 x); +vec4 fract(vec4 x); + +float mod(float x, float y); +vec2 mod(vec2 x, float y); +vec3 mod(vec3 x, float y); +vec4 mod(vec4 x, float y); + +vec2 mod(vec2 x, vec2 y); +vec3 mod(vec3 x, vec3 y); +vec4 mod(vec4 x, vec4 y); + +float min(float x, float y); +vec2 min(vec2 x, vec2 y); +vec3 min(vec3 x, vec3 y); +vec4 min(vec4 x, vec4 y); + +vec2 min(vec2 x, float y); +vec3 min(vec3 x, float y); +vec4 min(vec4 x, float y); + +float max(float x, float y); +vec2 max(vec2 x, vec2 y); +vec3 max(vec3 x, vec3 y); +vec4 max(vec4 x, vec4 y); + +vec2 max(vec2 x, float y); +vec3 max(vec3 x, float y); +vec4 max(vec4 x, float y); + +float clamp(float x, float minVal, float maxVal); +vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal); +vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal); +vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal); + +vec2 clamp(vec2 x, float minVal, float maxVal); +vec3 clamp(vec3 x, float minVal, float maxVal); +vec4 clamp(vec4 x, float minVal, float maxVal); + +float mix(float x, float y, float a); +vec2 mix(vec2 x, vec2 y, vec2 a); +vec3 mix(vec3 x, vec3 y, vec3 a); +vec4 mix(vec4 x, vec4 y, vec4 a); + +vec2 mix(vec2 x, vec2 y, float a); +vec3 mix(vec3 x, vec3 y, float a); +vec4 mix(vec4 x, vec4 y, float a); + +float step(float edge, float x); +vec2 step(vec2 edge, vec2 x); +vec3 step(vec3 edge, vec3 x); +vec4 step(vec4 edge, vec4 x); + +vec2 step(float edge, vec2 x); +vec3 step(float edge, vec3 x); +vec4 step(float edge, vec4 x); + +float smoothstep(float edge0, float edge1, float x); +vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x); +vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x); +vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x); + +vec2 smoothstep(float edge0, float edge1, vec2 x); +vec3 smoothstep(float edge0, float edge1, vec3 x); +vec4 smoothstep(float edge0, float edge1, vec4 x); + +/* + * 8.4 - Geometric Functions + */ +float length(float x); +float length(vec2 x); +float length(vec3 x); +float length(vec4 x); + +float distance(float p0, float p1); +float distance(vec2 p0, vec2 p1); +float distance(vec3 p0, vec3 p1); +float distance(vec4 p0, vec4 p1); + +float dot(float x, float y); +float dot(vec2 x, vec2 y); +float dot(vec3 x, vec3 y); +float dot(vec4 x, vec4 y); + +vec3 cross(vec3 x, vec3 y); + +float normalize(float x); +vec2 normalize(vec2 x); +vec3 normalize(vec3 x); +vec4 normalize(vec4 x); + +float faceforward(float N, float I, float Nref); +vec2 faceforward(vec2 N, vec2 I, vec2 Nref); +vec3 faceforward(vec3 N, vec3 I, vec3 Nref); +vec4 faceforward(vec4 N, vec4 I, vec4 Nref); + +float reflect(float I, float N); +vec2 reflect(vec2 I, vec2 N); +vec3 reflect(vec3 I, vec3 N); +vec4 reflect(vec4 I, vec4 N); + +float refract(float I, float N, float eta); +vec2 refract(vec2 I, vec2 N, float eta); +vec3 refract(vec3 I, vec3 N, float eta); +vec4 refract(vec4 I, vec4 N, float eta); + + +/* + * 8.5 - Matrix Functions + */ +mat2 matrixCompMult(mat2 x, mat2 y); +mat3 matrixCompMult(mat3 x, mat3 y); +mat4 matrixCompMult(mat4 x, mat4 y); +mat2x3 matrixCompMult(mat2x3 x, mat2x3 y); +mat2x4 matrixCompMult(mat2x4 x, mat2x4 y); +mat3x2 matrixCompMult(mat3x2 x, mat3x2 y); +mat3x4 matrixCompMult(mat3x4 x, mat3x4 y); +mat4x2 matrixCompMult(mat4x2 x, mat4x2 y); +mat4x3 matrixCompMult(mat4x3 x, mat4x3 y); + +mat2 outerProduct(vec2 c, vec2 r); +mat3 outerProduct(vec3 c, vec3 r); +mat4 outerProduct(vec4 c, vec4 r); + +mat2x3 outerProduct(vec3 c, vec2 r); +mat3x2 outerProduct(vec2 c, vec3 r); + +mat2x4 outerProduct(vec4 c, vec2 r); +mat4x2 outerProduct(vec2 c, vec4 r); + +mat3x4 outerProduct(vec4 c, vec3 r); +mat4x3 outerProduct(vec3 c, vec4 r); + +mat2 transpose(mat2 m); +mat3 transpose(mat3 m); +mat4 transpose(mat4 m); + +mat2x3 transpose(mat3x2 m); +mat3x2 transpose(mat2x3 m); + +mat2x4 transpose(mat4x2 m); +mat4x2 transpose(mat2x4 m); + +mat3x4 transpose(mat4x3 m); +mat4x3 transpose(mat3x4 m); + +/* + * 8.6 - Vector Relational Functions + */ +bvec2 lessThan( vec2 x, vec2 y); +bvec3 lessThan( vec3 x, vec3 y); +bvec4 lessThan( vec4 x, vec4 y); +bvec2 lessThan(ivec2 x, ivec2 y); +bvec3 lessThan(ivec3 x, ivec3 y); +bvec4 lessThan(ivec4 x, ivec4 y); + +bvec2 lessThanEqual( vec2 x, vec2 y); +bvec3 lessThanEqual( vec3 x, vec3 y); +bvec4 lessThanEqual( vec4 x, vec4 y); +bvec2 lessThanEqual(ivec2 x, ivec2 y); +bvec3 lessThanEqual(ivec3 x, ivec3 y); +bvec4 lessThanEqual(ivec4 x, ivec4 y); + +bvec2 greaterThan( vec2 x, vec2 y); +bvec3 greaterThan( vec3 x, vec3 y); +bvec4 greaterThan( vec4 x, vec4 y); +bvec2 greaterThan(ivec2 x, ivec2 y); +bvec3 greaterThan(ivec3 x, ivec3 y); +bvec4 greaterThan(ivec4 x, ivec4 y); + +bvec2 greaterThanEqual( vec2 x, vec2 y); +bvec3 greaterThanEqual( vec3 x, vec3 y); +bvec4 greaterThanEqual( vec4 x, vec4 y); +bvec2 greaterThanEqual(ivec2 x, ivec2 y); +bvec3 greaterThanEqual(ivec3 x, ivec3 y); +bvec4 greaterThanEqual(ivec4 x, ivec4 y); + +bvec2 equal( vec2 x, vec2 y); +bvec3 equal( vec3 x, vec3 y); +bvec4 equal( vec4 x, vec4 y); +bvec2 equal(ivec2 x, ivec2 y); +bvec3 equal(ivec3 x, ivec3 y); +bvec4 equal(ivec4 x, ivec4 y); +bvec2 equal(bvec2 x, bvec2 y); +bvec3 equal(bvec3 x, bvec3 y); +bvec4 equal(bvec4 x, bvec4 y); + +bvec2 notEqual( vec2 x, vec2 y); +bvec3 notEqual( vec3 x, vec3 y); +bvec4 notEqual( vec4 x, vec4 y); +bvec2 notEqual(ivec2 x, ivec2 y); +bvec3 notEqual(ivec3 x, ivec3 y); +bvec4 notEqual(ivec4 x, ivec4 y); +bvec2 notEqual(bvec2 x, bvec2 y); +bvec3 notEqual(bvec3 x, bvec3 y); +bvec4 notEqual(bvec4 x, bvec4 y); + +bool any(bvec2 x); +bool any(bvec3 x); +bool any(bvec4 x); + +bool all(bvec2 x); +bool all(bvec3 x); +bool all(bvec4 x); + +bvec2 not(bvec2 x); +bvec3 not(bvec3 x); +bvec4 not(bvec4 x); + +/* + * 8.7 - Texture Lookup Functions + */ +vec4 texture1D (sampler1D sampler, float coord); +vec4 texture1DProj (sampler1D sampler, vec2 coord); +vec4 texture1DProj (sampler1D sampler, vec4 coord); +vec4 texture1D (sampler1D sampler, float coord, float bias); +vec4 texture1DProj (sampler1D sampler, vec2 coord, float bias); +vec4 texture1DProj (sampler1D sampler, vec4 coord, float bias); + +vec4 texture2D (sampler2D sampler, vec2 coord); +vec4 texture2DProj (sampler2D sampler, vec3 coord); +vec4 texture2DProj (sampler2D sampler, vec4 coord); +vec4 texture2D (sampler2D sampler, vec2 coord, float bias); +vec4 texture2DProj (sampler2D sampler, vec3 coord, float bias); +vec4 texture2DProj (sampler2D sampler, vec4 coord, float bias); + +vec4 texture3D (sampler3D sampler, vec3 coord); +vec4 texture3DProj (sampler3D sampler, vec4 coord); +vec4 texture3D (sampler3D sampler, vec3 coord, float bias); +vec4 texture3DProj (sampler3D sampler, vec4 coord, float bias); + +vec4 textureCube (samplerCube sampler, vec3 coord); +vec4 textureCube (samplerCube sampler, vec3 coord, float bias); + +vec4 shadow1D (sampler1DShadow sampler, vec3 coord); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord); +vec4 shadow1D (sampler1DShadow sampler, vec3 coord, float bias); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord, float bias); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord, float bias); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord, float bias); + + +/* + * 8.8 - Fragment Processing Functions + */ +float dFdx(float p); +vec2 dFdx(vec2 p); +vec3 dFdx(vec3 p); +vec4 dFdx(vec4 p); + +float dFdy(float p); +vec2 dFdy(vec2 p); +vec3 dFdy(vec3 p); +vec4 dFdy(vec4 p); + +float fwidth(float p); +vec2 fwidth(vec2 p); +vec3 fwidth(vec3 p); +vec4 fwidth(vec4 p); + +/* + * 8.9 - Noise Functions + */ +float noise1(float x); +float noise1(vec2 x); +float noise1(vec3 x); +float noise1(vec4 x); + +vec2 noise2(float x); +vec2 noise2(vec2 x); +vec2 noise2(vec3 x); +vec2 noise2(vec4 x); + +vec3 noise3(float x); +vec3 noise3(vec2 x); +vec3 noise3(vec3 x); +vec3 noise3(vec4 x); + +vec4 noise4(float x); +vec4 noise4(vec2 x); +vec4 noise4(vec3 x); +vec4 noise4(vec4 x); diff --git a/src/glsl/builtins/profiles/120.vert b/src/glsl/builtins/profiles/120.vert new file mode 100644 index 0000000000..e14c931647 --- /dev/null +++ b/src/glsl/builtins/profiles/120.vert @@ -0,0 +1,383 @@ +#version 120 +/* + * 8.1 - Angle and Trigonometry Functions + */ +float radians(float degrees); +vec2 radians(vec2 degrees); +vec3 radians(vec3 degrees); +vec4 radians(vec4 degrees); + +float degrees(float radians); +vec2 degrees(vec2 radians); +vec3 degrees(vec3 radians); +vec4 degrees(vec4 radians); + +float sin(float angle); +vec2 sin(vec2 angle); +vec3 sin(vec3 angle); +vec4 sin(vec4 angle); + +float cos(float angle); +vec2 cos(vec2 angle); +vec3 cos(vec3 angle); +vec4 cos(vec4 angle); + +float tan(float angle); +vec2 tan(vec2 angle); +vec3 tan(vec3 angle); +vec4 tan(vec4 angle); + +float asin(float angle); +vec2 asin(vec2 angle); +vec3 asin(vec3 angle); +vec4 asin(vec4 angle); + +float acos(float angle); +vec2 acos(vec2 angle); +vec3 acos(vec3 angle); +vec4 acos(vec4 angle); + +float atan(float y, float x); +vec2 atan(vec2 y, vec2 x); +vec3 atan(vec3 y, vec3 x); +vec4 atan(vec4 y, vec4 x); + +float atan(float y_over_x); +vec2 atan(vec2 y_over_x); +vec3 atan(vec3 y_over_x); +vec4 atan(vec4 y_over_x); + +/* + * 8.2 - Exponential Functions + */ +float pow(float x, float y); +vec2 pow(vec2 x, vec2 y); +vec3 pow(vec3 x, vec3 y); +vec4 pow(vec4 x, vec4 y); + +float exp(float x); +vec2 exp(vec2 x); +vec3 exp(vec3 x); +vec4 exp(vec4 x); + +float log(float x); +vec2 log(vec2 x); +vec3 log(vec3 x); +vec4 log(vec4 x); + +float exp2(float x); +vec2 exp2(vec2 x); +vec3 exp2(vec3 x); +vec4 exp2(vec4 x); + +float log2(float x); +vec2 log2(vec2 x); +vec3 log2(vec3 x); +vec4 log2(vec4 x); + +float sqrt(float x); +vec2 sqrt(vec2 x); +vec3 sqrt(vec3 x); +vec4 sqrt(vec4 x); + +float inversesqrt(float x); +vec2 inversesqrt(vec2 x); +vec3 inversesqrt(vec3 x); +vec4 inversesqrt(vec4 x); + +/* + * 8.3 - Common Functions + */ +float abs(float x); +vec2 abs(vec2 x); +vec3 abs(vec3 x); +vec4 abs(vec4 x); + +float sign(float x); +vec2 sign(vec2 x); +vec3 sign(vec3 x); +vec4 sign(vec4 x); + +float floor(float x); +vec2 floor(vec2 x); +vec3 floor(vec3 x); +vec4 floor(vec4 x); + +float ceil(float x); +vec2 ceil(vec2 x); +vec3 ceil(vec3 x); +vec4 ceil(vec4 x); + +float fract(float x); +vec2 fract(vec2 x); +vec3 fract(vec3 x); +vec4 fract(vec4 x); + +float mod(float x, float y); +vec2 mod(vec2 x, float y); +vec3 mod(vec3 x, float y); +vec4 mod(vec4 x, float y); + +vec2 mod(vec2 x, vec2 y); +vec3 mod(vec3 x, vec3 y); +vec4 mod(vec4 x, vec4 y); + +float min(float x, float y); +vec2 min(vec2 x, vec2 y); +vec3 min(vec3 x, vec3 y); +vec4 min(vec4 x, vec4 y); + +vec2 min(vec2 x, float y); +vec3 min(vec3 x, float y); +vec4 min(vec4 x, float y); + +float max(float x, float y); +vec2 max(vec2 x, vec2 y); +vec3 max(vec3 x, vec3 y); +vec4 max(vec4 x, vec4 y); + +vec2 max(vec2 x, float y); +vec3 max(vec3 x, float y); +vec4 max(vec4 x, float y); + +float clamp(float x, float minVal, float maxVal); +vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal); +vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal); +vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal); + +vec2 clamp(vec2 x, float minVal, float maxVal); +vec3 clamp(vec3 x, float minVal, float maxVal); +vec4 clamp(vec4 x, float minVal, float maxVal); + +float mix(float x, float y, float a); +vec2 mix(vec2 x, vec2 y, vec2 a); +vec3 mix(vec3 x, vec3 y, vec3 a); +vec4 mix(vec4 x, vec4 y, vec4 a); + +vec2 mix(vec2 x, vec2 y, float a); +vec3 mix(vec3 x, vec3 y, float a); +vec4 mix(vec4 x, vec4 y, float a); + +float step(float edge, float x); +vec2 step(vec2 edge, vec2 x); +vec3 step(vec3 edge, vec3 x); +vec4 step(vec4 edge, vec4 x); + +vec2 step(float edge, vec2 x); +vec3 step(float edge, vec3 x); +vec4 step(float edge, vec4 x); + +float smoothstep(float edge0, float edge1, float x); +vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x); +vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x); +vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x); + +vec2 smoothstep(float edge0, float edge1, vec2 x); +vec3 smoothstep(float edge0, float edge1, vec3 x); +vec4 smoothstep(float edge0, float edge1, vec4 x); + +/* + * 8.4 - Geometric Functions + */ +float length(float x); +float length(vec2 x); +float length(vec3 x); +float length(vec4 x); + +float distance(float p0, float p1); +float distance(vec2 p0, vec2 p1); +float distance(vec3 p0, vec3 p1); +float distance(vec4 p0, vec4 p1); + +float dot(float x, float y); +float dot(vec2 x, vec2 y); +float dot(vec3 x, vec3 y); +float dot(vec4 x, vec4 y); + +vec3 cross(vec3 x, vec3 y); + +float normalize(float x); +vec2 normalize(vec2 x); +vec3 normalize(vec3 x); +vec4 normalize(vec4 x); + +vec4 ftransform(); + +float faceforward(float N, float I, float Nref); +vec2 faceforward(vec2 N, vec2 I, vec2 Nref); +vec3 faceforward(vec3 N, vec3 I, vec3 Nref); +vec4 faceforward(vec4 N, vec4 I, vec4 Nref); + +float reflect(float I, float N); +vec2 reflect(vec2 I, vec2 N); +vec3 reflect(vec3 I, vec3 N); +vec4 reflect(vec4 I, vec4 N); + +float refract(float I, float N, float eta); +vec2 refract(vec2 I, vec2 N, float eta); +vec3 refract(vec3 I, vec3 N, float eta); +vec4 refract(vec4 I, vec4 N, float eta); + + +/* + * 8.5 - Matrix Functions + */ +mat2 matrixCompMult(mat2 x, mat2 y); +mat3 matrixCompMult(mat3 x, mat3 y); +mat4 matrixCompMult(mat4 x, mat4 y); +mat2x3 matrixCompMult(mat2x3 x, mat2x3 y); +mat2x4 matrixCompMult(mat2x4 x, mat2x4 y); +mat3x2 matrixCompMult(mat3x2 x, mat3x2 y); +mat3x4 matrixCompMult(mat3x4 x, mat3x4 y); +mat4x2 matrixCompMult(mat4x2 x, mat4x2 y); +mat4x3 matrixCompMult(mat4x3 x, mat4x3 y); + +mat2 outerProduct(vec2 c, vec2 r); +mat3 outerProduct(vec3 c, vec3 r); +mat4 outerProduct(vec4 c, vec4 r); + +mat2x3 outerProduct(vec3 c, vec2 r); +mat3x2 outerProduct(vec2 c, vec3 r); + +mat2x4 outerProduct(vec4 c, vec2 r); +mat4x2 outerProduct(vec2 c, vec4 r); + +mat3x4 outerProduct(vec4 c, vec3 r); +mat4x3 outerProduct(vec3 c, vec4 r); + +mat2 transpose(mat2 m); +mat3 transpose(mat3 m); +mat4 transpose(mat4 m); + +mat2x3 transpose(mat3x2 m); +mat3x2 transpose(mat2x3 m); + +mat2x4 transpose(mat4x2 m); +mat4x2 transpose(mat2x4 m); + +mat3x4 transpose(mat4x3 m); +mat4x3 transpose(mat3x4 m); + +/* + * 8.6 - Vector Relational Functions + */ +bvec2 lessThan( vec2 x, vec2 y); +bvec3 lessThan( vec3 x, vec3 y); +bvec4 lessThan( vec4 x, vec4 y); +bvec2 lessThan(ivec2 x, ivec2 y); +bvec3 lessThan(ivec3 x, ivec3 y); +bvec4 lessThan(ivec4 x, ivec4 y); + +bvec2 lessThanEqual( vec2 x, vec2 y); +bvec3 lessThanEqual( vec3 x, vec3 y); +bvec4 lessThanEqual( vec4 x, vec4 y); +bvec2 lessThanEqual(ivec2 x, ivec2 y); +bvec3 lessThanEqual(ivec3 x, ivec3 y); +bvec4 lessThanEqual(ivec4 x, ivec4 y); + +bvec2 greaterThan( vec2 x, vec2 y); +bvec3 greaterThan( vec3 x, vec3 y); +bvec4 greaterThan( vec4 x, vec4 y); +bvec2 greaterThan(ivec2 x, ivec2 y); +bvec3 greaterThan(ivec3 x, ivec3 y); +bvec4 greaterThan(ivec4 x, ivec4 y); + +bvec2 greaterThanEqual( vec2 x, vec2 y); +bvec3 greaterThanEqual( vec3 x, vec3 y); +bvec4 greaterThanEqual( vec4 x, vec4 y); +bvec2 greaterThanEqual(ivec2 x, ivec2 y); +bvec3 greaterThanEqual(ivec3 x, ivec3 y); +bvec4 greaterThanEqual(ivec4 x, ivec4 y); + +bvec2 equal( vec2 x, vec2 y); +bvec3 equal( vec3 x, vec3 y); +bvec4 equal( vec4 x, vec4 y); +bvec2 equal(ivec2 x, ivec2 y); +bvec3 equal(ivec3 x, ivec3 y); +bvec4 equal(ivec4 x, ivec4 y); +bvec2 equal(bvec2 x, bvec2 y); +bvec3 equal(bvec3 x, bvec3 y); +bvec4 equal(bvec4 x, bvec4 y); + +bvec2 notEqual( vec2 x, vec2 y); +bvec3 notEqual( vec3 x, vec3 y); +bvec4 notEqual( vec4 x, vec4 y); +bvec2 notEqual(ivec2 x, ivec2 y); +bvec3 notEqual(ivec3 x, ivec3 y); +bvec4 notEqual(ivec4 x, ivec4 y); +bvec2 notEqual(bvec2 x, bvec2 y); +bvec3 notEqual(bvec3 x, bvec3 y); +bvec4 notEqual(bvec4 x, bvec4 y); + +bool any(bvec2 x); +bool any(bvec3 x); +bool any(bvec4 x); + +bool all(bvec2 x); +bool all(bvec3 x); +bool all(bvec4 x); + +bvec2 not(bvec2 x); +bvec3 not(bvec3 x); +bvec4 not(bvec4 x); + +/* + * 8.7 - Texture Lookup Functions + */ +vec4 texture1D (sampler1D sampler, float coord); +vec4 texture1DProj (sampler1D sampler, vec2 coord); +vec4 texture1DProj (sampler1D sampler, vec4 coord); +vec4 texture1DLod (sampler1D sampler, float coord, float lod); +vec4 texture1DProjLod(sampler1D sampler, vec2 coord, float lod); +vec4 texture1DProjLod(sampler1D sampler, vec4 coord, float lod); + +vec4 texture2D (sampler2D sampler, vec2 coord); +vec4 texture2DProj (sampler2D sampler, vec3 coord); +vec4 texture2DProj (sampler2D sampler, vec4 coord); +vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod); +vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod); +vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod); + +vec4 texture3D (sampler3D sampler, vec3 coord); +vec4 texture3DProj (sampler3D sampler, vec4 coord); +vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod); +vec4 texture3DProjLod(sampler3D sampler, vec4 coord, float lod); + +vec4 textureCube (samplerCube sampler, vec3 coord); +vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod); + +vec4 shadow1D (sampler1DShadow sampler, vec3 coord); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord); +vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod); +vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod); +vec4 shadow1DProjLod(sampler1DShadow sampler, vec4 coord, float lod); +vec4 shadow2DProjLod(sampler2DShadow sampler, vec4 coord, float lod); + +/* + * 8.8 - Fragment Processing Functions (none in vertex shader) + */ + +/* + * 8.9 - Noise Functions + */ +float noise1(float x); +float noise1(vec2 x); +float noise1(vec3 x); +float noise1(vec4 x); + +vec2 noise2(float x); +vec2 noise2(vec2 x); +vec2 noise2(vec3 x); +vec2 noise2(vec4 x); + +vec3 noise3(float x); +vec3 noise3(vec2 x); +vec3 noise3(vec3 x); +vec3 noise3(vec4 x); + +vec4 noise4(float x); +vec4 noise4(vec2 x); +vec4 noise4(vec3 x); +vec4 noise4(vec4 x); diff --git a/src/glsl/builtins/profiles/130.frag b/src/glsl/builtins/profiles/130.frag new file mode 100644 index 0000000000..aa7a6adb1d --- /dev/null +++ b/src/glsl/builtins/profiles/130.frag @@ -0,0 +1,1031 @@ +#version 130 +/* + * 8.1 - Angle and Trigonometry Functions + */ +float radians(float degrees); +vec2 radians(vec2 degrees); +vec3 radians(vec3 degrees); +vec4 radians(vec4 degrees); + +float degrees(float radians); +vec2 degrees(vec2 radians); +vec3 degrees(vec3 radians); +vec4 degrees(vec4 radians); + +float sin(float angle); +vec2 sin(vec2 angle); +vec3 sin(vec3 angle); +vec4 sin(vec4 angle); + +float cos(float angle); +vec2 cos(vec2 angle); +vec3 cos(vec3 angle); +vec4 cos(vec4 angle); + +float tan(float angle); +vec2 tan(vec2 angle); +vec3 tan(vec3 angle); +vec4 tan(vec4 angle); + +float asin(float angle); +vec2 asin(vec2 angle); +vec3 asin(vec3 angle); +vec4 asin(vec4 angle); + +float acos(float angle); +vec2 acos(vec2 angle); +vec3 acos(vec3 angle); +vec4 acos(vec4 angle); + +float atan(float y, float x); +vec2 atan(vec2 y, vec2 x); +vec3 atan(vec3 y, vec3 x); +vec4 atan(vec4 y, vec4 x); + +float atan(float y_over_x); +vec2 atan(vec2 y_over_x); +vec3 atan(vec3 y_over_x); +vec4 atan(vec4 y_over_x); + +float sinh(float x); +vec2 sinh(vec2 x); +vec3 sinh(vec3 x); +vec4 sinh(vec4 x); + +float cosh(float x); +vec2 cosh(vec2 x); +vec3 cosh(vec3 x); +vec4 cosh(vec4 x); + +float tanh(float x); +vec2 tanh(vec2 x); +vec3 tanh(vec3 x); +vec4 tanh(vec4 x); + +#if 0 +float asinh(float x); +vec2 asinh(vec2 x); +vec3 asinh(vec3 x); +vec4 asinh(vec4 x); + +float acosh(float x); +vec2 acosh(vec2 x); +vec3 acosh(vec3 x); +vec4 acosh(vec4 x); + +float atanh(float x); +vec2 atanh(vec2 x); +vec3 atanh(vec3 x); +vec4 atanh(vec4 x); +#endif + +/* + * 8.2 - Exponential Functions + */ +float pow(float x, float y); +vec2 pow(vec2 x, vec2 y); +vec3 pow(vec3 x, vec3 y); +vec4 pow(vec4 x, vec4 y); + +float exp(float x); +vec2 exp(vec2 x); +vec3 exp(vec3 x); +vec4 exp(vec4 x); + +float log(float x); +vec2 log(vec2 x); +vec3 log(vec3 x); +vec4 log(vec4 x); + +float exp2(float x); +vec2 exp2(vec2 x); +vec3 exp2(vec3 x); +vec4 exp2(vec4 x); + +float log2(float x); +vec2 log2(vec2 x); +vec3 log2(vec3 x); +vec4 log2(vec4 x); + +float sqrt(float x); +vec2 sqrt(vec2 x); +vec3 sqrt(vec3 x); +vec4 sqrt(vec4 x); + +float inversesqrt(float x); +vec2 inversesqrt(vec2 x); +vec3 inversesqrt(vec3 x); +vec4 inversesqrt(vec4 x); + +/* + * 8.3 - Common Functions + */ +float abs(float x); +vec2 abs(vec2 x); +vec3 abs(vec3 x); +vec4 abs(vec4 x); +int abs(int x); +ivec2 abs(ivec2 x); +ivec3 abs(ivec3 x); +ivec4 abs(ivec4 x); + +float sign(float x); +vec2 sign(vec2 x); +vec3 sign(vec3 x); +vec4 sign(vec4 x); +int sign(int x); +ivec2 sign(ivec2 x); +ivec3 sign(ivec3 x); +ivec4 sign(ivec4 x); + +float floor(float x); +vec2 floor(vec2 x); +vec3 floor(vec3 x); +vec4 floor(vec4 x); + +float ceil(float x); +vec2 ceil(vec2 x); +vec3 ceil(vec3 x); +vec4 ceil(vec4 x); + +float fract(float x); +vec2 fract(vec2 x); +vec3 fract(vec3 x); +vec4 fract(vec4 x); + +float mod(float x, float y); +vec2 mod(vec2 x, float y); +vec3 mod(vec3 x, float y); +vec4 mod(vec4 x, float y); + +vec2 mod(vec2 x, vec2 y); +vec3 mod(vec3 x, vec3 y); +vec4 mod(vec4 x, vec4 y); + +float min(float x, float y); +vec2 min(vec2 x, vec2 y); +vec3 min(vec3 x, vec3 y); +vec4 min(vec4 x, vec4 y); + +vec2 min(vec2 x, float y); +vec3 min(vec3 x, float y); +vec4 min(vec4 x, float y); + +int min(int x, int y); +ivec2 min(ivec2 x, ivec2 y); +ivec3 min(ivec3 x, ivec3 y); +ivec4 min(ivec4 x, ivec4 y); + +ivec2 min(ivec2 x, int y); +ivec3 min(ivec3 x, int y); +ivec4 min(ivec4 x, int y); + +uint min(uint x, uint y); +uvec2 min(uvec2 x, uvec2 y); +uvec3 min(uvec3 x, uvec3 y); +uvec4 min(uvec4 x, uvec4 y); + +uvec2 min(uvec2 x, uint y); +uvec3 min(uvec3 x, uint y); +uvec4 min(uvec4 x, uint y); + +float max(float x, float y); +vec2 max(vec2 x, vec2 y); +vec3 max(vec3 x, vec3 y); +vec4 max(vec4 x, vec4 y); + +vec2 max(vec2 x, float y); +vec3 max(vec3 x, float y); +vec4 max(vec4 x, float y); + +int max(int x, int y); +ivec2 max(ivec2 x, ivec2 y); +ivec3 max(ivec3 x, ivec3 y); +ivec4 max(ivec4 x, ivec4 y); + +ivec2 max(ivec2 x, int y); +ivec3 max(ivec3 x, int y); +ivec4 max(ivec4 x, int y); + +uint max(uint x, uint y); +uvec2 max(uvec2 x, uvec2 y); +uvec3 max(uvec3 x, uvec3 y); +uvec4 max(uvec4 x, uvec4 y); + +uvec2 max(uvec2 x, uint y); +uvec3 max(uvec3 x, uint y); +uvec4 max(uvec4 x, uint y); + +float clamp(float x, float minVal, float maxVal); +vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal); +vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal); +vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal); + +vec2 clamp(vec2 x, float minVal, float maxVal); +vec3 clamp(vec3 x, float minVal, float maxVal); +vec4 clamp(vec4 x, float minVal, float maxVal); + +int clamp(int x, int minVal, int maxVal); +ivec2 clamp(ivec2 x, ivec2 minVal, ivec2 maxVal); +ivec3 clamp(ivec3 x, ivec3 minVal, ivec3 maxVal); +ivec4 clamp(ivec4 x, ivec4 minVal, ivec4 maxVal); + +ivec2 clamp(ivec2 x, int minVal, int maxVal); +ivec3 clamp(ivec3 x, int minVal, int maxVal); +ivec4 clamp(ivec4 x, int minVal, int maxVal); + +uint clamp(uint x, uint minVal, uint maxVal); +uvec2 clamp(uvec2 x, uvec2 minVal, uvec2 maxVal); +uvec3 clamp(uvec3 x, uvec3 minVal, uvec3 maxVal); +uvec4 clamp(uvec4 x, uvec4 minVal, uvec4 maxVal); + +uvec2 clamp(uvec2 x, uint minVal, uint maxVal); +uvec3 clamp(uvec3 x, uint minVal, uint maxVal); +uvec4 clamp(uvec4 x, uint minVal, uint maxVal); + +float mix(float x, float y, float a); +vec2 mix(vec2 x, vec2 y, vec2 a); +vec3 mix(vec3 x, vec3 y, vec3 a); +vec4 mix(vec4 x, vec4 y, vec4 a); + +vec2 mix(vec2 x, vec2 y, float a); +vec3 mix(vec3 x, vec3 y, float a); +vec4 mix(vec4 x, vec4 y, float a); + +float step(float edge, float x); +vec2 step(vec2 edge, vec2 x); +vec3 step(vec3 edge, vec3 x); +vec4 step(vec4 edge, vec4 x); + +vec2 step(float edge, vec2 x); +vec3 step(float edge, vec3 x); +vec4 step(float edge, vec4 x); + +float smoothstep(float edge0, float edge1, float x); +vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x); +vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x); +vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x); + +vec2 smoothstep(float edge0, float edge1, vec2 x); +vec3 smoothstep(float edge0, float edge1, vec3 x); +vec4 smoothstep(float edge0, float edge1, vec4 x); + +#if 0 +bool isnan(float x); +bvec2 isnan(vec2 x); +bvec3 isnan(vec3 x); +bvec4 isnan(vec4 x); + +bool isinf(float x); +bvec2 isinf(vec2 x); +bvec3 isinf(vec3 x); +bvec4 isinf(vec4 x); +#endif + +/* + * 8.4 - Geometric Functions + */ +float length(float x); +float length(vec2 x); +float length(vec3 x); +float length(vec4 x); + +float distance(float p0, float p1); +float distance(vec2 p0, vec2 p1); +float distance(vec3 p0, vec3 p1); +float distance(vec4 p0, vec4 p1); + +float dot(float x, float y); +float dot(vec2 x, vec2 y); +float dot(vec3 x, vec3 y); +float dot(vec4 x, vec4 y); + +vec3 cross(vec3 x, vec3 y); + +float normalize(float x); +vec2 normalize(vec2 x); +vec3 normalize(vec3 x); +vec4 normalize(vec4 x); + +float faceforward(float N, float I, float Nref); +vec2 faceforward(vec2 N, vec2 I, vec2 Nref); +vec3 faceforward(vec3 N, vec3 I, vec3 Nref); +vec4 faceforward(vec4 N, vec4 I, vec4 Nref); + +float reflect(float I, float N); +vec2 reflect(vec2 I, vec2 N); +vec3 reflect(vec3 I, vec3 N); +vec4 reflect(vec4 I, vec4 N); + +float refract(float I, float N, float eta); +vec2 refract(vec2 I, vec2 N, float eta); +vec3 refract(vec3 I, vec3 N, float eta); +vec4 refract(vec4 I, vec4 N, float eta); + + +/* + * 8.5 - Matrix Functions + */ +mat2 matrixCompMult(mat2 x, mat2 y); +mat3 matrixCompMult(mat3 x, mat3 y); +mat4 matrixCompMult(mat4 x, mat4 y); +mat2x3 matrixCompMult(mat2x3 x, mat2x3 y); +mat2x4 matrixCompMult(mat2x4 x, mat2x4 y); +mat3x2 matrixCompMult(mat3x2 x, mat3x2 y); +mat3x4 matrixCompMult(mat3x4 x, mat3x4 y); +mat4x2 matrixCompMult(mat4x2 x, mat4x2 y); +mat4x3 matrixCompMult(mat4x3 x, mat4x3 y); + +mat2 outerProduct(vec2 c, vec2 r); +mat3 outerProduct(vec3 c, vec3 r); +mat4 outerProduct(vec4 c, vec4 r); + +mat2x3 outerProduct(vec3 c, vec2 r); +mat3x2 outerProduct(vec2 c, vec3 r); + +mat2x4 outerProduct(vec4 c, vec2 r); +mat4x2 outerProduct(vec2 c, vec4 r); + +mat3x4 outerProduct(vec4 c, vec3 r); +mat4x3 outerProduct(vec3 c, vec4 r); + +mat2 transpose(mat2 m); +mat3 transpose(mat3 m); +mat4 transpose(mat4 m); + +mat2x3 transpose(mat3x2 m); +mat3x2 transpose(mat2x3 m); + +mat2x4 transpose(mat4x2 m); +mat4x2 transpose(mat2x4 m); + +mat3x4 transpose(mat4x3 m); +mat4x3 transpose(mat3x4 m); + +/* + * 8.6 - Vector Relational Functions + */ +bvec2 lessThan( vec2 x, vec2 y); +bvec3 lessThan( vec3 x, vec3 y); +bvec4 lessThan( vec4 x, vec4 y); +bvec2 lessThan(ivec2 x, ivec2 y); +bvec3 lessThan(ivec3 x, ivec3 y); +bvec4 lessThan(ivec4 x, ivec4 y); +bvec2 lessThan(uvec2 x, uvec2 y); +bvec3 lessThan(uvec3 x, uvec3 y); +bvec4 lessThan(uvec4 x, uvec4 y); + +bvec2 lessThanEqual( vec2 x, vec2 y); +bvec3 lessThanEqual( vec3 x, vec3 y); +bvec4 lessThanEqual( vec4 x, vec4 y); +bvec2 lessThanEqual(ivec2 x, ivec2 y); +bvec3 lessThanEqual(ivec3 x, ivec3 y); +bvec4 lessThanEqual(ivec4 x, ivec4 y); +bvec2 lessThanEqual(uvec2 x, uvec2 y); +bvec3 lessThanEqual(uvec3 x, uvec3 y); +bvec4 lessThanEqual(uvec4 x, uvec4 y); + +bvec2 greaterThan( vec2 x, vec2 y); +bvec3 greaterThan( vec3 x, vec3 y); +bvec4 greaterThan( vec4 x, vec4 y); +bvec2 greaterThan(ivec2 x, ivec2 y); +bvec3 greaterThan(ivec3 x, ivec3 y); +bvec4 greaterThan(ivec4 x, ivec4 y); +bvec2 greaterThan(uvec2 x, uvec2 y); +bvec3 greaterThan(uvec3 x, uvec3 y); +bvec4 greaterThan(uvec4 x, uvec4 y); + +bvec2 greaterThanEqual( vec2 x, vec2 y); +bvec3 greaterThanEqual( vec3 x, vec3 y); +bvec4 greaterThanEqual( vec4 x, vec4 y); +bvec2 greaterThanEqual(ivec2 x, ivec2 y); +bvec3 greaterThanEqual(ivec3 x, ivec3 y); +bvec4 greaterThanEqual(ivec4 x, ivec4 y); +bvec2 greaterThanEqual(uvec2 x, uvec2 y); +bvec3 greaterThanEqual(uvec3 x, uvec3 y); +bvec4 greaterThanEqual(uvec4 x, uvec4 y); + +bvec2 equal( vec2 x, vec2 y); +bvec3 equal( vec3 x, vec3 y); +bvec4 equal( vec4 x, vec4 y); +bvec2 equal(ivec2 x, ivec2 y); +bvec3 equal(ivec3 x, ivec3 y); +bvec4 equal(ivec4 x, ivec4 y); +bvec2 equal(uvec2 x, uvec2 y); +bvec3 equal(uvec3 x, uvec3 y); +bvec4 equal(uvec4 x, uvec4 y); +bvec2 equal(bvec2 x, bvec2 y); +bvec3 equal(bvec3 x, bvec3 y); +bvec4 equal(bvec4 x, bvec4 y); + +bvec2 notEqual( vec2 x, vec2 y); +bvec3 notEqual( vec3 x, vec3 y); +bvec4 notEqual( vec4 x, vec4 y); +bvec2 notEqual(ivec2 x, ivec2 y); +bvec3 notEqual(ivec3 x, ivec3 y); +bvec4 notEqual(ivec4 x, ivec4 y); +bvec2 notEqual(uvec2 x, uvec2 y); +bvec3 notEqual(uvec3 x, uvec3 y); +bvec4 notEqual(uvec4 x, uvec4 y); +bvec2 notEqual(bvec2 x, bvec2 y); +bvec3 notEqual(bvec3 x, bvec3 y); +bvec4 notEqual(bvec4 x, bvec4 y); + +bool any(bvec2 x); +bool any(bvec3 x); +bool any(bvec4 x); + +bool all(bvec2 x); +bool all(bvec3 x); +bool all(bvec4 x); + +bvec2 not(bvec2 x); +bvec3 not(bvec3 x); +bvec4 not(bvec4 x); + +/* + * 8.7 - Texture Lookup Functions + */ + +#if 0 +/* textureSize */ +int textureSize( sampler1D sampler, int lod); +int textureSize(isampler1D sampler, int lod); +int textureSize(usampler1D sampler, int lod); + +ivec2 textureSize( sampler2D sampler, int lod); +ivec2 textureSize(isampler2D sampler, int lod); +ivec2 textureSize(usampler2D sampler, int lod); + +ivec3 textureSize( sampler3D sampler, int lod); +ivec3 textureSize(isampler3D sampler, int lod); +ivec3 textureSize(usampler3D sampler, int lod); + +ivec2 textureSize( samplerCube sampler, int lod); +ivec2 textureSize(isamplerCube sampler, int lod); +ivec2 textureSize(usamplerCube sampler, int lod); + +int textureSize(sampler1DShadow sampler, int lod); +ivec2 textureSize(sampler2DShadow sampler, int lod); +ivec2 textureSize(samplerCubeShadow sampler, int lod); + +ivec2 textureSize( sampler1DArray sampler, int lod); +ivec2 textureSize(isampler1DArray sampler, int lod); +ivec2 textureSize(usampler1DArray sampler, int lod); +ivec3 textureSize( sampler2DArray sampler, int lod); +ivec2 textureSize(isampler2DArray sampler, int lod); +ivec2 textureSize(usampler2DArray sampler, int lod); + +ivec2 textureSize(sampler1DArrayShadow sampler, int lod); +ivec3 textureSize(sampler2DArrayShadow sampler, int lod); +#endif + +/* texture - no bias */ + vec4 texture( sampler1D sampler, float P); +ivec4 texture(isampler1D sampler, float P); +uvec4 texture(usampler1D sampler, float P); + + vec4 texture( sampler2D sampler, vec2 P); +ivec4 texture(isampler2D sampler, vec2 P); +uvec4 texture(usampler2D sampler, vec2 P); + + vec4 texture( sampler3D sampler, vec3 P); +ivec4 texture(isampler3D sampler, vec3 P); +uvec4 texture(usampler3D sampler, vec3 P); + + vec4 texture( samplerCube sampler, vec3 P); +ivec4 texture(isamplerCube sampler, vec3 P); +uvec4 texture(usamplerCube sampler, vec3 P); + +float texture(sampler1DShadow sampler, vec3 P); +float texture(sampler2DShadow sampler, vec3 P); +float texture(samplerCubeShadow sampler, vec4 P); + + vec4 texture( sampler1DArray sampler, vec2 P); +ivec4 texture(isampler1DArray sampler, vec2 P); +uvec4 texture(usampler1DArray sampler, vec2 P); + + vec4 texture( sampler2DArray sampler, vec3 P); +ivec4 texture(isampler2DArray sampler, vec3 P); +uvec4 texture(usampler2DArray sampler, vec3 P); + +float texture(sampler1DArrayShadow sampler, vec3 P); +float texture(sampler2DArrayShadow sampler, vec4 P); + +/* texture - bias variants */ + vec4 texture( sampler1D sampler, float P, float bias); +ivec4 texture(isampler1D sampler, float P, float bias); +uvec4 texture(usampler1D sampler, float P, float bias); + + vec4 texture( sampler2D sampler, vec2 P, float bias); +ivec4 texture(isampler2D sampler, vec2 P, float bias); +uvec4 texture(usampler2D sampler, vec2 P, float bias); + + vec4 texture( sampler3D sampler, vec3 P, float bias); +ivec4 texture(isampler3D sampler, vec3 P, float bias); +uvec4 texture(usampler3D sampler, vec3 P, float bias); + + vec4 texture( samplerCube sampler, vec3 P, float bias); +ivec4 texture(isamplerCube sampler, vec3 P, float bias); +uvec4 texture(usamplerCube sampler, vec3 P, float bias); + +float texture(sampler1DShadow sampler, vec3 P, float bias); +float texture(sampler2DShadow sampler, vec3 P, float bias); +float texture(samplerCubeShadow sampler, vec4 P, float bias); + + vec4 texture( sampler1DArray sampler, vec2 P, float bias); +ivec4 texture(isampler1DArray sampler, vec2 P, float bias); +uvec4 texture(usampler1DArray sampler, vec2 P, float bias); + + vec4 texture( sampler2DArray sampler, vec3 P, float bias); +ivec4 texture(isampler2DArray sampler, vec3 P, float bias); +uvec4 texture(usampler2DArray sampler, vec3 P, float bias); + +float texture(sampler1DArrayShadow sampler, vec3 P, float bias); + +/* textureProj - no bias */ + vec4 textureProj( sampler1D sampler, vec2 P); +ivec4 textureProj(isampler1D sampler, vec2 P); +uvec4 textureProj(usampler1D sampler, vec2 P); + vec4 textureProj( sampler1D sampler, vec4 P); +ivec4 textureProj(isampler1D sampler, vec4 P); +uvec4 textureProj(usampler1D sampler, vec4 P); + + vec4 textureProj( sampler2D sampler, vec3 P); +ivec4 textureProj(isampler2D sampler, vec3 P); +uvec4 textureProj(usampler2D sampler, vec3 P); + vec4 textureProj( sampler2D sampler, vec4 P); +ivec4 textureProj(isampler2D sampler, vec4 P); +uvec4 textureProj(usampler2D sampler, vec4 P); + + vec4 textureProj( sampler3D sampler, vec4 P); +ivec4 textureProj(isampler3D sampler, vec4 P); +uvec4 textureProj(usampler3D sampler, vec4 P); + +float textureProj(sampler1DShadow sampler, vec4 P); +float textureProj(sampler2DShadow sampler, vec4 P); + +/* textureProj - bias variants */ + vec4 textureProj( sampler1D sampler, vec2 P, float bias); +ivec4 textureProj(isampler1D sampler, vec2 P, float bias); +uvec4 textureProj(usampler1D sampler, vec2 P, float bias); + vec4 textureProj( sampler1D sampler, vec4 P, float bias); +ivec4 textureProj(isampler1D sampler, vec4 P, float bias); +uvec4 textureProj(usampler1D sampler, vec4 P, float bias); + + vec4 textureProj( sampler2D sampler, vec3 P, float bias); +ivec4 textureProj(isampler2D sampler, vec3 P, float bias); +uvec4 textureProj(usampler2D sampler, vec3 P, float bias); + vec4 textureProj( sampler2D sampler, vec4 P, float bias); +ivec4 textureProj(isampler2D sampler, vec4 P, float bias); +uvec4 textureProj(usampler2D sampler, vec4 P, float bias); + + vec4 textureProj( sampler3D sampler, vec4 P, float bias); +ivec4 textureProj(isampler3D sampler, vec4 P, float bias); +uvec4 textureProj(usampler3D sampler, vec4 P, float bias); + +float textureProj(sampler1DShadow sampler, vec4 P, float bias); +float textureProj(sampler2DShadow sampler, vec4 P, float bias); + +/* textureLod */ + vec4 textureLod( sampler1D sampler, float P, float lod); +ivec4 textureLod(isampler1D sampler, float P, float lod); +uvec4 textureLod(usampler1D sampler, float P, float lod); + + vec4 textureLod( sampler2D sampler, vec2 P, float lod); +ivec4 textureLod(isampler2D sampler, vec2 P, float lod); +uvec4 textureLod(usampler2D sampler, vec2 P, float lod); + + vec4 textureLod( sampler3D sampler, vec3 P, float lod); +ivec4 textureLod(isampler3D sampler, vec3 P, float lod); +uvec4 textureLod(usampler3D sampler, vec3 P, float lod); + + vec4 textureLod( samplerCube sampler, vec3 P, float lod); +ivec4 textureLod(isamplerCube sampler, vec3 P, float lod); +uvec4 textureLod(usamplerCube sampler, vec3 P, float lod); + +float textureLod(sampler1DShadow sampler, vec3 P, float lod); +float textureLod(sampler2DShadow sampler, vec3 P, float lod); + + vec4 textureLod( sampler1DArray sampler, vec2 P, float lod); +ivec4 textureLod(isampler1DArray sampler, vec2 P, float lod); +uvec4 textureLod(usampler1DArray sampler, vec2 P, float lod); + + vec4 textureLod( sampler2DArray sampler, vec3 P, float lod); +ivec4 textureLod(isampler2DArray sampler, vec3 P, float lod); +uvec4 textureLod(usampler2DArray sampler, vec3 P, float lod); + +float textureLod(sampler1DArrayShadow sampler, vec3 P, float lod); + +#if 0 +/* textureOffset - no bias */ + vec4 textureOffset( sampler1D sampler, float P, int offset); +ivec4 textureOffset(isampler1D sampler, float P, int offset); +uvec4 textureOffset(usampler1D sampler, float P, int offset); + + vec4 textureOffset( sampler2D sampler, vec2 P, ivec2 offset); +ivec4 textureOffset(isampler2D sampler, vec2 P, ivec2 offset); +uvec4 textureOffset(usampler2D sampler, vec2 P, ivec2 offset); + + vec4 textureOffset( sampler3D sampler, vec3 P, ivec3 offset); +ivec4 textureOffset(isampler3D sampler, vec3 P, ivec3 offset); +uvec4 textureOffset(usampler3D sampler, vec3 P, ivec3 offset); + +float textureOffset(sampler1DShadow sampler, vec3 P, int offset); +float textureOffset(sampler2DShadow sampler, vec3 P, ivec2 offset); + + vec4 textureOffset( sampler1DArray sampler, vec2 P, int offset); +ivec4 textureOffset(isampler1DArray sampler, vec2 P, int offset); +uvec4 textureOffset(usampler1DArray sampler, vec2 P, int offset); + + vec4 textureOffset( sampler2DArray sampler, vec3 P, ivec2 offset); +ivec4 textureOffset(isampler2DArray sampler, vec3 P, ivec2 offset); +uvec4 textureOffset(usampler2DArray sampler, vec3 P, ivec2 offset); + +float textureOffset(sampler1DArrayShadow sampler, vec3 P, int offset); + +/* textureOffset - bias variants */ + vec4 textureOffset( sampler1D sampler, float P, int offset, float bias); +ivec4 textureOffset(isampler1D sampler, float P, int offset, float bias); +uvec4 textureOffset(usampler1D sampler, float P, int offset, float bias); + + vec4 textureOffset( sampler2D sampler, vec2 P, ivec2 offset, float bias); +ivec4 textureOffset(isampler2D sampler, vec2 P, ivec2 offset, float bias); +uvec4 textureOffset(usampler2D sampler, vec2 P, ivec2 offset, float bias); + + vec4 textureOffset( sampler3D sampler, vec3 P, ivec3 offset, float bias); +ivec4 textureOffset(isampler3D sampler, vec3 P, ivec3 offset, float bias); +uvec4 textureOffset(usampler3D sampler, vec3 P, ivec3 offset, float bias); + +float textureOffset(sampler1DShadow sampler, vec3 P, int offset, float bias); +float textureOffset(sampler2DShadow sampler, vec3 P, ivec2 offset, float bias); + + vec4 textureOffset( sampler1DArray sampler, vec2 P, int offset, float bias); +ivec4 textureOffset(isampler1DArray sampler, vec2 P, int offset, float bias); +uvec4 textureOffset(usampler1DArray sampler, vec2 P, int offset, float bias); + + vec4 textureOffset( sampler2DArray sampler, vec3 P, ivec2 offset, float bias); +ivec4 textureOffset(isampler2DArray sampler, vec3 P, ivec2 offset, float bias); +uvec4 textureOffset(usampler2DArray sampler, vec3 P, ivec2 offset, float bias); + +float textureOffset(sampler1DArrayShadow samp, vec3 P, int offset, float bias); +#endif + +/* texelFetch */ + vec4 texelFetch( sampler1D sampler, int P, int lod); +ivec4 texelFetch(isampler1D sampler, int P, int lod); +uvec4 texelFetch(usampler1D sampler, int P, int lod); + + vec4 texelFetch( sampler2D sampler, ivec2 P, int lod); +ivec4 texelFetch(isampler2D sampler, ivec2 P, int lod); +uvec4 texelFetch(usampler2D sampler, ivec2 P, int lod); + + vec4 texelFetch( sampler3D sampler, ivec3 P, int lod); +ivec4 texelFetch(isampler3D sampler, ivec3 P, int lod); +uvec4 texelFetch(usampler3D sampler, ivec3 P, int lod); + + vec4 texelFetch( sampler1DArray sampler, ivec2 P, int lod); +ivec4 texelFetch(isampler1DArray sampler, ivec2 P, int lod); +uvec4 texelFetch(usampler1DArray sampler, ivec2 P, int lod); + + vec4 texelFetch( sampler2DArray sampler, ivec3 P, int lod); +ivec4 texelFetch(isampler2DArray sampler, ivec3 P, int lod); +uvec4 texelFetch(usampler2DArray sampler, ivec3 P, int lod); + +#if 0 +/* texelFetchOffset */ + vec4 texelFetchOffset( sampler1D sampler, int P, int lod, int offset); +ivec4 texelFetchOffset(isampler1D sampler, int P, int lod, int offset); +uvec4 texelFetchOffset(usampler1D sampler, int P, int lod, int offset); + + vec4 texelFetchOffset( sampler2D sampler, ivec2 P, int lod, ivec2 offset); +ivec4 texelFetchOffset(isampler2D sampler, ivec2 P, int lod, ivec2 offset); +uvec4 texelFetchOffset(usampler2D sampler, ivec2 P, int lod, ivec2 offset); + + vec4 texelFetchOffset( sampler3D sampler, ivec3 P, int lod, ivec3 offset); +ivec4 texelFetchOffset(isampler3D sampler, ivec3 P, int lod, ivec3 offset); +uvec4 texelFetchOffset(usampler3D sampler, ivec3 P, int lod, ivec3 offset); + + vec4 texelFetchOffset( sampler1DArray sampler, ivec2 P, int lod, int offset); +ivec4 texelFetchOffset(isampler1DArray sampler, ivec2 P, int lod, int offset); +uvec4 texelFetchOffset(usampler1DArray sampler, ivec2 P, int lod, int offset); + + vec4 texelFetchOffset( sampler2DArray sampler, ivec3 P, int lod, ivec2 offset); +ivec4 texelFetchOffset(isampler2DArray sampler, ivec3 P, int lod, ivec2 offset); +uvec4 texelFetchOffset(usampler2DArray sampler, ivec3 P, int lod, ivec2 offset); + +/* textureProjOffset - no bias */ + vec4 textureProj( sampler1D sampler, vec2 P, int offset); +ivec4 textureProj(isampler1D sampler, vec2 P, int offset); +uvec4 textureProj(usampler1D sampler, vec2 P, int offset); + vec4 textureProj( sampler1D sampler, vec4 P, int offset); +ivec4 textureProj(isampler1D sampler, vec4 P, int offset); +uvec4 textureProj(usampler1D sampler, vec4 P, int offset); + + vec4 textureProj( sampler2D sampler, vec3 P, ivec2 offset); +ivec4 textureProj(isampler2D sampler, vec3 P, ivec2 offset); +uvec4 textureProj(usampler2D sampler, vec3 P, ivec2 offset); + vec4 textureProj( sampler2D sampler, vec4 P, ivec2 offset); +ivec4 textureProj(isampler2D sampler, vec4 P, ivec2 offset); +uvec4 textureProj(usampler2D sampler, vec4 P, ivec2 offset); + + vec4 textureProj( sampler3D sampler, vec4 P, ivec3 offset); +ivec4 textureProj(isampler3D sampler, vec4 P, ivec3 offset); +uvec4 textureProj(usampler3D sampler, vec4 P, ivec3 offset); + +float textureProj(sampler1DShadow sampler, vec4 P, int offset); +float textureProj(sampler2DShadow sampler, vec4 P, ivec2 offset); + +/* textureProjOffset - bias variants */ + vec4 textureProj( sampler1D sampler, vec2 P, int offset, float bias); +ivec4 textureProj(isampler1D sampler, vec2 P, int offset, float bias); +uvec4 textureProj(usampler1D sampler, vec2 P, int offset, float bias); + vec4 textureProj( sampler1D sampler, vec4 P, int offset, float bias); +ivec4 textureProj(isampler1D sampler, vec4 P, int offset, float bias); +uvec4 textureProj(usampler1D sampler, vec4 P, int offset, float bias); + + vec4 textureProj( sampler2D sampler, vec3 P, ivec2 offset, float bias); +ivec4 textureProj(isampler2D sampler, vec3 P, ivec2 offset, float bias); +uvec4 textureProj(usampler2D sampler, vec3 P, ivec2 offset, float bias); + vec4 textureProj( sampler2D sampler, vec4 P, ivec2 offset, float bias); +ivec4 textureProj(isampler2D sampler, vec4 P, ivec2 offset, float bias); +uvec4 textureProj(usampler2D sampler, vec4 P, ivec2 offset, float bias); + + vec4 textureProj( sampler3D sampler, vec4 P, ivec3 offset, float bias); +ivec4 textureProj(isampler3D sampler, vec4 P, ivec3 offset, float bias); +uvec4 textureProj(usampler3D sampler, vec4 P, ivec3 offset, float bias); + +float textureProj(sampler1DShadow sampler, vec4 P, int offset, float bias); +float textureProj(sampler2DShadow sampler, vec4 P, ivec2 offset, float bias); + +/* textureLodOffset */ + vec4 textureLodOffset( sampler1D sampler, float P, float lod, int offset); +ivec4 textureLodOffset(isampler1D sampler, float P, float lod, int offset); +uvec4 textureLodOffset(usampler1D sampler, float P, float lod, int offset); + + vec4 textureLodOffset( sampler2D sampler, vec2 P, float lod, ivec2 offset); +ivec4 textureLodOffset(isampler2D sampler, vec2 P, float lod, ivec2 offset); +uvec4 textureLodOffset(usampler2D sampler, vec2 P, float lod, ivec2 offset); + + vec4 textureLodOffset( sampler3D sampler, vec3 P, float lod, ivec3 offset); +ivec4 textureLodOffset(isampler3D sampler, vec3 P, float lod, ivec3 offset); +uvec4 textureLodOffset(usampler3D sampler, vec3 P, float lod, ivec3 offset); + +float textureLodOffset(sampler1DShadow samp, vec3 P, float lod, int offset); +float textureLodOffset(sampler2DShadow samp, vec3 P, float lod, ivec2 offset); + + vec4 textureLodOffset( sampler1DArray sampler, vec2 P, float lod, int offset); +ivec4 textureLodOffset(isampler1DArray sampler, vec2 P, float lod, int offset); +uvec4 textureLodOffset(usampler1DArray sampler, vec2 P, float lod, int offset); + + vec4 textureLodOffset( sampler2DArray samp, vec3 P, float lod, ivec2 offset); +ivec4 textureLodOffset(isampler2DArray samp, vec3 P, float lod, ivec2 offset); +uvec4 textureLodOffset(usampler2DArray samp, vec3 P, float lod, ivec2 offset); + +float textureLodOffset(sampler1DArrayShadow s, vec3 P, float lod, int offset); +#endif + +/* textureProjLod */ + vec4 textureProjLod( sampler1D sampler, vec2 P, float lod); +ivec4 textureProjLod(isampler1D sampler, vec2 P, float lod); +uvec4 textureProjLod(usampler1D sampler, vec2 P, float lod); + vec4 textureProjLod( sampler1D sampler, vec4 P, float lod); +ivec4 textureProjLod(isampler1D sampler, vec4 P, float lod); +uvec4 textureProjLod(usampler1D sampler, vec4 P, float lod); + + vec4 textureProjLod( sampler2D sampler, vec3 P, float lod); +ivec4 textureProjLod(isampler2D sampler, vec3 P, float lod); +uvec4 textureProjLod(usampler2D sampler, vec3 P, float lod); + vec4 textureProjLod( sampler2D sampler, vec4 P, float lod); +ivec4 textureProjLod(isampler2D sampler, vec4 P, float lod); +uvec4 textureProjLod(usampler2D sampler, vec4 P, float lod); + + vec4 textureProjLod( sampler3D sampler, vec4 P, float lod); +ivec4 textureProjLod(isampler3D sampler, vec4 P, float lod); +uvec4 textureProjLod(usampler3D sampler, vec4 P, float lod); + +float textureProjLod(sampler1DShadow sampler, vec4 P, float lod); +float textureProjLod(sampler2DShadow sampler, vec4 P, float lod); + +#if 0 +/* textureProjLodOffset */ + vec4 textureProjLodOffset( sampler1D sampler, vec2 P, float lod, int offset); +ivec4 textureProjLodOffset(isampler1D sampler, vec2 P, float lod, int offset); +uvec4 textureProjLodOffset(usampler1D sampler, vec2 P, float lod, int offset); + vec4 textureProjLodOffset( sampler1D sampler, vec4 P, float lod, int offset); +ivec4 textureProjLodOffset(isampler1D sampler, vec4 P, float lod, int offset); +uvec4 textureProjLodOffset(usampler1D sampler, vec4 P, float lod, int offset); + + vec4 textureProjLodOffset( sampler2D sampler, vec3 P, float lod, ivec2 offset); +ivec4 textureProjLodOffset(isampler2D sampler, vec3 P, float lod, ivec2 offset); +uvec4 textureProjLodOffset(usampler2D sampler, vec3 P, float lod, ivec2 offset); + vec4 textureProjLodOffset( sampler2D sampler, vec4 P, float lod, ivec2 offset); +ivec4 textureProjLodOffset(isampler2D sampler, vec4 P, float lod, ivec2 offset); +uvec4 textureProjLodOffset(usampler2D sampler, vec4 P, float lod, ivec2 offset); + + vec4 textureProjLodOffset( sampler3D sampler, vec4 P, float lod, ivec3 offset); +ivec4 textureProjLodOffset(isampler3D sampler, vec4 P, float lod, ivec3 offset); +uvec4 textureProjLodOffset(usampler3D sampler, vec4 P, float lod, ivec3 offset); + +float textureProjLodOffset(sampler1DShadow s, vec4 P, float lod, int offset); +float textureProjLodOffset(sampler2DShadow s, vec4 P, float lod, ivec2 offset); +#endif + +/* textureGrad */ + vec4 textureGrad( sampler1D sampler, float P, float dPdx, float dPdy); +ivec4 textureGrad(isampler1D sampler, float P, float dPdx, float dPdy); +uvec4 textureGrad(usampler1D sampler, float P, float dPdx, float dPdy); + + vec4 textureGrad( sampler2D sampler, vec2 P, vec2 dPdx, vec2 dPdy); +ivec4 textureGrad(isampler2D sampler, vec2 P, vec2 dPdx, vec2 dPdy); +uvec4 textureGrad(usampler2D sampler, vec2 P, vec2 dPdx, vec2 dPdy); + + vec4 textureGrad( sampler3D sampler, vec3 P, vec3 dPdx, vec3 dPdy); +ivec4 textureGrad(isampler3D sampler, vec3 P, vec3 dPdx, vec3 dPdy); +uvec4 textureGrad(usampler3D sampler, vec3 P, vec3 dPdx, vec3 dPdy); + + vec4 textureGrad( samplerCube sampler, vec3 P, vec3 dPdx, vec3 dPdy); +ivec4 textureGrad(isamplerCube sampler, vec3 P, vec3 dPdx, vec3 dPdy); +uvec4 textureGrad(usamplerCube sampler, vec3 P, vec3 dPdx, vec3 dPdy); + +float textureGrad(sampler1DShadow sampler, vec3 P, float dPdx, float dPdy); +float textureGrad(sampler2DShadow sampler, vec3 P, vec2 dPdx, vec2 dPdy); +float textureGrad(samplerCubeShadow sampler, vec4 P, vec3 dPdx, vec3 dPdy); + + vec4 textureGrad( sampler1DArray sampler, vec2 P, float dPdx, float dPdy); +ivec4 textureGrad(isampler1DArray sampler, vec2 P, float dPdx, float dPdy); +uvec4 textureGrad(usampler1DArray sampler, vec2 P, float dPdx, float dPdy); + + vec4 textureGrad( sampler2DArray sampler, vec3 P, vec2 dPdx, vec2 dPdy); +ivec4 textureGrad(isampler2DArray sampler, vec3 P, vec2 dPdx, vec2 dPdy); +uvec4 textureGrad(usampler2DArray sampler, vec3 P, vec2 dPdx, vec2 dPdy); + +float textureGrad(sampler1DArrayShadow sampler, vec3 P, float dPdx, float dPdy); +float textureGrad(sampler2DArrayShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy); + +#if 0 +/* textureGradOffset */ + vec4 textureGradOffset( sampler1D s, float P, float dx, float dy, int off); +ivec4 textureGradOffset(isampler1D s, float P, float dx, float dy, int offset); +uvec4 textureGradOffset(usampler1D s, float P, float dx, float dy, int offset); + + vec4 textureGradOffset( sampler2D s, vec2 P, vec2 dx, vec2 dy, ivec2 offset); +ivec4 textureGradOffset(isampler2D s, vec2 P, vec2 dx, vec2 dy, ivec2 offset); +uvec4 textureGradOffset(usampler2D s, vec2 P, vec2 dx, vec2 dy, ivec2 offset); + + vec4 textureGradOffset( sampler3D s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); +ivec4 textureGradOffset(isampler3D s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); +uvec4 textureGradOffset(usampler3D s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); + + vec4 textureGradOffset( samplerCube s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); +ivec4 textureGradOffset(isamplerCube s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); +uvec4 textureGradOffset(usamplerCube s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); + +float textureGradOffset(sampler1DShadow s, vec3 P, float dx, float dy, int off); +float textureGradOffset(sampler2DShadow s, vec3 P, vec2 dx, vec2 dy, ivec2 off); + + vec4 textureGradOffset( sampler1DArray s, vec2 P, float dx, float dy, int off); +ivec4 textureGradOffset(isampler1DArray s, vec2 P, float dx, float dy, int off); +uvec4 textureGradOffset(usampler1DArray s, vec2 P, float dx, float dy, int off); + + vec4 textureGradOffset( sampler2DArray s, vec3 P, vec2 dx, vec2 dy, ivec2 off); +ivec4 textureGradOffset(isampler2DArray s, vec3 P, vec2 dx, vec2 dy, ivec2 off); +uvec4 textureGradOffset(usampler2DArray s, vec3 P, vec2 dx, vec2 dy, ivec2 off); + +float textureGradOffset(sampler1DArrayShadow s, vec3 P, float dx, float dy, int o); +float textureGradOffset(sampler2DArrayShadow s, vec4 P, vec2 dx, vec2 dy, ivec2 o); +#endif + +/* textureProjGrad */ + vec4 textureProjGrad( sampler1D sampler, vec2 P, float dPdx, float dPdy); +ivec4 textureProjGrad(isampler1D sampler, vec2 P, float dPdx, float dPdy); +uvec4 textureProjGrad(usampler1D sampler, vec2 P, float dPdx, float dPdy); + vec4 textureProjGrad( sampler1D sampler, vec4 P, float dPdx, float dPdy); +ivec4 textureProjGrad(isampler1D sampler, vec4 P, float dPdx, float dPdy); +uvec4 textureProjGrad(usampler1D sampler, vec4 P, float dPdx, float dPdy); + + vec4 textureProjGrad( sampler2D sampler, vec3 P, vec2 dPdx, vec2 dPdy); +ivec4 textureProjGrad(isampler2D sampler, vec3 P, vec2 dPdx, vec2 dPdy); +uvec4 textureProjGrad(usampler2D sampler, vec3 P, vec2 dPdx, vec2 dPdy); + vec4 textureProjGrad( sampler2D sampler, vec4 P, vec2 dPdx, vec2 dPdy); +ivec4 textureProjGrad(isampler2D sampler, vec4 P, vec2 dPdx, vec2 dPdy); +uvec4 textureProjGrad(usampler2D sampler, vec4 P, vec2 dPdx, vec2 dPdy); + + vec4 textureProjGrad( sampler3D sampler, vec4 P, vec3 dPdx, vec3 dPdy); +ivec4 textureProjGrad(isampler3D sampler, vec4 P, vec3 dPdx, vec3 dPdy); +uvec4 textureProjGrad(usampler3D sampler, vec4 P, vec3 dPdx, vec3 dPdy); + +float textureProjGrad(sampler1DShadow sampler, vec4 P, float dPdx, float dPdy); +float textureProjGrad(sampler2DShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy); + +#if 0 +/* textureProjGradOffset */ + vec4 textureProjGradOffset( sampler1D s, vec2 P, float dx, float dy, int off); +ivec4 textureProjGradOffset(isampler1D s, vec2 P, float dx, float dy, int off); +uvec4 textureProjGradOffset(usampler1D s, vec2 P, float dx, float dy, int off); + vec4 textureProjGradOffset( sampler1D s, vec4 P, float dx, float dy, int off); +ivec4 textureProjGradOffset(isampler1D s, vec4 P, float dx, float dy, int off); +uvec4 textureProjGradOffset(usampler1D s, vec4 P, float dx, float dy, int off); + + vec4 textureProjGradOffset( sampler2D s, vec3 P, vec2 dx, vec2 dy, ivec2 off); +ivec4 textureProjGradOffset(isampler2D s, vec3 P, vec2 dx, vec2 dy, ivec2 off); +uvec4 textureProjGradOffset(usampler2D s, vec3 P, vec2 dx, vec2 dy, ivec2 off); + vec4 textureProjGradOffset( sampler2D s, vec4 P, vec2 dx, vec2 dy, ivec2 off); +ivec4 textureProjGradOffset(isampler2D s, vec4 P, vec2 dx, vec2 dy, ivec2 off); +uvec4 textureProjGradOffset(usampler2D s, vec4 P, vec2 dx, vec2 dy, ivec2 off); + + vec4 textureProjGradOffset( sampler3D s, vec4 P, vec3 dx, vec3 dy, ivec3 off); +ivec4 textureProjGradOffset(isampler3D s, vec4 P, vec3 dx, vec3 dy, ivec3 off); +uvec4 textureProjGradOffset(usampler3D s, vec4 P, vec3 dx, vec3 dy, ivec3 off); + +float textureProjGradOffset(sampler1DShadow s, vec4 P, float dx, float dy, int o); +float textureProjGradOffset(sampler2DShadow s, vec4 P, vec2 dx, vec2 dy, vec2 o); +#endif + +/* + * The following texture functions are deprecated: + */ +vec4 texture1D (sampler1D sampler, float coord); +vec4 texture1DProj (sampler1D sampler, vec2 coord); +vec4 texture1DProj (sampler1D sampler, vec4 coord); +vec4 texture1D (sampler1D sampler, float coord, float bias); +vec4 texture1DProj (sampler1D sampler, vec2 coord, float bias); +vec4 texture1DProj (sampler1D sampler, vec4 coord, float bias); +vec4 texture1DLod (sampler1D sampler, float coord, float lod); +vec4 texture1DProjLod(sampler1D sampler, vec2 coord, float lod); +vec4 texture1DProjLod(sampler1D sampler, vec4 coord, float lod); + +vec4 texture2D (sampler2D sampler, vec2 coord); +vec4 texture2DProj (sampler2D sampler, vec3 coord); +vec4 texture2DProj (sampler2D sampler, vec4 coord); +vec4 texture2D (sampler2D sampler, vec2 coord, float bias); +vec4 texture2DProj (sampler2D sampler, vec3 coord, float bias); +vec4 texture2DProj (sampler2D sampler, vec4 coord, float bias); +vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod); +vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod); +vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod); + +vec4 texture3D (sampler3D sampler, vec3 coord); +vec4 texture3DProj (sampler3D sampler, vec4 coord); +vec4 texture3D (sampler3D sampler, vec3 coord, float bias); +vec4 texture3DProj (sampler3D sampler, vec4 coord, float bias); +vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod); +vec4 texture3DProjLod(sampler3D sampler, vec4 coord, float lod); + +vec4 textureCube (samplerCube sampler, vec3 coord); +vec4 textureCube (samplerCube sampler, vec3 coord, float bias); +vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod); + +vec4 shadow1D (sampler1DShadow sampler, vec3 coord); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord); +vec4 shadow1D (sampler1DShadow sampler, vec3 coord, float bias); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord, float bias); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord, float bias); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord, float bias); +vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod); +vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod); +vec4 shadow1DProjLod(sampler1DShadow sampler, vec4 coord, float lod); +vec4 shadow2DProjLod(sampler2DShadow sampler, vec4 coord, float lod); + +/* + * 8.8 - Fragment Processing Functions + */ +float dFdx(float p); +vec2 dFdx(vec2 p); +vec3 dFdx(vec3 p); +vec4 dFdx(vec4 p); + +float dFdy(float p); +vec2 dFdy(vec2 p); +vec3 dFdy(vec3 p); +vec4 dFdy(vec4 p); + +float fwidth(float p); +vec2 fwidth(vec2 p); +vec3 fwidth(vec3 p); +vec4 fwidth(vec4 p); + +/* + * 8.9 - Noise Functions + */ +float noise1(float x); +float noise1(vec2 x); +float noise1(vec3 x); +float noise1(vec4 x); + +vec2 noise2(float x); +vec2 noise2(vec2 x); +vec2 noise2(vec3 x); +vec2 noise2(vec4 x); + +vec3 noise3(float x); +vec3 noise3(vec2 x); +vec3 noise3(vec3 x); +vec3 noise3(vec4 x); + +vec4 noise4(float x); +vec4 noise4(vec2 x); +vec4 noise4(vec3 x); +vec4 noise4(vec4 x); diff --git a/src/glsl/builtins/profiles/130.vert b/src/glsl/builtins/profiles/130.vert new file mode 100644 index 0000000000..d0152b0374 --- /dev/null +++ b/src/glsl/builtins/profiles/130.vert @@ -0,0 +1,1019 @@ +#version 130 +/* + * 8.1 - Angle and Trigonometry Functions + */ +float radians(float degrees); +vec2 radians(vec2 degrees); +vec3 radians(vec3 degrees); +vec4 radians(vec4 degrees); + +float degrees(float radians); +vec2 degrees(vec2 radians); +vec3 degrees(vec3 radians); +vec4 degrees(vec4 radians); + +float sin(float angle); +vec2 sin(vec2 angle); +vec3 sin(vec3 angle); +vec4 sin(vec4 angle); + +float cos(float angle); +vec2 cos(vec2 angle); +vec3 cos(vec3 angle); +vec4 cos(vec4 angle); + +float tan(float angle); +vec2 tan(vec2 angle); +vec3 tan(vec3 angle); +vec4 tan(vec4 angle); + +float asin(float angle); +vec2 asin(vec2 angle); +vec3 asin(vec3 angle); +vec4 asin(vec4 angle); + +float acos(float angle); +vec2 acos(vec2 angle); +vec3 acos(vec3 angle); +vec4 acos(vec4 angle); + +float atan(float y, float x); +vec2 atan(vec2 y, vec2 x); +vec3 atan(vec3 y, vec3 x); +vec4 atan(vec4 y, vec4 x); + +float atan(float y_over_x); +vec2 atan(vec2 y_over_x); +vec3 atan(vec3 y_over_x); +vec4 atan(vec4 y_over_x); + +float sinh(float x); +vec2 sinh(vec2 x); +vec3 sinh(vec3 x); +vec4 sinh(vec4 x); + +float cosh(float x); +vec2 cosh(vec2 x); +vec3 cosh(vec3 x); +vec4 cosh(vec4 x); + +float tanh(float x); +vec2 tanh(vec2 x); +vec3 tanh(vec3 x); +vec4 tanh(vec4 x); + +#if 0 +float asinh(float x); +vec2 asinh(vec2 x); +vec3 asinh(vec3 x); +vec4 asinh(vec4 x); + +float acosh(float x); +vec2 acosh(vec2 x); +vec3 acosh(vec3 x); +vec4 acosh(vec4 x); + +float atanh(float x); +vec2 atanh(vec2 x); +vec3 atanh(vec3 x); +vec4 atanh(vec4 x); +#endif + +/* + * 8.2 - Exponential Functions + */ +float pow(float x, float y); +vec2 pow(vec2 x, vec2 y); +vec3 pow(vec3 x, vec3 y); +vec4 pow(vec4 x, vec4 y); + +float exp(float x); +vec2 exp(vec2 x); +vec3 exp(vec3 x); +vec4 exp(vec4 x); + +float log(float x); +vec2 log(vec2 x); +vec3 log(vec3 x); +vec4 log(vec4 x); + +float exp2(float x); +vec2 exp2(vec2 x); +vec3 exp2(vec3 x); +vec4 exp2(vec4 x); + +float log2(float x); +vec2 log2(vec2 x); +vec3 log2(vec3 x); +vec4 log2(vec4 x); + +float sqrt(float x); +vec2 sqrt(vec2 x); +vec3 sqrt(vec3 x); +vec4 sqrt(vec4 x); + +float inversesqrt(float x); +vec2 inversesqrt(vec2 x); +vec3 inversesqrt(vec3 x); +vec4 inversesqrt(vec4 x); + +/* + * 8.3 - Common Functions + */ +float abs(float x); +vec2 abs(vec2 x); +vec3 abs(vec3 x); +vec4 abs(vec4 x); +int abs(int x); +ivec2 abs(ivec2 x); +ivec3 abs(ivec3 x); +ivec4 abs(ivec4 x); + +float sign(float x); +vec2 sign(vec2 x); +vec3 sign(vec3 x); +vec4 sign(vec4 x); +int sign(int x); +ivec2 sign(ivec2 x); +ivec3 sign(ivec3 x); +ivec4 sign(ivec4 x); + +float floor(float x); +vec2 floor(vec2 x); +vec3 floor(vec3 x); +vec4 floor(vec4 x); + +float ceil(float x); +vec2 ceil(vec2 x); +vec3 ceil(vec3 x); +vec4 ceil(vec4 x); + +float fract(float x); +vec2 fract(vec2 x); +vec3 fract(vec3 x); +vec4 fract(vec4 x); + +float mod(float x, float y); +vec2 mod(vec2 x, float y); +vec3 mod(vec3 x, float y); +vec4 mod(vec4 x, float y); + +vec2 mod(vec2 x, vec2 y); +vec3 mod(vec3 x, vec3 y); +vec4 mod(vec4 x, vec4 y); + +float min(float x, float y); +vec2 min(vec2 x, vec2 y); +vec3 min(vec3 x, vec3 y); +vec4 min(vec4 x, vec4 y); + +vec2 min(vec2 x, float y); +vec3 min(vec3 x, float y); +vec4 min(vec4 x, float y); + +int min(int x, int y); +ivec2 min(ivec2 x, ivec2 y); +ivec3 min(ivec3 x, ivec3 y); +ivec4 min(ivec4 x, ivec4 y); + +ivec2 min(ivec2 x, int y); +ivec3 min(ivec3 x, int y); +ivec4 min(ivec4 x, int y); + +uint min(uint x, uint y); +uvec2 min(uvec2 x, uvec2 y); +uvec3 min(uvec3 x, uvec3 y); +uvec4 min(uvec4 x, uvec4 y); + +uvec2 min(uvec2 x, uint y); +uvec3 min(uvec3 x, uint y); +uvec4 min(uvec4 x, uint y); + +float max(float x, float y); +vec2 max(vec2 x, vec2 y); +vec3 max(vec3 x, vec3 y); +vec4 max(vec4 x, vec4 y); + +vec2 max(vec2 x, float y); +vec3 max(vec3 x, float y); +vec4 max(vec4 x, float y); + +int max(int x, int y); +ivec2 max(ivec2 x, ivec2 y); +ivec3 max(ivec3 x, ivec3 y); +ivec4 max(ivec4 x, ivec4 y); + +ivec2 max(ivec2 x, int y); +ivec3 max(ivec3 x, int y); +ivec4 max(ivec4 x, int y); + +uint max(uint x, uint y); +uvec2 max(uvec2 x, uvec2 y); +uvec3 max(uvec3 x, uvec3 y); +uvec4 max(uvec4 x, uvec4 y); + +uvec2 max(uvec2 x, uint y); +uvec3 max(uvec3 x, uint y); +uvec4 max(uvec4 x, uint y); + +float clamp(float x, float minVal, float maxVal); +vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal); +vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal); +vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal); + +vec2 clamp(vec2 x, float minVal, float maxVal); +vec3 clamp(vec3 x, float minVal, float maxVal); +vec4 clamp(vec4 x, float minVal, float maxVal); + +int clamp(int x, int minVal, int maxVal); +ivec2 clamp(ivec2 x, ivec2 minVal, ivec2 maxVal); +ivec3 clamp(ivec3 x, ivec3 minVal, ivec3 maxVal); +ivec4 clamp(ivec4 x, ivec4 minVal, ivec4 maxVal); + +ivec2 clamp(ivec2 x, int minVal, int maxVal); +ivec3 clamp(ivec3 x, int minVal, int maxVal); +ivec4 clamp(ivec4 x, int minVal, int maxVal); + +uint clamp(uint x, uint minVal, uint maxVal); +uvec2 clamp(uvec2 x, uvec2 minVal, uvec2 maxVal); +uvec3 clamp(uvec3 x, uvec3 minVal, uvec3 maxVal); +uvec4 clamp(uvec4 x, uvec4 minVal, uvec4 maxVal); + +uvec2 clamp(uvec2 x, uint minVal, uint maxVal); +uvec3 clamp(uvec3 x, uint minVal, uint maxVal); +uvec4 clamp(uvec4 x, uint minVal, uint maxVal); + +float mix(float x, float y, float a); +vec2 mix(vec2 x, vec2 y, vec2 a); +vec3 mix(vec3 x, vec3 y, vec3 a); +vec4 mix(vec4 x, vec4 y, vec4 a); + +vec2 mix(vec2 x, vec2 y, float a); +vec3 mix(vec3 x, vec3 y, float a); +vec4 mix(vec4 x, vec4 y, float a); + +float step(float edge, float x); +vec2 step(vec2 edge, vec2 x); +vec3 step(vec3 edge, vec3 x); +vec4 step(vec4 edge, vec4 x); + +vec2 step(float edge, vec2 x); +vec3 step(float edge, vec3 x); +vec4 step(float edge, vec4 x); + +float smoothstep(float edge0, float edge1, float x); +vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x); +vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x); +vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x); + +vec2 smoothstep(float edge0, float edge1, vec2 x); +vec3 smoothstep(float edge0, float edge1, vec3 x); +vec4 smoothstep(float edge0, float edge1, vec4 x); + +#if 0 +bool isnan(float x); +bvec2 isnan(vec2 x); +bvec3 isnan(vec3 x); +bvec4 isnan(vec4 x); + +bool isinf(float x); +bvec2 isinf(vec2 x); +bvec3 isinf(vec3 x); +bvec4 isinf(vec4 x); +#endif + +/* + * 8.4 - Geometric Functions + */ +float length(float x); +float length(vec2 x); +float length(vec3 x); +float length(vec4 x); + +float distance(float p0, float p1); +float distance(vec2 p0, vec2 p1); +float distance(vec3 p0, vec3 p1); +float distance(vec4 p0, vec4 p1); + +float dot(float x, float y); +float dot(vec2 x, vec2 y); +float dot(vec3 x, vec3 y); +float dot(vec4 x, vec4 y); + +vec3 cross(vec3 x, vec3 y); + +float normalize(float x); +vec2 normalize(vec2 x); +vec3 normalize(vec3 x); +vec4 normalize(vec4 x); + +vec4 ftransform(); + +float faceforward(float N, float I, float Nref); +vec2 faceforward(vec2 N, vec2 I, vec2 Nref); +vec3 faceforward(vec3 N, vec3 I, vec3 Nref); +vec4 faceforward(vec4 N, vec4 I, vec4 Nref); + +float reflect(float I, float N); +vec2 reflect(vec2 I, vec2 N); +vec3 reflect(vec3 I, vec3 N); +vec4 reflect(vec4 I, vec4 N); + +float refract(float I, float N, float eta); +vec2 refract(vec2 I, vec2 N, float eta); +vec3 refract(vec3 I, vec3 N, float eta); +vec4 refract(vec4 I, vec4 N, float eta); + + +/* + * 8.5 - Matrix Functions + */ +mat2 matrixCompMult(mat2 x, mat2 y); +mat3 matrixCompMult(mat3 x, mat3 y); +mat4 matrixCompMult(mat4 x, mat4 y); +mat2x3 matrixCompMult(mat2x3 x, mat2x3 y); +mat2x4 matrixCompMult(mat2x4 x, mat2x4 y); +mat3x2 matrixCompMult(mat3x2 x, mat3x2 y); +mat3x4 matrixCompMult(mat3x4 x, mat3x4 y); +mat4x2 matrixCompMult(mat4x2 x, mat4x2 y); +mat4x3 matrixCompMult(mat4x3 x, mat4x3 y); + +mat2 outerProduct(vec2 c, vec2 r); +mat3 outerProduct(vec3 c, vec3 r); +mat4 outerProduct(vec4 c, vec4 r); + +mat2x3 outerProduct(vec3 c, vec2 r); +mat3x2 outerProduct(vec2 c, vec3 r); + +mat2x4 outerProduct(vec4 c, vec2 r); +mat4x2 outerProduct(vec2 c, vec4 r); + +mat3x4 outerProduct(vec4 c, vec3 r); +mat4x3 outerProduct(vec3 c, vec4 r); + +mat2 transpose(mat2 m); +mat3 transpose(mat3 m); +mat4 transpose(mat4 m); + +mat2x3 transpose(mat3x2 m); +mat3x2 transpose(mat2x3 m); + +mat2x4 transpose(mat4x2 m); +mat4x2 transpose(mat2x4 m); + +mat3x4 transpose(mat4x3 m); +mat4x3 transpose(mat3x4 m); + +/* + * 8.6 - Vector Relational Functions + */ +bvec2 lessThan( vec2 x, vec2 y); +bvec3 lessThan( vec3 x, vec3 y); +bvec4 lessThan( vec4 x, vec4 y); +bvec2 lessThan(ivec2 x, ivec2 y); +bvec3 lessThan(ivec3 x, ivec3 y); +bvec4 lessThan(ivec4 x, ivec4 y); +bvec2 lessThan(uvec2 x, uvec2 y); +bvec3 lessThan(uvec3 x, uvec3 y); +bvec4 lessThan(uvec4 x, uvec4 y); + +bvec2 lessThanEqual( vec2 x, vec2 y); +bvec3 lessThanEqual( vec3 x, vec3 y); +bvec4 lessThanEqual( vec4 x, vec4 y); +bvec2 lessThanEqual(ivec2 x, ivec2 y); +bvec3 lessThanEqual(ivec3 x, ivec3 y); +bvec4 lessThanEqual(ivec4 x, ivec4 y); +bvec2 lessThanEqual(uvec2 x, uvec2 y); +bvec3 lessThanEqual(uvec3 x, uvec3 y); +bvec4 lessThanEqual(uvec4 x, uvec4 y); + +bvec2 greaterThan( vec2 x, vec2 y); +bvec3 greaterThan( vec3 x, vec3 y); +bvec4 greaterThan( vec4 x, vec4 y); +bvec2 greaterThan(ivec2 x, ivec2 y); +bvec3 greaterThan(ivec3 x, ivec3 y); +bvec4 greaterThan(ivec4 x, ivec4 y); +bvec2 greaterThan(uvec2 x, uvec2 y); +bvec3 greaterThan(uvec3 x, uvec3 y); +bvec4 greaterThan(uvec4 x, uvec4 y); + +bvec2 greaterThanEqual( vec2 x, vec2 y); +bvec3 greaterThanEqual( vec3 x, vec3 y); +bvec4 greaterThanEqual( vec4 x, vec4 y); +bvec2 greaterThanEqual(ivec2 x, ivec2 y); +bvec3 greaterThanEqual(ivec3 x, ivec3 y); +bvec4 greaterThanEqual(ivec4 x, ivec4 y); +bvec2 greaterThanEqual(uvec2 x, uvec2 y); +bvec3 greaterThanEqual(uvec3 x, uvec3 y); +bvec4 greaterThanEqual(uvec4 x, uvec4 y); + +bvec2 equal( vec2 x, vec2 y); +bvec3 equal( vec3 x, vec3 y); +bvec4 equal( vec4 x, vec4 y); +bvec2 equal(ivec2 x, ivec2 y); +bvec3 equal(ivec3 x, ivec3 y); +bvec4 equal(ivec4 x, ivec4 y); +bvec2 equal(uvec2 x, uvec2 y); +bvec3 equal(uvec3 x, uvec3 y); +bvec4 equal(uvec4 x, uvec4 y); +bvec2 equal(bvec2 x, bvec2 y); +bvec3 equal(bvec3 x, bvec3 y); +bvec4 equal(bvec4 x, bvec4 y); + +bvec2 notEqual( vec2 x, vec2 y); +bvec3 notEqual( vec3 x, vec3 y); +bvec4 notEqual( vec4 x, vec4 y); +bvec2 notEqual(ivec2 x, ivec2 y); +bvec3 notEqual(ivec3 x, ivec3 y); +bvec4 notEqual(ivec4 x, ivec4 y); +bvec2 notEqual(uvec2 x, uvec2 y); +bvec3 notEqual(uvec3 x, uvec3 y); +bvec4 notEqual(uvec4 x, uvec4 y); +bvec2 notEqual(bvec2 x, bvec2 y); +bvec3 notEqual(bvec3 x, bvec3 y); +bvec4 notEqual(bvec4 x, bvec4 y); + +bool any(bvec2 x); +bool any(bvec3 x); +bool any(bvec4 x); + +bool all(bvec2 x); +bool all(bvec3 x); +bool all(bvec4 x); + +bvec2 not(bvec2 x); +bvec3 not(bvec3 x); +bvec4 not(bvec4 x); + +/* + * 8.7 - Texture Lookup Functions + */ + +#if 0 +/* textureSize */ +int textureSize( sampler1D sampler, int lod); +int textureSize(isampler1D sampler, int lod); +int textureSize(usampler1D sampler, int lod); + +ivec2 textureSize( sampler2D sampler, int lod); +ivec2 textureSize(isampler2D sampler, int lod); +ivec2 textureSize(usampler2D sampler, int lod); + +ivec3 textureSize( sampler3D sampler, int lod); +ivec3 textureSize(isampler3D sampler, int lod); +ivec3 textureSize(usampler3D sampler, int lod); + +ivec2 textureSize( samplerCube sampler, int lod); +ivec2 textureSize(isamplerCube sampler, int lod); +ivec2 textureSize(usamplerCube sampler, int lod); + +int textureSize(sampler1DShadow sampler, int lod); +ivec2 textureSize(sampler2DShadow sampler, int lod); +ivec2 textureSize(samplerCubeShadow sampler, int lod); + +ivec2 textureSize( sampler1DArray sampler, int lod); +ivec2 textureSize(isampler1DArray sampler, int lod); +ivec2 textureSize(usampler1DArray sampler, int lod); +ivec3 textureSize( sampler2DArray sampler, int lod); +ivec2 textureSize(isampler2DArray sampler, int lod); +ivec2 textureSize(usampler2DArray sampler, int lod); + +ivec2 textureSize(sampler1DArrayShadow sampler, int lod); +ivec3 textureSize(sampler2DArrayShadow sampler, int lod); +#endif + +/* texture - no bias */ + vec4 texture( sampler1D sampler, float P); +ivec4 texture(isampler1D sampler, float P); +uvec4 texture(usampler1D sampler, float P); + + vec4 texture( sampler2D sampler, vec2 P); +ivec4 texture(isampler2D sampler, vec2 P); +uvec4 texture(usampler2D sampler, vec2 P); + + vec4 texture( sampler3D sampler, vec3 P); +ivec4 texture(isampler3D sampler, vec3 P); +uvec4 texture(usampler3D sampler, vec3 P); + + vec4 texture( samplerCube sampler, vec3 P); +ivec4 texture(isamplerCube sampler, vec3 P); +uvec4 texture(usamplerCube sampler, vec3 P); + +float texture(sampler1DShadow sampler, vec3 P); +float texture(sampler2DShadow sampler, vec3 P); +float texture(samplerCubeShadow sampler, vec4 P); + + vec4 texture( sampler1DArray sampler, vec2 P); +ivec4 texture(isampler1DArray sampler, vec2 P); +uvec4 texture(usampler1DArray sampler, vec2 P); + + vec4 texture( sampler2DArray sampler, vec3 P); +ivec4 texture(isampler2DArray sampler, vec3 P); +uvec4 texture(usampler2DArray sampler, vec3 P); + +float texture(sampler1DArrayShadow sampler, vec3 P); +float texture(sampler2DArrayShadow sampler, vec4 P); + +/* texture - bias variants */ + vec4 texture( sampler1D sampler, float P, float bias); +ivec4 texture(isampler1D sampler, float P, float bias); +uvec4 texture(usampler1D sampler, float P, float bias); + + vec4 texture( sampler2D sampler, vec2 P, float bias); +ivec4 texture(isampler2D sampler, vec2 P, float bias); +uvec4 texture(usampler2D sampler, vec2 P, float bias); + + vec4 texture( sampler3D sampler, vec3 P, float bias); +ivec4 texture(isampler3D sampler, vec3 P, float bias); +uvec4 texture(usampler3D sampler, vec3 P, float bias); + + vec4 texture( samplerCube sampler, vec3 P, float bias); +ivec4 texture(isamplerCube sampler, vec3 P, float bias); +uvec4 texture(usamplerCube sampler, vec3 P, float bias); + +float texture(sampler1DShadow sampler, vec3 P, float bias); +float texture(sampler2DShadow sampler, vec3 P, float bias); +float texture(samplerCubeShadow sampler, vec4 P, float bias); + + vec4 texture( sampler1DArray sampler, vec2 P, float bias); +ivec4 texture(isampler1DArray sampler, vec2 P, float bias); +uvec4 texture(usampler1DArray sampler, vec2 P, float bias); + + vec4 texture( sampler2DArray sampler, vec3 P, float bias); +ivec4 texture(isampler2DArray sampler, vec3 P, float bias); +uvec4 texture(usampler2DArray sampler, vec3 P, float bias); + +float texture(sampler1DArrayShadow sampler, vec3 P, float bias); + +/* textureProj - no bias */ + vec4 textureProj( sampler1D sampler, vec2 P); +ivec4 textureProj(isampler1D sampler, vec2 P); +uvec4 textureProj(usampler1D sampler, vec2 P); + vec4 textureProj( sampler1D sampler, vec4 P); +ivec4 textureProj(isampler1D sampler, vec4 P); +uvec4 textureProj(usampler1D sampler, vec4 P); + + vec4 textureProj( sampler2D sampler, vec3 P); +ivec4 textureProj(isampler2D sampler, vec3 P); +uvec4 textureProj(usampler2D sampler, vec3 P); + vec4 textureProj( sampler2D sampler, vec4 P); +ivec4 textureProj(isampler2D sampler, vec4 P); +uvec4 textureProj(usampler2D sampler, vec4 P); + + vec4 textureProj( sampler3D sampler, vec4 P); +ivec4 textureProj(isampler3D sampler, vec4 P); +uvec4 textureProj(usampler3D sampler, vec4 P); + +float textureProj(sampler1DShadow sampler, vec4 P); +float textureProj(sampler2DShadow sampler, vec4 P); + +/* textureProj - bias variants */ + vec4 textureProj( sampler1D sampler, vec2 P, float bias); +ivec4 textureProj(isampler1D sampler, vec2 P, float bias); +uvec4 textureProj(usampler1D sampler, vec2 P, float bias); + vec4 textureProj( sampler1D sampler, vec4 P, float bias); +ivec4 textureProj(isampler1D sampler, vec4 P, float bias); +uvec4 textureProj(usampler1D sampler, vec4 P, float bias); + + vec4 textureProj( sampler2D sampler, vec3 P, float bias); +ivec4 textureProj(isampler2D sampler, vec3 P, float bias); +uvec4 textureProj(usampler2D sampler, vec3 P, float bias); + vec4 textureProj( sampler2D sampler, vec4 P, float bias); +ivec4 textureProj(isampler2D sampler, vec4 P, float bias); +uvec4 textureProj(usampler2D sampler, vec4 P, float bias); + + vec4 textureProj( sampler3D sampler, vec4 P, float bias); +ivec4 textureProj(isampler3D sampler, vec4 P, float bias); +uvec4 textureProj(usampler3D sampler, vec4 P, float bias); + +float textureProj(sampler1DShadow sampler, vec4 P, float bias); +float textureProj(sampler2DShadow sampler, vec4 P, float bias); + +/* textureLod */ + vec4 textureLod( sampler1D sampler, float P, float lod); +ivec4 textureLod(isampler1D sampler, float P, float lod); +uvec4 textureLod(usampler1D sampler, float P, float lod); + + vec4 textureLod( sampler2D sampler, vec2 P, float lod); +ivec4 textureLod(isampler2D sampler, vec2 P, float lod); +uvec4 textureLod(usampler2D sampler, vec2 P, float lod); + + vec4 textureLod( sampler3D sampler, vec3 P, float lod); +ivec4 textureLod(isampler3D sampler, vec3 P, float lod); +uvec4 textureLod(usampler3D sampler, vec3 P, float lod); + + vec4 textureLod( samplerCube sampler, vec3 P, float lod); +ivec4 textureLod(isamplerCube sampler, vec3 P, float lod); +uvec4 textureLod(usamplerCube sampler, vec3 P, float lod); + +float textureLod(sampler1DShadow sampler, vec3 P, float lod); +float textureLod(sampler2DShadow sampler, vec3 P, float lod); + + vec4 textureLod( sampler1DArray sampler, vec2 P, float lod); +ivec4 textureLod(isampler1DArray sampler, vec2 P, float lod); +uvec4 textureLod(usampler1DArray sampler, vec2 P, float lod); + + vec4 textureLod( sampler2DArray sampler, vec3 P, float lod); +ivec4 textureLod(isampler2DArray sampler, vec3 P, float lod); +uvec4 textureLod(usampler2DArray sampler, vec3 P, float lod); + +float textureLod(sampler1DArrayShadow sampler, vec3 P, float lod); + +#if 0 +/* textureOffset - no bias */ + vec4 textureOffset( sampler1D sampler, float P, int offset); +ivec4 textureOffset(isampler1D sampler, float P, int offset); +uvec4 textureOffset(usampler1D sampler, float P, int offset); + + vec4 textureOffset( sampler2D sampler, vec2 P, ivec2 offset); +ivec4 textureOffset(isampler2D sampler, vec2 P, ivec2 offset); +uvec4 textureOffset(usampler2D sampler, vec2 P, ivec2 offset); + + vec4 textureOffset( sampler3D sampler, vec3 P, ivec3 offset); +ivec4 textureOffset(isampler3D sampler, vec3 P, ivec3 offset); +uvec4 textureOffset(usampler3D sampler, vec3 P, ivec3 offset); + +float textureOffset(sampler1DShadow sampler, vec3 P, int offset); +float textureOffset(sampler2DShadow sampler, vec3 P, ivec2 offset); + + vec4 textureOffset( sampler1DArray sampler, vec2 P, int offset); +ivec4 textureOffset(isampler1DArray sampler, vec2 P, int offset); +uvec4 textureOffset(usampler1DArray sampler, vec2 P, int offset); + + vec4 textureOffset( sampler2DArray sampler, vec3 P, ivec2 offset); +ivec4 textureOffset(isampler2DArray sampler, vec3 P, ivec2 offset); +uvec4 textureOffset(usampler2DArray sampler, vec3 P, ivec2 offset); + +float textureOffset(sampler1DArrayShadow sampler, vec3 P, int offset); + +/* textureOffset - bias variants */ + vec4 textureOffset( sampler1D sampler, float P, int offset, float bias); +ivec4 textureOffset(isampler1D sampler, float P, int offset, float bias); +uvec4 textureOffset(usampler1D sampler, float P, int offset, float bias); + + vec4 textureOffset( sampler2D sampler, vec2 P, ivec2 offset, float bias); +ivec4 textureOffset(isampler2D sampler, vec2 P, ivec2 offset, float bias); +uvec4 textureOffset(usampler2D sampler, vec2 P, ivec2 offset, float bias); + + vec4 textureOffset( sampler3D sampler, vec3 P, ivec3 offset, float bias); +ivec4 textureOffset(isampler3D sampler, vec3 P, ivec3 offset, float bias); +uvec4 textureOffset(usampler3D sampler, vec3 P, ivec3 offset, float bias); + +float textureOffset(sampler1DShadow sampler, vec3 P, int offset, float bias); +float textureOffset(sampler2DShadow sampler, vec3 P, ivec2 offset, float bias); + + vec4 textureOffset( sampler1DArray sampler, vec2 P, int offset, float bias); +ivec4 textureOffset(isampler1DArray sampler, vec2 P, int offset, float bias); +uvec4 textureOffset(usampler1DArray sampler, vec2 P, int offset, float bias); + + vec4 textureOffset( sampler2DArray sampler, vec3 P, ivec2 offset, float bias); +ivec4 textureOffset(isampler2DArray sampler, vec3 P, ivec2 offset, float bias); +uvec4 textureOffset(usampler2DArray sampler, vec3 P, ivec2 offset, float bias); + +float textureOffset(sampler1DArrayShadow samp, vec3 P, int offset, float bias); +#endif + +/* texelFetch */ + vec4 texelFetch( sampler1D sampler, int P, int lod); +ivec4 texelFetch(isampler1D sampler, int P, int lod); +uvec4 texelFetch(usampler1D sampler, int P, int lod); + + vec4 texelFetch( sampler2D sampler, ivec2 P, int lod); +ivec4 texelFetch(isampler2D sampler, ivec2 P, int lod); +uvec4 texelFetch(usampler2D sampler, ivec2 P, int lod); + + vec4 texelFetch( sampler3D sampler, ivec3 P, int lod); +ivec4 texelFetch(isampler3D sampler, ivec3 P, int lod); +uvec4 texelFetch(usampler3D sampler, ivec3 P, int lod); + + vec4 texelFetch( sampler1DArray sampler, ivec2 P, int lod); +ivec4 texelFetch(isampler1DArray sampler, ivec2 P, int lod); +uvec4 texelFetch(usampler1DArray sampler, ivec2 P, int lod); + + vec4 texelFetch( sampler2DArray sampler, ivec3 P, int lod); +ivec4 texelFetch(isampler2DArray sampler, ivec3 P, int lod); +uvec4 texelFetch(usampler2DArray sampler, ivec3 P, int lod); + +#if 0 +/* texelFetchOffset */ + vec4 texelFetchOffset( sampler1D sampler, int P, int lod, int offset); +ivec4 texelFetchOffset(isampler1D sampler, int P, int lod, int offset); +uvec4 texelFetchOffset(usampler1D sampler, int P, int lod, int offset); + + vec4 texelFetchOffset( sampler2D sampler, ivec2 P, int lod, ivec2 offset); +ivec4 texelFetchOffset(isampler2D sampler, ivec2 P, int lod, ivec2 offset); +uvec4 texelFetchOffset(usampler2D sampler, ivec2 P, int lod, ivec2 offset); + + vec4 texelFetchOffset( sampler3D sampler, ivec3 P, int lod, ivec3 offset); +ivec4 texelFetchOffset(isampler3D sampler, ivec3 P, int lod, ivec3 offset); +uvec4 texelFetchOffset(usampler3D sampler, ivec3 P, int lod, ivec3 offset); + + vec4 texelFetchOffset( sampler1DArray sampler, ivec2 P, int lod, int offset); +ivec4 texelFetchOffset(isampler1DArray sampler, ivec2 P, int lod, int offset); +uvec4 texelFetchOffset(usampler1DArray sampler, ivec2 P, int lod, int offset); + + vec4 texelFetchOffset( sampler2DArray sampler, ivec3 P, int lod, ivec2 offset); +ivec4 texelFetchOffset(isampler2DArray sampler, ivec3 P, int lod, ivec2 offset); +uvec4 texelFetchOffset(usampler2DArray sampler, ivec3 P, int lod, ivec2 offset); + +/* textureProjOffset - no bias */ + vec4 textureProj( sampler1D sampler, vec2 P, int offset); +ivec4 textureProj(isampler1D sampler, vec2 P, int offset); +uvec4 textureProj(usampler1D sampler, vec2 P, int offset); + vec4 textureProj( sampler1D sampler, vec4 P, int offset); +ivec4 textureProj(isampler1D sampler, vec4 P, int offset); +uvec4 textureProj(usampler1D sampler, vec4 P, int offset); + + vec4 textureProj( sampler2D sampler, vec3 P, ivec2 offset); +ivec4 textureProj(isampler2D sampler, vec3 P, ivec2 offset); +uvec4 textureProj(usampler2D sampler, vec3 P, ivec2 offset); + vec4 textureProj( sampler2D sampler, vec4 P, ivec2 offset); +ivec4 textureProj(isampler2D sampler, vec4 P, ivec2 offset); +uvec4 textureProj(usampler2D sampler, vec4 P, ivec2 offset); + + vec4 textureProj( sampler3D sampler, vec4 P, ivec3 offset); +ivec4 textureProj(isampler3D sampler, vec4 P, ivec3 offset); +uvec4 textureProj(usampler3D sampler, vec4 P, ivec3 offset); + +float textureProj(sampler1DShadow sampler, vec4 P, int offset); +float textureProj(sampler2DShadow sampler, vec4 P, ivec2 offset); + +/* textureProjOffset - bias variants */ + vec4 textureProj( sampler1D sampler, vec2 P, int offset, float bias); +ivec4 textureProj(isampler1D sampler, vec2 P, int offset, float bias); +uvec4 textureProj(usampler1D sampler, vec2 P, int offset, float bias); + vec4 textureProj( sampler1D sampler, vec4 P, int offset, float bias); +ivec4 textureProj(isampler1D sampler, vec4 P, int offset, float bias); +uvec4 textureProj(usampler1D sampler, vec4 P, int offset, float bias); + + vec4 textureProj( sampler2D sampler, vec3 P, ivec2 offset, float bias); +ivec4 textureProj(isampler2D sampler, vec3 P, ivec2 offset, float bias); +uvec4 textureProj(usampler2D sampler, vec3 P, ivec2 offset, float bias); + vec4 textureProj( sampler2D sampler, vec4 P, ivec2 offset, float bias); +ivec4 textureProj(isampler2D sampler, vec4 P, ivec2 offset, float bias); +uvec4 textureProj(usampler2D sampler, vec4 P, ivec2 offset, float bias); + + vec4 textureProj( sampler3D sampler, vec4 P, ivec3 offset, float bias); +ivec4 textureProj(isampler3D sampler, vec4 P, ivec3 offset, float bias); +uvec4 textureProj(usampler3D sampler, vec4 P, ivec3 offset, float bias); + +float textureProj(sampler1DShadow sampler, vec4 P, int offset, float bias); +float textureProj(sampler2DShadow sampler, vec4 P, ivec2 offset, float bias); + +/* textureLodOffset */ + vec4 textureLodOffset( sampler1D sampler, float P, float lod, int offset); +ivec4 textureLodOffset(isampler1D sampler, float P, float lod, int offset); +uvec4 textureLodOffset(usampler1D sampler, float P, float lod, int offset); + + vec4 textureLodOffset( sampler2D sampler, vec2 P, float lod, ivec2 offset); +ivec4 textureLodOffset(isampler2D sampler, vec2 P, float lod, ivec2 offset); +uvec4 textureLodOffset(usampler2D sampler, vec2 P, float lod, ivec2 offset); + + vec4 textureLodOffset( sampler3D sampler, vec3 P, float lod, ivec3 offset); +ivec4 textureLodOffset(isampler3D sampler, vec3 P, float lod, ivec3 offset); +uvec4 textureLodOffset(usampler3D sampler, vec3 P, float lod, ivec3 offset); + +float textureLodOffset(sampler1DShadow samp, vec3 P, float lod, int offset); +float textureLodOffset(sampler2DShadow samp, vec3 P, float lod, ivec2 offset); + + vec4 textureLodOffset( sampler1DArray sampler, vec2 P, float lod, int offset); +ivec4 textureLodOffset(isampler1DArray sampler, vec2 P, float lod, int offset); +uvec4 textureLodOffset(usampler1DArray sampler, vec2 P, float lod, int offset); + + vec4 textureLodOffset( sampler2DArray samp, vec3 P, float lod, ivec2 offset); +ivec4 textureLodOffset(isampler2DArray samp, vec3 P, float lod, ivec2 offset); +uvec4 textureLodOffset(usampler2DArray samp, vec3 P, float lod, ivec2 offset); + +float textureLodOffset(sampler1DArrayShadow s, vec3 P, float lod, int offset); +#endif + +/* textureProjLod */ + vec4 textureProjLod( sampler1D sampler, vec2 P, float lod); +ivec4 textureProjLod(isampler1D sampler, vec2 P, float lod); +uvec4 textureProjLod(usampler1D sampler, vec2 P, float lod); + vec4 textureProjLod( sampler1D sampler, vec4 P, float lod); +ivec4 textureProjLod(isampler1D sampler, vec4 P, float lod); +uvec4 textureProjLod(usampler1D sampler, vec4 P, float lod); + + vec4 textureProjLod( sampler2D sampler, vec3 P, float lod); +ivec4 textureProjLod(isampler2D sampler, vec3 P, float lod); +uvec4 textureProjLod(usampler2D sampler, vec3 P, float lod); + vec4 textureProjLod( sampler2D sampler, vec4 P, float lod); +ivec4 textureProjLod(isampler2D sampler, vec4 P, float lod); +uvec4 textureProjLod(usampler2D sampler, vec4 P, float lod); + + vec4 textureProjLod( sampler3D sampler, vec4 P, float lod); +ivec4 textureProjLod(isampler3D sampler, vec4 P, float lod); +uvec4 textureProjLod(usampler3D sampler, vec4 P, float lod); + +float textureProjLod(sampler1DShadow sampler, vec4 P, float lod); +float textureProjLod(sampler2DShadow sampler, vec4 P, float lod); + +#if 0 +/* textureProjLodOffset */ + vec4 textureProjLodOffset( sampler1D sampler, vec2 P, float lod, int offset); +ivec4 textureProjLodOffset(isampler1D sampler, vec2 P, float lod, int offset); +uvec4 textureProjLodOffset(usampler1D sampler, vec2 P, float lod, int offset); + vec4 textureProjLodOffset( sampler1D sampler, vec4 P, float lod, int offset); +ivec4 textureProjLodOffset(isampler1D sampler, vec4 P, float lod, int offset); +uvec4 textureProjLodOffset(usampler1D sampler, vec4 P, float lod, int offset); + + vec4 textureProjLodOffset( sampler2D sampler, vec3 P, float lod, ivec2 offset); +ivec4 textureProjLodOffset(isampler2D sampler, vec3 P, float lod, ivec2 offset); +uvec4 textureProjLodOffset(usampler2D sampler, vec3 P, float lod, ivec2 offset); + vec4 textureProjLodOffset( sampler2D sampler, vec4 P, float lod, ivec2 offset); +ivec4 textureProjLodOffset(isampler2D sampler, vec4 P, float lod, ivec2 offset); +uvec4 textureProjLodOffset(usampler2D sampler, vec4 P, float lod, ivec2 offset); + + vec4 textureProjLodOffset( sampler3D sampler, vec4 P, float lod, ivec3 offset); +ivec4 textureProjLodOffset(isampler3D sampler, vec4 P, float lod, ivec3 offset); +uvec4 textureProjLodOffset(usampler3D sampler, vec4 P, float lod, ivec3 offset); + +float textureProjLodOffset(sampler1DShadow s, vec4 P, float lod, int offset); +float textureProjLodOffset(sampler2DShadow s, vec4 P, float lod, ivec2 offset); +#endif + +/* textureGrad */ + vec4 textureGrad( sampler1D sampler, float P, float dPdx, float dPdy); +ivec4 textureGrad(isampler1D sampler, float P, float dPdx, float dPdy); +uvec4 textureGrad(usampler1D sampler, float P, float dPdx, float dPdy); + + vec4 textureGrad( sampler2D sampler, vec2 P, vec2 dPdx, vec2 dPdy); +ivec4 textureGrad(isampler2D sampler, vec2 P, vec2 dPdx, vec2 dPdy); +uvec4 textureGrad(usampler2D sampler, vec2 P, vec2 dPdx, vec2 dPdy); + + vec4 textureGrad( sampler3D sampler, vec3 P, vec3 dPdx, vec3 dPdy); +ivec4 textureGrad(isampler3D sampler, vec3 P, vec3 dPdx, vec3 dPdy); +uvec4 textureGrad(usampler3D sampler, vec3 P, vec3 dPdx, vec3 dPdy); + + vec4 textureGrad( samplerCube sampler, vec3 P, vec3 dPdx, vec3 dPdy); +ivec4 textureGrad(isamplerCube sampler, vec3 P, vec3 dPdx, vec3 dPdy); +uvec4 textureGrad(usamplerCube sampler, vec3 P, vec3 dPdx, vec3 dPdy); + +float textureGrad(sampler1DShadow sampler, vec3 P, float dPdx, float dPdy); +float textureGrad(sampler2DShadow sampler, vec3 P, vec2 dPdx, vec2 dPdy); +float textureGrad(samplerCubeShadow sampler, vec4 P, vec3 dPdx, vec3 dPdy); + + vec4 textureGrad( sampler1DArray sampler, vec2 P, float dPdx, float dPdy); +ivec4 textureGrad(isampler1DArray sampler, vec2 P, float dPdx, float dPdy); +uvec4 textureGrad(usampler1DArray sampler, vec2 P, float dPdx, float dPdy); + + vec4 textureGrad( sampler2DArray sampler, vec3 P, vec2 dPdx, vec2 dPdy); +ivec4 textureGrad(isampler2DArray sampler, vec3 P, vec2 dPdx, vec2 dPdy); +uvec4 textureGrad(usampler2DArray sampler, vec3 P, vec2 dPdx, vec2 dPdy); + +float textureGrad(sampler1DArrayShadow sampler, vec3 P, float dPdx, float dPdy); +float textureGrad(sampler2DArrayShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy); + +#if 0 +/* textureGradOffset */ + vec4 textureGradOffset( sampler1D s, float P, float dx, float dy, int off); +ivec4 textureGradOffset(isampler1D s, float P, float dx, float dy, int offset); +uvec4 textureGradOffset(usampler1D s, float P, float dx, float dy, int offset); + + vec4 textureGradOffset( sampler2D s, vec2 P, vec2 dx, vec2 dy, ivec2 offset); +ivec4 textureGradOffset(isampler2D s, vec2 P, vec2 dx, vec2 dy, ivec2 offset); +uvec4 textureGradOffset(usampler2D s, vec2 P, vec2 dx, vec2 dy, ivec2 offset); + + vec4 textureGradOffset( sampler3D s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); +ivec4 textureGradOffset(isampler3D s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); +uvec4 textureGradOffset(usampler3D s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); + + vec4 textureGradOffset( samplerCube s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); +ivec4 textureGradOffset(isamplerCube s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); +uvec4 textureGradOffset(usamplerCube s, vec3 P, vec3 dx, vec3 dy, ivec3 offset); + +float textureGradOffset(sampler1DShadow s, vec3 P, float dx, float dy, int off); +float textureGradOffset(sampler2DShadow s, vec3 P, vec2 dx, vec2 dy, ivec2 off); + + vec4 textureGradOffset( sampler1DArray s, vec2 P, float dx, float dy, int off); +ivec4 textureGradOffset(isampler1DArray s, vec2 P, float dx, float dy, int off); +uvec4 textureGradOffset(usampler1DArray s, vec2 P, float dx, float dy, int off); + + vec4 textureGradOffset( sampler2DArray s, vec3 P, vec2 dx, vec2 dy, ivec2 off); +ivec4 textureGradOffset(isampler2DArray s, vec3 P, vec2 dx, vec2 dy, ivec2 off); +uvec4 textureGradOffset(usampler2DArray s, vec3 P, vec2 dx, vec2 dy, ivec2 off); + +float textureGradOffset(sampler1DArrayShadow s, vec3 P, float dx, float dy, int o); +float textureGradOffset(sampler2DArrayShadow s, vec4 P, vec2 dx, vec2 dy, ivec2 o); +#endif + +/* textureProjGrad */ + vec4 textureProjGrad( sampler1D sampler, vec2 P, float dPdx, float dPdy); +ivec4 textureProjGrad(isampler1D sampler, vec2 P, float dPdx, float dPdy); +uvec4 textureProjGrad(usampler1D sampler, vec2 P, float dPdx, float dPdy); + vec4 textureProjGrad( sampler1D sampler, vec4 P, float dPdx, float dPdy); +ivec4 textureProjGrad(isampler1D sampler, vec4 P, float dPdx, float dPdy); +uvec4 textureProjGrad(usampler1D sampler, vec4 P, float dPdx, float dPdy); + + vec4 textureProjGrad( sampler2D sampler, vec3 P, vec2 dPdx, vec2 dPdy); +ivec4 textureProjGrad(isampler2D sampler, vec3 P, vec2 dPdx, vec2 dPdy); +uvec4 textureProjGrad(usampler2D sampler, vec3 P, vec2 dPdx, vec2 dPdy); + vec4 textureProjGrad( sampler2D sampler, vec4 P, vec2 dPdx, vec2 dPdy); +ivec4 textureProjGrad(isampler2D sampler, vec4 P, vec2 dPdx, vec2 dPdy); +uvec4 textureProjGrad(usampler2D sampler, vec4 P, vec2 dPdx, vec2 dPdy); + + vec4 textureProjGrad( sampler3D sampler, vec4 P, vec3 dPdx, vec3 dPdy); +ivec4 textureProjGrad(isampler3D sampler, vec4 P, vec3 dPdx, vec3 dPdy); +uvec4 textureProjGrad(usampler3D sampler, vec4 P, vec3 dPdx, vec3 dPdy); + +float textureProjGrad(sampler1DShadow sampler, vec4 P, float dPdx, float dPdy); +float textureProjGrad(sampler2DShadow sampler, vec4 P, vec2 dPdx, vec2 dPdy); + +#if 0 +/* textureProjGradOffset */ + vec4 textureProjGradOffset( sampler1D s, vec2 P, float dx, float dy, int off); +ivec4 textureProjGradOffset(isampler1D s, vec2 P, float dx, float dy, int off); +uvec4 textureProjGradOffset(usampler1D s, vec2 P, float dx, float dy, int off); + vec4 textureProjGradOffset( sampler1D s, vec4 P, float dx, float dy, int off); +ivec4 textureProjGradOffset(isampler1D s, vec4 P, float dx, float dy, int off); +uvec4 textureProjGradOffset(usampler1D s, vec4 P, float dx, float dy, int off); + + vec4 textureProjGradOffset( sampler2D s, vec3 P, vec2 dx, vec2 dy, ivec2 off); +ivec4 textureProjGradOffset(isampler2D s, vec3 P, vec2 dx, vec2 dy, ivec2 off); +uvec4 textureProjGradOffset(usampler2D s, vec3 P, vec2 dx, vec2 dy, ivec2 off); + vec4 textureProjGradOffset( sampler2D s, vec4 P, vec2 dx, vec2 dy, ivec2 off); +ivec4 textureProjGradOffset(isampler2D s, vec4 P, vec2 dx, vec2 dy, ivec2 off); +uvec4 textureProjGradOffset(usampler2D s, vec4 P, vec2 dx, vec2 dy, ivec2 off); + + vec4 textureProjGradOffset( sampler3D s, vec4 P, vec3 dx, vec3 dy, ivec3 off); +ivec4 textureProjGradOffset(isampler3D s, vec4 P, vec3 dx, vec3 dy, ivec3 off); +uvec4 textureProjGradOffset(usampler3D s, vec4 P, vec3 dx, vec3 dy, ivec3 off); + +float textureProjGradOffset(sampler1DShadow s, vec4 P, float dx, float dy, int o); +float textureProjGradOffset(sampler2DShadow s, vec4 P, vec2 dx, vec2 dy, vec2 o); +#endif + +/* + * The following texture functions are deprecated: + */ +vec4 texture1D (sampler1D sampler, float coord); +vec4 texture1DProj (sampler1D sampler, vec2 coord); +vec4 texture1DProj (sampler1D sampler, vec4 coord); +vec4 texture1D (sampler1D sampler, float coord, float bias); +vec4 texture1DProj (sampler1D sampler, vec2 coord, float bias); +vec4 texture1DProj (sampler1D sampler, vec4 coord, float bias); +vec4 texture1DLod (sampler1D sampler, float coord, float lod); +vec4 texture1DProjLod(sampler1D sampler, vec2 coord, float lod); +vec4 texture1DProjLod(sampler1D sampler, vec4 coord, float lod); + +vec4 texture2D (sampler2D sampler, vec2 coord); +vec4 texture2DProj (sampler2D sampler, vec3 coord); +vec4 texture2DProj (sampler2D sampler, vec4 coord); +vec4 texture2D (sampler2D sampler, vec2 coord, float bias); +vec4 texture2DProj (sampler2D sampler, vec3 coord, float bias); +vec4 texture2DProj (sampler2D sampler, vec4 coord, float bias); +vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod); +vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod); +vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod); + +vec4 texture3D (sampler3D sampler, vec3 coord); +vec4 texture3DProj (sampler3D sampler, vec4 coord); +vec4 texture3D (sampler3D sampler, vec3 coord, float bias); +vec4 texture3DProj (sampler3D sampler, vec4 coord, float bias); +vec4 texture3DLod (sampler3D sampler, vec3 coord, float lod); +vec4 texture3DProjLod(sampler3D sampler, vec4 coord, float lod); + +vec4 textureCube (samplerCube sampler, vec3 coord); +vec4 textureCube (samplerCube sampler, vec3 coord, float bias); +vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod); + +vec4 shadow1D (sampler1DShadow sampler, vec3 coord); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord); +vec4 shadow1D (sampler1DShadow sampler, vec3 coord, float bias); +vec4 shadow2D (sampler2DShadow sampler, vec3 coord, float bias); +vec4 shadow1DProj (sampler1DShadow sampler, vec4 coord, float bias); +vec4 shadow2DProj (sampler2DShadow sampler, vec4 coord, float bias); +vec4 shadow1DLod (sampler1DShadow sampler, vec3 coord, float lod); +vec4 shadow2DLod (sampler2DShadow sampler, vec3 coord, float lod); +vec4 shadow1DProjLod(sampler1DShadow sampler, vec4 coord, float lod); +vec4 shadow2DProjLod(sampler2DShadow sampler, vec4 coord, float lod); + +/* + * 8.8 - Fragment Processing Functions (none in vertex shader) + */ + +/* + * 8.9 - Noise Functions + */ +float noise1(float x); +float noise1(vec2 x); +float noise1(vec3 x); +float noise1(vec4 x); + +vec2 noise2(float x); +vec2 noise2(vec2 x); +vec2 noise2(vec3 x); +vec2 noise2(vec4 x); + +vec3 noise3(float x); +vec3 noise3(vec2 x); +vec3 noise3(vec3 x); +vec3 noise3(vec4 x); + +vec4 noise4(float x); +vec4 noise4(vec2 x); +vec4 noise4(vec3 x); +vec4 noise4(vec4 x); diff --git a/src/glsl/builtins/profiles/ARB_texture_rectangle.frag b/src/glsl/builtins/profiles/ARB_texture_rectangle.frag new file mode 100644 index 0000000000..8938aa3e97 --- /dev/null +++ b/src/glsl/builtins/profiles/ARB_texture_rectangle.frag @@ -0,0 +1,7 @@ +#extension GL_ARB_texture_rectangle : enable +vec4 texture2DRect(sampler2DRect sampler, vec2 coord); +vec4 texture2DRectProj(sampler2DRect sampler, vec3 coord); +vec4 texture2DRectProj(sampler2DRect sampler, vec4 coord); + +vec4 shadow2DRect(sampler2DRectShadow sampler, vec3 coord); +vec4 shadow2DRectProj(sampler2DRectShadow sampler, vec4 coord); diff --git a/src/glsl/builtins/profiles/ARB_texture_rectangle.vert b/src/glsl/builtins/profiles/ARB_texture_rectangle.vert new file mode 100644 index 0000000000..8938aa3e97 --- /dev/null +++ b/src/glsl/builtins/profiles/ARB_texture_rectangle.vert @@ -0,0 +1,7 @@ +#extension GL_ARB_texture_rectangle : enable +vec4 texture2DRect(sampler2DRect sampler, vec2 coord); +vec4 texture2DRectProj(sampler2DRect sampler, vec3 coord); +vec4 texture2DRectProj(sampler2DRect sampler, vec4 coord); + +vec4 shadow2DRect(sampler2DRectShadow sampler, vec3 coord); +vec4 shadow2DRectProj(sampler2DRectShadow sampler, vec4 coord); diff --git a/src/glsl/builtins/profiles/EXT_texture_array.frag b/src/glsl/builtins/profiles/EXT_texture_array.frag new file mode 100644 index 0000000000..d0ce981dd9 --- /dev/null +++ b/src/glsl/builtins/profiles/EXT_texture_array.frag @@ -0,0 +1,11 @@ +#extension GL_EXT_texture_array : enable +vec4 texture1DArray(sampler1DArray sampler, vec2 coord); +vec4 texture1DArray(sampler1DArray sampler, vec2 coord, float bias); + +vec4 texture2DArray(sampler2DArray sampler, vec3 coord); +vec4 texture2DArray(sampler2DArray sampler, vec3 coord, float bias); + +vec4 shadow1DArray(sampler1DArrayShadow sampler, vec3 coord); +vec4 shadow1DArray(sampler1DArrayShadow sampler, vec3 coord, float bias); + +vec4 shadow2DArray(sampler2DArrayShadow sampler, vec4 coord); diff --git a/src/glsl/builtins/profiles/EXT_texture_array.vert b/src/glsl/builtins/profiles/EXT_texture_array.vert new file mode 100644 index 0000000000..6b1b7f2f16 --- /dev/null +++ b/src/glsl/builtins/profiles/EXT_texture_array.vert @@ -0,0 +1,11 @@ +#extension GL_EXT_texture_array : enable +vec4 texture1DArray(sampler1DArray sampler, vec2 coord); +vec4 texture1DArrayLod(sampler1DArray sampler, vec2 coord, float lod); + +vec4 texture2DArray(sampler2DArray sampler, vec3 coord); +vec4 texture2DArrayLod(sampler2DArray sampler, vec3 coord, float lod); + +vec4 shadow1DArray(sampler1DArrayShadow sampler, vec3 coord); +vec4 shadow1DArrayLod(sampler1DArrayShadow sampler, vec3 coord, float lod); + +vec4 shadow2DArray(sampler2DArrayShadow sampler, vec4 coord); diff --git a/src/glsl/builtins/tools/builtin_function.cpp b/src/glsl/builtins/tools/builtin_function.cpp new file mode 100644 index 0000000000..c44804f2ef --- /dev/null +++ b/src/glsl/builtins/tools/builtin_function.cpp @@ -0,0 +1,39 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include "glsl_parser_extras.h" + +/* A dummy file. When compiling prototypes, we don't care about builtins. + * We really don't want to half-compile builtin_functions.cpp and fail, though. + */ +void +_mesa_glsl_release_functions(void) +{ +} + +void +_mesa_glsl_initialize_functions(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ +} diff --git a/src/glsl/builtins/tools/generate_builtins.py b/src/glsl/builtins/tools/generate_builtins.py new file mode 100755 index 0000000000..5accc1b120 --- /dev/null +++ b/src/glsl/builtins/tools/generate_builtins.py @@ -0,0 +1,240 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import re +from glob import glob +from os import path +from subprocess import Popen, PIPE + +# Local module: generator for texture lookup builtins +from texture_builtins import generate_texture_functions + +builtins_dir = path.join(path.dirname(path.abspath(__file__)), "..") + +# Read the files in builtins/ir/*...add them to the supplied dictionary. +def read_ir_files(fs): + for filename in glob(path.join(path.join(builtins_dir, 'ir'), '*')): + with open(filename) as f: + fs[path.basename(filename)] = f.read() + +# Return a dictionary containing all builtin definitions (even generated) +def get_builtin_definitions(): + fs = {} + generate_texture_functions(fs) + read_ir_files(fs) + return fs + +def stringify(s): + t = s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n"\n "') + return ' "' + t + '"\n' + +def write_function_definitions(): + fs = get_builtin_definitions() + for k, v in sorted(fs.iteritems()): + print 'static const char *builtin_' + k + ' =' + print stringify(v), ';' + +def run_compiler(args): + compiler_path = path.join(path.join(builtins_dir, '..'), 'glsl_compiler') + command = [compiler_path, '--dump-lir'] + args + p = Popen(command, 1, stdout=PIPE, shell=False) + output = p.communicate()[0] + + # Clean up output a bit by killing whitespace before a closing paren. + kill_paren_whitespace = re.compile(r'[ \n]*\)', re.MULTILINE); + output = kill_paren_whitespace.sub(')', output); + + # Also toss any duplicate newlines + output = output.replace('\n\n', '\n') + + return (output, p.returncode) + +def write_profile(filename, profile): + (proto_ir, returncode) = run_compiler([filename]) + + if returncode != 0: + print '#error builtins profile', profile, 'failed to compile' + return + + # Kill any global variable declarations. We don't want them. + kill_globals = re.compile(r'^\(declare.*\n', re.MULTILINE); + proto_ir = kill_globals.sub('', proto_ir) + + # Kill pointer addresses. They're not necessary in prototypes and just + # clutter the diff output. + proto_ir = re.sub(r'@0x[0-9a-f]+', '', proto_ir); + + print 'static const char *prototypes_for_' + profile + ' =' + print stringify(proto_ir), ';' + + # Print a table of all the functions (not signatures) referenced. + # This is done so we can avoid bothering with a hash table in the C++ code. + + function_names = set() + for func in re.finditer(r'\(function (.+)\n', proto_ir): + function_names.add(func.group(1)) + + print 'static const char *functions_for_' + profile + ' [] = {' + for func in sorted(function_names): + print ' builtin_' + func + ',' + print '};' + +def write_profiles(): + profiles = get_profile_list() + for (filename, profile) in profiles: + write_profile(filename, profile) + +def get_profile_list(): + profiles = [] + for pfile in sorted(glob(path.join(path.join(builtins_dir, 'profiles'), '*'))): + profiles.append((pfile, path.basename(pfile).replace('.', '_'))) + return profiles + +if __name__ == "__main__": + print """/* DO NOT MODIFY - automatically generated by generate_builtins.py */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include "main/core.h" /* for struct gl_shader */ +#include "glsl_parser_extras.h" +#include "ir_reader.h" +#include "program.h" +#include "ast.h" + +extern "C" struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type); + +gl_shader * +read_builtins(GLenum target, const char *protos, const char **functions, unsigned count) +{ + gl_shader *sh = _mesa_new_shader(NULL, 0, target); + struct _mesa_glsl_parse_state *st = + new(sh) _mesa_glsl_parse_state(NULL, target, sh); + + st->language_version = 130; + st->symbols->language_version = 130; + st->ARB_texture_rectangle_enable = true; + st->EXT_texture_array_enable = true; + _mesa_glsl_initialize_types(st); + + sh->ir = new(sh) exec_list; + sh->symbols = st->symbols; + + /* Read the IR containing the prototypes */ + _mesa_glsl_read_ir(st, sh->ir, protos, true); + + /* Read ALL the function bodies, telling the IR reader not to scan for + * prototypes (we've already created them). The IR reader will skip any + * signature that does not already exist as a prototype. + */ + for (unsigned i = 0; i < count; i++) { + _mesa_glsl_read_ir(st, sh->ir, functions[i], false); + + if (st->error) { + printf("error reading builtin: %.35s ...\\n", functions[i]); + talloc_free(sh); + return NULL; + } + } + + reparent_ir(sh->ir, sh); + delete st; + + return sh; +} +""" + + write_function_definitions() + write_profiles() + + profiles = get_profile_list() + + print 'static gl_shader *builtin_profiles[%d];' % len(profiles) + + print """ +void *builtin_mem_ctx = NULL; + +void +_mesa_glsl_release_functions(void) +{ + talloc_free(builtin_mem_ctx); + builtin_mem_ctx = NULL; +} + +static void +_mesa_read_profile(struct _mesa_glsl_parse_state *state, + exec_list *instructions, + int profile_index, + const char *prototypes, + const char **functions, + int count) +{ + gl_shader *sh = builtin_profiles[profile_index]; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, prototypes, functions, count); + talloc_steal(builtin_mem_ctx, sh); + builtin_profiles[profile_index] = sh; + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; +} + +void +_mesa_glsl_initialize_functions(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + if (builtin_mem_ctx == NULL) { + builtin_mem_ctx = talloc_init("GLSL built-in functions"); + memset(&builtin_profiles, 0, sizeof(builtin_profiles)); + } + + state->num_builtins_to_link = 0; +""" + + i=0 + for (filename, profile) in profiles: + if profile.endswith('_vert'): + check = 'state->target == vertex_shader && ' + elif profile.endswith('_frag'): + check = 'state->target == fragment_shader && ' + + version = re.sub(r'_(vert|frag)$', '', profile) + if version.isdigit(): + check += 'state->language_version == ' + version + else: # an extension name + check += 'state->' + version + '_enable' + + print ' if (' + check + ') {' + print ' _mesa_read_profile(state, instructions, %d,' % i + print ' prototypes_for_' + profile + ',' + print ' functions_for_' + profile + ',' + print ' Elements(functions_for_' + profile + '));' + print ' }' + print + i = i + 1 + print '}' + diff --git a/src/glsl/builtins/tools/generate_matrixCompMultGLSL.py b/src/glsl/builtins/tools/generate_matrixCompMultGLSL.py new file mode 100755 index 0000000000..391ad110d3 --- /dev/null +++ b/src/glsl/builtins/tools/generate_matrixCompMultGLSL.py @@ -0,0 +1,28 @@ +#!/usr/bin/python + +def gen_matrix(x, y = 0): + if y == 0: + y = x + type = "mat" + str(x) + if x != y: + type = type + "x" + str(y) + print type + " matrixCompMult(" + type + " x, " + type + " y)\n{" + print " " + type + " z;" + + for i in range(x): + print " z[" + str(i) + "] = x[" + str(i) + "] * y[" + str(i) + "];" + print " return z;\n}" + +print "#version 120" +# 1.10 +gen_matrix(2) +gen_matrix(3) +gen_matrix(4) + +# 1.20 +gen_matrix(2,3) # mat2x3 means 2 columns, 3 rows +gen_matrix(3,2) +gen_matrix(2,4) +gen_matrix(4,2) +gen_matrix(3,4) +gen_matrix(4,3) diff --git a/src/glsl/builtins/tools/generate_outerProductGLSL.py b/src/glsl/builtins/tools/generate_outerProductGLSL.py new file mode 100755 index 0000000000..c561cc3ba1 --- /dev/null +++ b/src/glsl/builtins/tools/generate_outerProductGLSL.py @@ -0,0 +1,23 @@ +#!/usr/bin/python + +def gen(x, y): + type = "mat" + str(x) + if x != y: + type = type + "x" + str(y) + print type + " outerProduct(vec" + str(y) + " u, vec" + str(x) + " v)\n{" + print " " + type + " m;" + + for i in range(x): + print " m[" + str(i) + "] = u * v[" + str(i) + "];" + print " return m;\n}" + +print "#version 120" +gen(2,2) +gen(2,3) # mat2x3 means 2 columns, 3 rows +gen(2,4) +gen(3,2) +gen(3,3) +gen(3,4) +gen(4,2) +gen(4,3) +gen(4,4) diff --git a/src/glsl/builtins/tools/generate_transposeGLSL.py b/src/glsl/builtins/tools/generate_transposeGLSL.py new file mode 100755 index 0000000000..8f669ce983 --- /dev/null +++ b/src/glsl/builtins/tools/generate_transposeGLSL.py @@ -0,0 +1,28 @@ +#!/usr/bin/python + +def gen(x, y): + origtype = "mat" + str(x) + trantype = "mat" + str(y) + if x != y: + origtype = origtype + "x" + str(y) + trantype = trantype + "x" + str(x) + print trantype + " transpose(" + origtype + " m)\n{" + print " " + trantype + " t;" + + # The obvious implementation of transpose + for i in range(x): + for j in range(y): + print " t[" + str(j) + "][" + str(i) + "] =", + print "m[" + str(i) + "][" + str(j) + "];" + print " return t;\n}" + +print "#version 120" +gen(2,2) +gen(2,3) # mat2x3 means 2 columns, 3 rows +gen(2,4) +gen(3,2) +gen(3,3) +gen(3,4) +gen(4,2) +gen(4,3) +gen(4,4) diff --git a/src/glsl/builtins/tools/texture_builtins.py b/src/glsl/builtins/tools/texture_builtins.py new file mode 100755 index 0000000000..8bf708b5aa --- /dev/null +++ b/src/glsl/builtins/tools/texture_builtins.py @@ -0,0 +1,349 @@ +#!/usr/bin/python + +import sys +import StringIO + +def vec_type(g, size): + if size == 1: + if g == "i": + return "int" + elif g == "u": + return "uint" + return "float" + return g + "vec" + str(size) + +# Get the base dimension - i.e. sampler3D gives 3 +# Array samplers also get +1 here since the layer is really an extra coordinate +def get_coord_dim(sampler_type): + if sampler_type[0].isdigit(): + coord_dim = int(sampler_type[0]) + elif sampler_type.startswith("Cube"): + coord_dim = 3 + else: + assert False ("coord_dim: invalid sampler_type: " + sampler_type) + + if sampler_type.find("Array") != -1: + coord_dim += 1 + return coord_dim + +# Get the number of extra vector components (i.e. shadow comparitor) +def get_extra_dim(sampler_type, use_proj, unused_fields): + extra_dim = unused_fields + if sampler_type.find("Shadow") != -1: + extra_dim += 1 + if use_proj: + extra_dim += 1 + return extra_dim + +def generate_sigs(g, tex_inst, sampler_type, use_proj = False, unused_fields = 0): + coord_dim = get_coord_dim(sampler_type) + extra_dim = get_extra_dim(sampler_type, use_proj, unused_fields) + + # Print parameters + print " (signature " + g + "vec4" + print " (parameters" + print " (declare (in) " + g + "sampler" + sampler_type + " sampler)" + print " (declare (in) " + vec_type("i" if tex_inst == "txf" else "", coord_dim + extra_dim) + " P)", + if tex_inst == "txb": + print "\n (declare (in) float bias)", + elif tex_inst == "txl": + print "\n (declare (in) float lod)", + elif tex_inst == "txf": + print "\n (declare (in) int lod)", + elif tex_inst == "txd": + grad_type = vec_type("", coord_dim) + print "\n (declare (in) " + grad_type + " dPdx)", + print "\n (declare (in) " + grad_type + " dPdy)", + + print ")\n ((return (" + tex_inst + " (var_ref sampler)", + + # Coordinate + if extra_dim > 0: + print "(swiz " + "xyzw"[:coord_dim] + " (var_ref P))", + else: + print "(var_ref P)", + + # Offset + print "(0 0 0)", + + if tex_inst != "txf": + # Projective divisor + if use_proj: + print "(swiz " + "xyzw"[coord_dim + extra_dim-1] + " (var_ref P))", + else: + print "1", + + # Shadow comparitor + if sampler_type == "2DArrayShadow": # a special case: + print "(swiz w (var_ref P))", # ...array layer is z; shadow is w + elif sampler_type.endswith("Shadow"): + print "(swiz z (var_ref P))", + else: + print "()", + + # Bias/explicit LOD/gradient: + if tex_inst == "txb": + print "(var_ref bias)", + elif tex_inst == "txl" or tex_inst == "txf": + print "(var_ref lod)", + elif tex_inst == "txd": + print "((var_ref dPdx) (var_ref dPdy))", + print "))))\n" + +def generate_fiu_sigs(tex_inst, sampler_type, use_proj = False, unused_fields = 0): + generate_sigs("", tex_inst, sampler_type, use_proj, unused_fields) + generate_sigs("i", tex_inst, sampler_type, use_proj, unused_fields) + generate_sigs("u", tex_inst, sampler_type, use_proj, unused_fields) + +def start_function(name): + sys.stdout = StringIO.StringIO() + print "((function " + name + +def end_function(fs, name): + print "))" + fs[name] = sys.stdout.getvalue(); + sys.stdout.close() + +# Generate all the functions and store them in the supplied dictionary. +# This is better than writing them to actual files since they should never be +# edited; it'd also be easy to confuse them with the many hand-generated files. +# +# Takes a dictionary as an argument. +def generate_texture_functions(fs): + start_function("texture") + generate_fiu_sigs("tex", "1D") + generate_fiu_sigs("tex", "2D") + generate_fiu_sigs("tex", "3D") + generate_fiu_sigs("tex", "Cube") + generate_fiu_sigs("tex", "1DArray") + generate_fiu_sigs("tex", "2DArray") + + generate_fiu_sigs("txb", "1D") + generate_fiu_sigs("txb", "2D") + generate_fiu_sigs("txb", "3D") + generate_fiu_sigs("txb", "Cube") + generate_fiu_sigs("txb", "1DArray") + generate_fiu_sigs("txb", "2DArray") + end_function(fs, "texture") + + start_function("textureProj") + generate_fiu_sigs("tex", "1D", True) + generate_fiu_sigs("tex", "1D", True, 2) + generate_fiu_sigs("tex", "2D", True) + generate_fiu_sigs("tex", "2D", True, 1) + generate_fiu_sigs("tex", "3D", True) + + generate_fiu_sigs("txb", "1D", True) + generate_fiu_sigs("txb", "1D", True, 2) + generate_fiu_sigs("txb", "2D", True) + generate_fiu_sigs("txb", "2D", True, 1) + generate_fiu_sigs("txb", "3D", True) + end_function(fs, "textureProj") + + start_function("textureLod") + generate_fiu_sigs("txl", "1D") + generate_fiu_sigs("txl", "2D") + generate_fiu_sigs("txl", "3D") + generate_fiu_sigs("txl", "Cube") + generate_fiu_sigs("txl", "1DArray") + generate_fiu_sigs("txl", "2DArray") + end_function(fs, "textureLod") + + start_function("texelFetch") + generate_fiu_sigs("txf", "1D") + generate_fiu_sigs("txf", "2D") + generate_fiu_sigs("txf", "3D") + generate_fiu_sigs("txf", "1DArray") + generate_fiu_sigs("txf", "2DArray") + end_function(fs, "texelFetch") + + start_function("textureProjLod") + generate_fiu_sigs("txl", "1D", True) + generate_fiu_sigs("txl", "1D", True, 2) + generate_fiu_sigs("txl", "2D", True) + generate_fiu_sigs("txl", "2D", True, 1) + generate_fiu_sigs("txl", "3D", True) + end_function(fs, "textureProjLod") + + start_function("textureGrad") + generate_fiu_sigs("txd", "1D") + generate_fiu_sigs("txd", "2D") + generate_fiu_sigs("txd", "3D") + generate_fiu_sigs("txd", "Cube") + generate_fiu_sigs("txd", "1DArray") + generate_fiu_sigs("txd", "2DArray") + end_function(fs, "textureGrad") + + start_function("textureProjGrad") + generate_fiu_sigs("txd", "1D", True) + generate_fiu_sigs("txd", "1D", True, 2) + generate_fiu_sigs("txd", "2D", True) + generate_fiu_sigs("txd", "2D", True, 1) + generate_fiu_sigs("txd", "3D", True) + end_function(fs, "textureProjGrad") + + # ARB_texture_rectangle extension + start_function("texture2DRect") + generate_sigs("", "tex", "2DRect") + end_function(fs, "texture2DRect") + + start_function("texture2DRectProj") + generate_sigs("", "tex", "2DRect", True) + generate_sigs("", "tex", "2DRect", True, 1) + end_function(fs, "texture2DRectProj") + + start_function("shadow2DRect") + generate_sigs("", "tex", "2DRectShadow") + end_function(fs, "shadow2DRect") + + start_function("shadow2DRectProj") + generate_sigs("", "tex", "2DRectShadow", True) + end_function(fs, "shadow2DRectProj") + + # EXT_texture_array extension + start_function("texture1DArray") + generate_sigs("", "tex", "1DArray") + generate_sigs("", "txb", "1DArray") + end_function(fs, "texture1DArray") + + start_function("texture1DArrayLod") + generate_sigs("", "txl", "1DArray") + end_function(fs, "texture1DArrayLod") + + start_function("texture2DArray") + generate_sigs("", "tex", "2DArray") + generate_sigs("", "txb", "2DArray") + end_function(fs, "texture2DArray") + + start_function("texture2DArrayLod") + generate_sigs("", "txl", "2DArray") + end_function(fs, "texture2DArrayLod") + + start_function("shadow1DArray") + generate_sigs("", "tex", "1DArrayShadow") + generate_sigs("", "txb", "1DArrayShadow") + end_function(fs, "shadow1DArray") + + start_function("shadow1DArrayLod") + generate_sigs("", "txl", "1DArrayShadow") + end_function(fs, "shadow1DArrayLod") + + start_function("shadow2DArray") + generate_sigs("", "tex", "2DArrayShadow") + end_function(fs, "shadow2DArray") + + # Deprecated (110/120 style) functions with silly names: + start_function("texture1D") + generate_sigs("", "tex", "1D") + generate_sigs("", "txb", "1D") + end_function(fs, "texture1D") + + start_function("texture1DLod") + generate_sigs("", "txl", "1D") + end_function(fs, "texture1DLod") + + start_function("texture1DProj") + generate_sigs("", "tex", "1D", True) + generate_sigs("", "tex", "1D", True, 2) + generate_sigs("", "txb", "1D", True) + generate_sigs("", "txb", "1D", True, 2) + end_function(fs, "texture1DProj") + + start_function("texture1DProjLod") + generate_sigs("", "txl", "1D", True) + generate_sigs("", "txl", "1D", True, 2) + end_function(fs, "texture1DProjLod") + + start_function("texture2D") + generate_sigs("", "tex", "2D") + generate_sigs("", "txb", "2D") + end_function(fs, "texture2D") + + start_function("texture2DLod") + generate_sigs("", "txl", "2D") + end_function(fs, "texture2DLod") + + start_function("texture2DProj") + generate_sigs("", "tex", "2D", True) + generate_sigs("", "tex", "2D", True, 1) + generate_sigs("", "txb", "2D", True) + generate_sigs("", "txb", "2D", True, 1) + end_function(fs, "texture2DProj") + + start_function("texture2DProjLod") + generate_sigs("", "txl", "2D", True) + generate_sigs("", "txl", "2D", True, 1) + end_function(fs, "texture2DProjLod") + + start_function("texture3D") + generate_sigs("", "tex", "3D") + generate_sigs("", "txb", "3D") + end_function(fs, "texture3D") + + start_function("texture3DLod") + generate_sigs("", "txl", "3D") + end_function(fs, "texture3DLod") + + start_function("texture3DProj") + generate_sigs("", "tex", "3D", True) + generate_sigs("", "txb", "3D", True) + end_function(fs, "texture3DProj") + + start_function("texture3DProjLod") + generate_sigs("", "txl", "3D", True) + end_function(fs, "texture3DProjLod") + + start_function("textureCube") + generate_sigs("", "tex", "Cube") + generate_sigs("", "txb", "Cube") + end_function(fs, "textureCube") + + start_function("textureCubeLod") + generate_sigs("", "txl", "Cube") + end_function(fs, "textureCubeLod") + + start_function("shadow1D") + generate_sigs("", "tex", "1DShadow", False, 1) + generate_sigs("", "txb", "1DShadow", False, 1) + end_function(fs, "shadow1D") + + start_function("shadow1DLod") + generate_sigs("", "txl", "1DShadow", False, 1) + end_function(fs, "shadow1DLod") + + start_function("shadow1DProj") + generate_sigs("", "tex", "1DShadow", True, 1) + generate_sigs("", "txb", "1DShadow", True, 1) + end_function(fs, "shadow1DProj") + + start_function("shadow1DProjLod") + generate_sigs("", "txl", "1DShadow", True, 1) + end_function(fs, "shadow1DProjLod") + + start_function("shadow2D") + generate_sigs("", "tex", "2DShadow") + generate_sigs("", "txb", "2DShadow") + end_function(fs, "shadow2D") + + start_function("shadow2DLod") + generate_sigs("", "txl", "2DShadow") + end_function(fs, "shadow2DLod") + + start_function("shadow2DProj") + generate_sigs("", "tex", "2DShadow", True) + generate_sigs("", "txb", "2DShadow", True) + end_function(fs, "shadow2DProj") + + start_function("shadow2DProjLod") + generate_sigs("", "txl", "2DShadow", True) + end_function(fs, "shadow2DProjLod") + + sys.stdout = sys.__stdout__ + return fs + +# If you actually run this script, it'll print out all the functions. +if __name__ == "__main__": + fs = {} + generate_texture_functions(fs); + for k, v in fs.iteritems(): + print v diff --git a/src/glsl/cl/Makefile b/src/glsl/cl/Makefile deleted file mode 100644 index 04a52df8c3..0000000000 --- a/src/glsl/cl/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -#src/glsl/cl/Makefile - -TOP = ../../.. - -include $(TOP)/configs/current - -LIBNAME = glslcl - -C_SOURCES = \ - sl_cl_parse.c - -include ../Makefile.template - diff --git a/src/glsl/cl/sl_cl_parse.c b/src/glsl/cl/sl_cl_parse.c deleted file mode 100644 index c1bc6031ce..0000000000 --- a/src/glsl/cl/sl_cl_parse.c +++ /dev/null @@ -1,3027 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include "../pp/sl_pp_public.h" -#include "../pp/sl_pp_token.h" -#include "sl_cl_parse.h" - - -/* revision number - increment after each change affecting emitted output */ -#define REVISION 5 - -/* external declaration (or precision or invariant stmt) */ -#define EXTERNAL_NULL 0 -#define EXTERNAL_FUNCTION_DEFINITION 1 -#define EXTERNAL_DECLARATION 2 -#define DEFAULT_PRECISION 3 -#define INVARIANT_STMT 4 - -/* precision */ -#define PRECISION_DEFAULT 0 -#define PRECISION_LOW 1 -#define PRECISION_MEDIUM 2 -#define PRECISION_HIGH 3 - -/* declaration */ -#define DECLARATION_FUNCTION_PROTOTYPE 1 -#define DECLARATION_INIT_DECLARATOR_LIST 2 - -/* function type */ -#define FUNCTION_ORDINARY 0 -#define FUNCTION_CONSTRUCTOR 1 -#define FUNCTION_OPERATOR 2 - -/* function call type */ -#define FUNCTION_CALL_NONARRAY 0 -#define FUNCTION_CALL_ARRAY 1 - -/* operator type */ -#define OPERATOR_ADDASSIGN 1 -#define OPERATOR_SUBASSIGN 2 -#define OPERATOR_MULASSIGN 3 -#define OPERATOR_DIVASSIGN 4 -/*#define OPERATOR_MODASSIGN 5*/ -/*#define OPERATOR_LSHASSIGN 6*/ -/*#define OPERATOR_RSHASSIGN 7*/ -/*#define OPERATOR_ORASSIGN 8*/ -/*#define OPERATOR_XORASSIGN 9*/ -/*#define OPERATOR_ANDASSIGN 10*/ -#define OPERATOR_LOGICALXOR 11 -/*#define OPERATOR_BITOR 12*/ -/*#define OPERATOR_BITXOR 13*/ -/*#define OPERATOR_BITAND 14*/ -#define OPERATOR_LESS 15 -#define OPERATOR_GREATER 16 -#define OPERATOR_LESSEQUAL 17 -#define OPERATOR_GREATEREQUAL 18 -/*#define OPERATOR_LSHIFT 19*/ -/*#define OPERATOR_RSHIFT 20*/ -#define OPERATOR_MULTIPLY 21 -#define OPERATOR_DIVIDE 22 -/*#define OPERATOR_MODULUS 23*/ -#define OPERATOR_INCREMENT 24 -#define OPERATOR_DECREMENT 25 -#define OPERATOR_PLUS 26 -#define OPERATOR_MINUS 27 -/*#define OPERATOR_COMPLEMENT 28*/ -#define OPERATOR_NOT 29 - -/* init declarator list */ -#define DECLARATOR_NONE 0 -#define DECLARATOR_NEXT 1 - -/* variable declaration */ -#define VARIABLE_NONE 0 -#define VARIABLE_IDENTIFIER 1 -#define VARIABLE_INITIALIZER 2 -#define VARIABLE_ARRAY_EXPLICIT 3 -#define VARIABLE_ARRAY_UNKNOWN 4 - -/* type qualifier */ -#define TYPE_QUALIFIER_NONE 0 -#define TYPE_QUALIFIER_CONST 1 -#define TYPE_QUALIFIER_ATTRIBUTE 2 -#define TYPE_QUALIFIER_VARYING 3 -#define TYPE_QUALIFIER_UNIFORM 4 -#define TYPE_QUALIFIER_FIXEDOUTPUT 5 -#define TYPE_QUALIFIER_FIXEDINPUT 6 - -/* invariant qualifier */ -#define TYPE_VARIANT 90 -#define TYPE_INVARIANT 91 - -/* centroid qualifier */ -#define TYPE_CENTER 95 -#define TYPE_CENTROID 96 - -/* layout qualifiers */ -#define LAYOUT_QUALIFIER_NONE 0 -#define LAYOUT_QUALIFIER_UPPER_LEFT 1 -#define LAYOUT_QUALIFIER_PIXEL_CENTER_INTEGER 2 - -/* type specifier */ -#define TYPE_SPECIFIER_VOID 0 -#define TYPE_SPECIFIER_BOOL 1 -#define TYPE_SPECIFIER_BVEC2 2 -#define TYPE_SPECIFIER_BVEC3 3 -#define TYPE_SPECIFIER_BVEC4 4 -#define TYPE_SPECIFIER_INT 5 -#define TYPE_SPECIFIER_IVEC2 6 -#define TYPE_SPECIFIER_IVEC3 7 -#define TYPE_SPECIFIER_IVEC4 8 -#define TYPE_SPECIFIER_FLOAT 9 -#define TYPE_SPECIFIER_VEC2 10 -#define TYPE_SPECIFIER_VEC3 11 -#define TYPE_SPECIFIER_VEC4 12 -#define TYPE_SPECIFIER_MAT2 13 -#define TYPE_SPECIFIER_MAT3 14 -#define TYPE_SPECIFIER_MAT4 15 -#define TYPE_SPECIFIER_SAMPLER1D 16 -#define TYPE_SPECIFIER_SAMPLER2D 17 -#define TYPE_SPECIFIER_SAMPLER3D 18 -#define TYPE_SPECIFIER_SAMPLERCUBE 19 -#define TYPE_SPECIFIER_SAMPLER1DSHADOW 20 -#define TYPE_SPECIFIER_SAMPLER2DSHADOW 21 -#define TYPE_SPECIFIER_SAMPLER2DRECT 22 -#define TYPE_SPECIFIER_SAMPLER2DRECTSHADOW 23 -#define TYPE_SPECIFIER_STRUCT 24 -#define TYPE_SPECIFIER_TYPENAME 25 - -/* OpenGL 2.1 */ -#define TYPE_SPECIFIER_MAT23 26 -#define TYPE_SPECIFIER_MAT32 27 -#define TYPE_SPECIFIER_MAT24 28 -#define TYPE_SPECIFIER_MAT42 29 -#define TYPE_SPECIFIER_MAT34 30 -#define TYPE_SPECIFIER_MAT43 31 - -/* GL_EXT_texture_array */ -#define TYPE_SPECIFIER_SAMPLER_1D_ARRAY 32 -#define TYPE_SPECIFIER_SAMPLER_2D_ARRAY 33 -#define TYPE_SPECIFIER_SAMPLER_1D_ARRAY_SHADOW 34 -#define TYPE_SPECIFIER_SAMPLER_2D_ARRAY_SHADOW 35 - -/* type specifier array */ -#define TYPE_SPECIFIER_NONARRAY 0 -#define TYPE_SPECIFIER_ARRAY 1 - -/* structure field */ -#define FIELD_NONE 0 -#define FIELD_NEXT 1 -#define FIELD_ARRAY 2 - -/* operation */ -#define OP_END 0 -#define OP_BLOCK_BEGIN_NO_NEW_SCOPE 1 -#define OP_BLOCK_BEGIN_NEW_SCOPE 2 -#define OP_DECLARE 3 -#define OP_ASM 4 -#define OP_BREAK 5 -#define OP_CONTINUE 6 -#define OP_DISCARD 7 -#define OP_RETURN 8 -#define OP_EXPRESSION 9 -#define OP_IF 10 -#define OP_WHILE 11 -#define OP_DO 12 -#define OP_FOR 13 -#define OP_PUSH_VOID 14 -#define OP_PUSH_BOOL 15 -#define OP_PUSH_INT 16 -#define OP_PUSH_FLOAT 17 -#define OP_PUSH_IDENTIFIER 18 -#define OP_SEQUENCE 19 -#define OP_ASSIGN 20 -#define OP_ADDASSIGN 21 -#define OP_SUBASSIGN 22 -#define OP_MULASSIGN 23 -#define OP_DIVASSIGN 24 -/*#define OP_MODASSIGN 25*/ -/*#define OP_LSHASSIGN 26*/ -/*#define OP_RSHASSIGN 27*/ -/*#define OP_ORASSIGN 28*/ -/*#define OP_XORASSIGN 29*/ -/*#define OP_ANDASSIGN 30*/ -#define OP_SELECT 31 -#define OP_LOGICALOR 32 -#define OP_LOGICALXOR 33 -#define OP_LOGICALAND 34 -/*#define OP_BITOR 35*/ -/*#define OP_BITXOR 36*/ -/*#define OP_BITAND 37*/ -#define OP_EQUAL 38 -#define OP_NOTEQUAL 39 -#define OP_LESS 40 -#define OP_GREATER 41 -#define OP_LESSEQUAL 42 -#define OP_GREATEREQUAL 43 -/*#define OP_LSHIFT 44*/ -/*#define OP_RSHIFT 45*/ -#define OP_ADD 46 -#define OP_SUBTRACT 47 -#define OP_MULTIPLY 48 -#define OP_DIVIDE 49 -/*#define OP_MODULUS 50*/ -#define OP_PREINCREMENT 51 -#define OP_PREDECREMENT 52 -#define OP_PLUS 53 -#define OP_MINUS 54 -/*#define OP_COMPLEMENT 55*/ -#define OP_NOT 56 -#define OP_SUBSCRIPT 57 -#define OP_CALL 58 -#define OP_FIELD 59 -#define OP_POSTINCREMENT 60 -#define OP_POSTDECREMENT 61 -#define OP_PRECISION 62 -#define OP_METHOD 63 - -/* parameter qualifier */ -#define PARAM_QUALIFIER_IN 0 -#define PARAM_QUALIFIER_OUT 1 -#define PARAM_QUALIFIER_INOUT 2 -#define PARAM_QUALIFIER_NONE 3 - -/* function parameter */ -#define PARAMETER_NONE 0 -#define PARAMETER_NEXT 1 - -/* function parameter array presence */ -#define PARAMETER_ARRAY_NOT_PRESENT 0 -#define PARAMETER_ARRAY_PRESENT 1 - - -struct parse_dict { - int _void; - int _float; - int _int; - int _bool; - int vec2; - int vec3; - int vec4; - int bvec2; - int bvec3; - int bvec4; - int ivec2; - int ivec3; - int ivec4; - int mat2; - int mat3; - int mat4; - int mat2x3; - int mat3x2; - int mat2x4; - int mat4x2; - int mat3x4; - int mat4x3; - int sampler1D; - int sampler2D; - int sampler3D; - int samplerCube; - int sampler1DShadow; - int sampler2DShadow; - int sampler2DRect; - int sampler2DRectShadow; - int sampler1DArray; - int sampler2DArray; - int sampler1DArrayShadow; - int sampler2DArrayShadow; - - int invariant; - - int centroid; - - int precision; - int lowp; - int mediump; - int highp; - - int _const; - int attribute; - int varying; - int uniform; - int __fixed_output; - int __fixed_input; - - int in; - int out; - int inout; - - int layout; - int origin_upper_left; - int pixel_center_integer; - - int _struct; - - int __constructor; - int __operator; - int ___asm; - - int _if; - int _else; - int _for; - int _while; - int _do; - - int _continue; - int _break; - int _return; - int discard; - - int _false; - int _true; - - int all; - int _GL_ARB_fragment_coord_conventions; - int _GL_ARB_texture_rectangle; -}; - - -struct parse_context { - struct sl_pp_context *context; - - struct parse_dict dict; - - struct sl_pp_token_info *tokens; - unsigned int tokens_read; - unsigned int tokens_cap; - - unsigned char *out_buf; - unsigned int out_cap; - - unsigned int shader_type; - unsigned int parsing_builtin; - - unsigned int fragment_coord_conventions:1; - unsigned int texture_rectangle:1; - - char error[256]; - int process_error; -}; - - -struct parse_state { - unsigned int in; - unsigned int out; -}; - - -static unsigned int -_emit(struct parse_context *ctx, - unsigned int *out, - unsigned char b) -{ - if (*out == ctx->out_cap) { - ctx->out_cap += 4096; - ctx->out_buf = (unsigned char *)realloc(ctx->out_buf, ctx->out_cap * sizeof(unsigned char)); - } - ctx->out_buf[*out] = b; - return (*out)++; -} - - -static void -_update(struct parse_context *ctx, - unsigned int out, - unsigned char b) -{ - ctx->out_buf[out] = b; -} - - -static void -_error(struct parse_context *ctx, - const char *msg) -{ - if (ctx->error[0] == '\0') { - strncpy(ctx->error, msg, sizeof(ctx->error) - 1); - ctx->error[sizeof(ctx->error) - 1] = '\0'; - } -} - - -static const struct sl_pp_token_info * -_fetch_token(struct parse_context *ctx, - unsigned int pos) -{ - if (ctx->process_error) { - return NULL; - } - - while (pos >= ctx->tokens_read) { - if (ctx->tokens_read == ctx->tokens_cap) { - ctx->tokens_cap += 1024; - ctx->tokens = realloc(ctx->tokens, - ctx->tokens_cap * sizeof(struct sl_pp_token_info)); - if (!ctx->tokens) { - _error(ctx, "out of memory"); - ctx->process_error = 1; - return NULL; - } - } - if (sl_pp_process_get(ctx->context, &ctx->tokens[ctx->tokens_read])) { - _error(ctx, sl_pp_context_error_message(ctx->context)); - ctx->process_error = 1; - return NULL; - } - switch (ctx->tokens[ctx->tokens_read].token) { - case SL_PP_COMMA: - case SL_PP_SEMICOLON: - case SL_PP_LBRACE: - case SL_PP_RBRACE: - case SL_PP_LPAREN: - case SL_PP_RPAREN: - case SL_PP_LBRACKET: - case SL_PP_RBRACKET: - case SL_PP_DOT: - case SL_PP_INCREMENT: - case SL_PP_ADDASSIGN: - case SL_PP_PLUS: - case SL_PP_DECREMENT: - case SL_PP_SUBASSIGN: - case SL_PP_MINUS: - case SL_PP_BITNOT: - case SL_PP_NOTEQUAL: - case SL_PP_NOT: - case SL_PP_MULASSIGN: - case SL_PP_STAR: - case SL_PP_DIVASSIGN: - case SL_PP_SLASH: - case SL_PP_MODASSIGN: - case SL_PP_MODULO: - case SL_PP_LSHIFTASSIGN: - case SL_PP_LSHIFT: - case SL_PP_LESSEQUAL: - case SL_PP_LESS: - case SL_PP_RSHIFTASSIGN: - case SL_PP_RSHIFT: - case SL_PP_GREATEREQUAL: - case SL_PP_GREATER: - case SL_PP_EQUAL: - case SL_PP_ASSIGN: - case SL_PP_AND: - case SL_PP_BITANDASSIGN: - case SL_PP_BITAND: - case SL_PP_XOR: - case SL_PP_BITXORASSIGN: - case SL_PP_BITXOR: - case SL_PP_OR: - case SL_PP_BITORASSIGN: - case SL_PP_BITOR: - case SL_PP_QUESTION: - case SL_PP_COLON: - case SL_PP_IDENTIFIER: - case SL_PP_UINT: - case SL_PP_FLOAT: - case SL_PP_EXTENSION_REQUIRE: - case SL_PP_EXTENSION_ENABLE: - case SL_PP_EXTENSION_WARN: - case SL_PP_EXTENSION_DISABLE: - case SL_PP_EOF: - ctx->tokens_read++; - break; - default: - ; /* no-op */ - } - } - return &ctx->tokens[pos]; -} - - -/** - * Try to parse/match a particular token. - * \return 0 for success, -1 for error. - */ -static int -_parse_token(struct parse_context *ctx, - enum sl_pp_token token, - struct parse_state *ps) -{ - const struct sl_pp_token_info *input = _fetch_token(ctx, ps->in); - - if (input && input->token == token) { - ps->in++; - return 0; - } - return -1; -} - - -/** - * Try to parse an identifer. - * \return 0 for success, -1 for error - */ -static int -_parse_id(struct parse_context *ctx, - int id, - struct parse_state *ps) -{ - const struct sl_pp_token_info *input = _fetch_token(ctx, ps->in); - - if (input && input->token == SL_PP_IDENTIFIER && input->data.identifier == id) { - ps->in++; - return 0; - } - return -1; -} - - -static int -_parse_identifier(struct parse_context *ctx, - struct parse_state *ps) -{ - const struct sl_pp_token_info *input = _fetch_token(ctx, ps->in); - - if (input && input->token == SL_PP_IDENTIFIER) { - const char *cstr = sl_pp_context_cstr(ctx->context, input->data.identifier); - - do { - _emit(ctx, &ps->out, *cstr); - } while (*cstr++); - ps->in++; - return 0; - } - return -1; -} - - -static int -_parse_float(struct parse_context *ctx, - struct parse_state *ps) -{ - const struct sl_pp_token_info *input = _fetch_token(ctx, ps->in); - - if (input && input->token == SL_PP_FLOAT) { - const char *cstr = sl_pp_context_cstr(ctx->context, input->data._float); - - _emit(ctx, &ps->out, 1); - do { - _emit(ctx, &ps->out, *cstr); - } while (*cstr++); - ps->in++; - return 0; - } - return -1; -} - - -static int -_parse_uint(struct parse_context *ctx, - struct parse_state *ps) -{ - const struct sl_pp_token_info *input = _fetch_token(ctx, ps->in); - - if (input && input->token == SL_PP_UINT) { - const char *cstr = sl_pp_context_cstr(ctx->context, input->data._uint); - - _emit(ctx, &ps->out, 1); - do { - _emit(ctx, &ps->out, *cstr); - } while (*cstr++); - ps->in++; - return 0; - } - return -1; -} - - -/**************************************/ - - -static int -_parse_unary_expression(struct parse_context *ctx, - struct parse_state *ps); - -static int -_parse_conditional_expression(struct parse_context *ctx, - struct parse_state *ps); - - -static int -_parse_constant_expression(struct parse_context *ctx, - struct parse_state *ps); - - -static int -_parse_primary_expression(struct parse_context *ctx, - struct parse_state *ps); - - -static int -_parse_statement(struct parse_context *ctx, - struct parse_state *ps); - - -static int -_parse_type_specifier(struct parse_context *ctx, - struct parse_state *ps); - - -static int -_parse_declaration(struct parse_context *ctx, - struct parse_state *ps); - - -static int -_parse_statement_list(struct parse_context *ctx, - struct parse_state *ps); - - -static int -_parse_assignment_expression(struct parse_context *ctx, - struct parse_state *ps); - - -static int -_parse_precision(struct parse_context *ctx, - struct parse_state *ps); - - -static int -_parse_overriden_operator(struct parse_context *ctx, - struct parse_state *ps) -{ - unsigned int op; - - if (_parse_token(ctx, SL_PP_INCREMENT, ps) == 0) { - op = OPERATOR_INCREMENT; - } else if (_parse_token(ctx, SL_PP_ADDASSIGN, ps) == 0) { - op = OPERATOR_ADDASSIGN; - } else if (_parse_token(ctx, SL_PP_PLUS, ps) == 0) { - op = OPERATOR_PLUS; - } else if (_parse_token(ctx, SL_PP_DECREMENT, ps) == 0) { - op = OPERATOR_DECREMENT; - } else if (_parse_token(ctx, SL_PP_SUBASSIGN, ps) == 0) { - op = OPERATOR_SUBASSIGN; - } else if (_parse_token(ctx, SL_PP_MINUS, ps) == 0) { - op = OPERATOR_MINUS; - } else if (_parse_token(ctx, SL_PP_NOT, ps) == 0) { - op = OPERATOR_NOT; - } else if (_parse_token(ctx, SL_PP_MULASSIGN, ps) == 0) { - op = OPERATOR_MULASSIGN; - } else if (_parse_token(ctx, SL_PP_STAR, ps) == 0) { - op = OPERATOR_MULTIPLY; - } else if (_parse_token(ctx, SL_PP_DIVASSIGN, ps) == 0) { - op = OPERATOR_DIVASSIGN; - } else if (_parse_token(ctx, SL_PP_SLASH, ps) == 0) { - op = OPERATOR_DIVIDE; - } else if (_parse_token(ctx, SL_PP_LESSEQUAL, ps) == 0) { - op = OPERATOR_LESSEQUAL; - } else if (_parse_token(ctx, SL_PP_LESS, ps) == 0) { - op = OPERATOR_LESS; - } else if (_parse_token(ctx, SL_PP_GREATEREQUAL, ps) == 0) { - op = OPERATOR_GREATEREQUAL; - } else if (_parse_token(ctx, SL_PP_GREATER, ps) == 0) { - op = OPERATOR_GREATER; - } else if (_parse_token(ctx, SL_PP_XOR, ps) == 0) { - op = OPERATOR_LOGICALXOR; - } else { - return -1; - } - - _emit(ctx, &ps->out, op); - return 0; -} - - -static int -_parse_function_decl_identifier(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e = _emit(ctx, &p.out, 0); - - if (ctx->parsing_builtin && _parse_id(ctx, ctx->dict.__constructor, &p) == 0) { - _update(ctx, e, FUNCTION_CONSTRUCTOR); - *ps = p; - return 0; - } - - if (ctx->parsing_builtin && _parse_id(ctx, ctx->dict.__operator, &p) == 0) { - _update(ctx, e, FUNCTION_OPERATOR); - if (_parse_overriden_operator(ctx, &p) == 0) { - *ps = p; - return 0; - } - return -1; - } - - if (_parse_identifier(ctx, &p) == 0) { - _update(ctx, e, FUNCTION_ORDINARY); - *ps = p; - return 0; - } - - return -1; -} - - -static int -_parse_invariant_qualifier(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_id(ctx, ctx->dict.invariant, ps)) { - return -1; - } - _emit(ctx, &ps->out, TYPE_INVARIANT); - return 0; -} - - -static int -_parse_centroid_qualifier(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_id(ctx, ctx->dict.centroid, ps)) { - return -1; - } - _emit(ctx, &ps->out, TYPE_CENTROID); - return 0; -} - - -static int -_parse_layout_qualifier(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_id(ctx, ctx->dict.layout, ps) == 0) { - if (!ctx->fragment_coord_conventions) { - _error(ctx, "GL_ARB_fragment_coord_conventions extension must be enabled " - "in order to use a layout qualifier"); - return -1; - } - - /* Layout qualifiers are only defined for fragment shaders, - * so do an early check. - */ - if (ctx->shader_type != 1) { - _error(ctx, "layout qualifiers are only valid for fragment shaders"); - return -1; - } - - /* start of a parenthesised list of layout qualifiers */ - - if (_parse_token(ctx, SL_PP_LPAREN, ps)) { - _error(ctx, "expected `('"); - return -1; - } - - /* parse comma-separated ID list */ - while (1) { - if (_parse_id(ctx, ctx->dict.origin_upper_left, ps) == 0) { - _emit(ctx, &ps->out, LAYOUT_QUALIFIER_UPPER_LEFT); - } - else if (_parse_id(ctx, ctx->dict.pixel_center_integer, ps) == 0) { - _emit(ctx, &ps->out, LAYOUT_QUALIFIER_PIXEL_CENTER_INTEGER); - } - else { - _error(ctx, "expected a layout qualifier name"); - return -1; - } - - if (_parse_token(ctx, SL_PP_RPAREN, ps) == 0) { - /* all done */ - break; - } - else if (_parse_token(ctx, SL_PP_COMMA, ps) == 0) { - /* another layout qualifier is coming */ - } - else { - _error(ctx, "expected `,' or `)'"); - return -1; - } - } - } - - return 0; -} - - -static int -_parse_storage_qualifier(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - const struct sl_pp_token_info *input = _fetch_token(ctx, p.in); - unsigned int e = _emit(ctx, &p.out, 0); - int id; - - if (!input || input->token != SL_PP_IDENTIFIER) { - return -1; - } - id = input->data.identifier; - - if (id == ctx->dict._const) { - _update(ctx, e, TYPE_QUALIFIER_CONST); - } else if (ctx->shader_type == 2 && id == ctx->dict.attribute) { - _update(ctx, e, TYPE_QUALIFIER_ATTRIBUTE); - } else if (id == ctx->dict.varying) { - _update(ctx, e, TYPE_QUALIFIER_VARYING); - } else if (id == ctx->dict.uniform) { - _update(ctx, e, TYPE_QUALIFIER_UNIFORM); - } else if (ctx->parsing_builtin && id == ctx->dict.__fixed_output) { - _update(ctx, e, TYPE_QUALIFIER_FIXEDOUTPUT); - } else if (ctx->parsing_builtin && id == ctx->dict.__fixed_input) { - _update(ctx, e, TYPE_QUALIFIER_FIXEDINPUT); - } else { - return -1; - } - _parse_token(ctx, SL_PP_IDENTIFIER, &p); - *ps = p; - return 0; -} - -static int -_parse_struct_declarator(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e; - - if (_parse_identifier(ctx, &p)) { - return -1; - } - e = _emit(ctx, &p.out, FIELD_NONE); - *ps = p; - - if (_parse_token(ctx, SL_PP_LBRACKET, &p)) { - return 0; - } - if (_parse_constant_expression(ctx, &p)) { - _error(ctx, "expected constant integral expression"); - return -1; - } - if (_parse_token(ctx, SL_PP_RBRACKET, &p)) { - _error(ctx, "expected `]'"); - return -1; - } - _update(ctx, e, FIELD_ARRAY); - *ps = p; - return 0; -} - - -static int -_parse_struct_declarator_list(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_struct_declarator(ctx, &p)) { - return -1; - } - - for (;;) { - *ps = p; - _emit(ctx, &p.out, FIELD_NEXT); - if (_parse_token(ctx, SL_PP_COMMA, &p)) { - return 0; - } - if (_parse_struct_declarator(ctx, &p)) { - return 0; - } - } -} - - -static int -_parse_struct_declaration(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_type_specifier(ctx, &p)) { - return -1; - } - if (_parse_struct_declarator_list(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) { - return -1; - } - _emit(ctx, &p.out, FIELD_NONE); - *ps = p; - return 0; -} - - -static int -_parse_struct_declaration_list(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_struct_declaration(ctx, &p)) { - return -1; - } - - for (;;) { - *ps = p; - _emit(ctx, &p.out, FIELD_NEXT); - if (_parse_struct_declaration(ctx, &p)) { - return 0; - } - } -} - - -static int -_parse_struct_specifier(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_id(ctx, ctx->dict._struct, &p)) { - return -1; - } - if (_parse_identifier(ctx, &p)) { - _emit(ctx, &p.out, '\0'); - } - if (_parse_token(ctx, SL_PP_LBRACE, &p)) { - _error(ctx, "expected `{'"); - return -1; - } - if (_parse_struct_declaration_list(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_RBRACE, &p)) { - return -1; - } - _emit(ctx, &p.out, FIELD_NONE); - *ps = p; - return 0; -} - - -static int -_parse_type_specifier_nonarray(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e = _emit(ctx, &p.out, 0); - const struct sl_pp_token_info *input; - int id; - - if (_parse_struct_specifier(ctx, &p) == 0) { - _update(ctx, e, TYPE_SPECIFIER_STRUCT); - *ps = p; - return 0; - } - - input = _fetch_token(ctx, p.in); - if (!input || input->token != SL_PP_IDENTIFIER) { - return -1; - } - id = input->data.identifier; - - if (id == ctx->dict._void) { - _update(ctx, e, TYPE_SPECIFIER_VOID); - } else if (id == ctx->dict._float) { - _update(ctx, e, TYPE_SPECIFIER_FLOAT); - } else if (id == ctx->dict._int) { - _update(ctx, e, TYPE_SPECIFIER_INT); - } else if (id == ctx->dict._bool) { - _update(ctx, e, TYPE_SPECIFIER_BOOL); - } else if (id == ctx->dict.vec2) { - _update(ctx, e, TYPE_SPECIFIER_VEC2); - } else if (id == ctx->dict.vec3) { - _update(ctx, e, TYPE_SPECIFIER_VEC3); - } else if (id == ctx->dict.vec4) { - _update(ctx, e, TYPE_SPECIFIER_VEC4); - } else if (id == ctx->dict.bvec2) { - _update(ctx, e, TYPE_SPECIFIER_BVEC2); - } else if (id == ctx->dict.bvec3) { - _update(ctx, e, TYPE_SPECIFIER_BVEC3); - } else if (id == ctx->dict.bvec4) { - _update(ctx, e, TYPE_SPECIFIER_BVEC4); - } else if (id == ctx->dict.ivec2) { - _update(ctx, e, TYPE_SPECIFIER_IVEC2); - } else if (id == ctx->dict.ivec3) { - _update(ctx, e, TYPE_SPECIFIER_IVEC3); - } else if (id == ctx->dict.ivec4) { - _update(ctx, e, TYPE_SPECIFIER_IVEC4); - } else if (id == ctx->dict.mat2) { - _update(ctx, e, TYPE_SPECIFIER_MAT2); - } else if (id == ctx->dict.mat3) { - _update(ctx, e, TYPE_SPECIFIER_MAT3); - } else if (id == ctx->dict.mat4) { - _update(ctx, e, TYPE_SPECIFIER_MAT4); - } else if (id == ctx->dict.mat2x3) { - _update(ctx, e, TYPE_SPECIFIER_MAT23); - } else if (id == ctx->dict.mat3x2) { - _update(ctx, e, TYPE_SPECIFIER_MAT32); - } else if (id == ctx->dict.mat2x4) { - _update(ctx, e, TYPE_SPECIFIER_MAT24); - } else if (id == ctx->dict.mat4x2) { - _update(ctx, e, TYPE_SPECIFIER_MAT42); - } else if (id == ctx->dict.mat3x4) { - _update(ctx, e, TYPE_SPECIFIER_MAT34); - } else if (id == ctx->dict.mat4x3) { - _update(ctx, e, TYPE_SPECIFIER_MAT43); - } else if (id == ctx->dict.sampler1D) { - _update(ctx, e, TYPE_SPECIFIER_SAMPLER1D); - } else if (id == ctx->dict.sampler2D) { - _update(ctx, e, TYPE_SPECIFIER_SAMPLER2D); - } else if (id == ctx->dict.sampler3D) { - _update(ctx, e, TYPE_SPECIFIER_SAMPLER3D); - } else if (id == ctx->dict.samplerCube) { - _update(ctx, e, TYPE_SPECIFIER_SAMPLERCUBE); - } else if (id == ctx->dict.sampler1DShadow) { - _update(ctx, e, TYPE_SPECIFIER_SAMPLER1DSHADOW); - } else if (id == ctx->dict.sampler2DShadow) { - _update(ctx, e, TYPE_SPECIFIER_SAMPLER2DSHADOW); - } else if (id == ctx->dict.sampler2DRect) { - if (!ctx->texture_rectangle) { - _error(ctx, "GL_ARB_texture_rectangle extension must be enabled " - "in order to use a rect sampler"); - return -1; - } - _update(ctx, e, TYPE_SPECIFIER_SAMPLER2DRECT); - } else if (id == ctx->dict.sampler2DRectShadow) { - if (!ctx->texture_rectangle) { - _error(ctx, "GL_ARB_texture_rectangle extension must be enabled " - "in order to use a rect sampler"); - return -1; - } - _update(ctx, e, TYPE_SPECIFIER_SAMPLER2DRECTSHADOW); - } else if (id == ctx->dict.sampler1DArray) { - _update(ctx, e, TYPE_SPECIFIER_SAMPLER_1D_ARRAY); - } else if (id == ctx->dict.sampler2DArray) { - /* XXX check for GL_EXT_texture_array */ - _update(ctx, e, TYPE_SPECIFIER_SAMPLER_2D_ARRAY); - } else if (id == ctx->dict.sampler1DArrayShadow) { - _update(ctx, e, TYPE_SPECIFIER_SAMPLER_1D_ARRAY_SHADOW); - } else if (id == ctx->dict.sampler2DArrayShadow) { - _update(ctx, e, TYPE_SPECIFIER_SAMPLER_2D_ARRAY_SHADOW); - } else if (_parse_identifier(ctx, &p) == 0) { - _update(ctx, e, TYPE_SPECIFIER_TYPENAME); - *ps = p; - return 0; - } else { - return -1; - } - - _parse_token(ctx, SL_PP_IDENTIFIER, &p); - *ps = p; - return 0; -} - - -static int -_parse_type_specifier_array(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_token(ctx, SL_PP_LBRACKET, &p)) { - return -1; - } - if (_parse_constant_expression(ctx, &p)) { - _error(ctx, "expected constant integral expression"); - return -1; - } - if (_parse_token(ctx, SL_PP_RBRACKET, &p)) { - _error(ctx, "expected `]'"); - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_type_specifier(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e; - - if (_parse_type_specifier_nonarray(ctx, &p)) { - return -1; - } - - e = _emit(ctx, &p.out, TYPE_SPECIFIER_ARRAY); - if (_parse_type_specifier_array(ctx, &p)) { - _update(ctx, e, TYPE_SPECIFIER_NONARRAY); - } - *ps = p; - return 0; -} - -static int -_parse_parameter_qualifier(struct parse_context *ctx, - struct parse_state *ps) -{ - unsigned int e = _emit(ctx, &ps->out, PARAM_QUALIFIER_NONE); - - if (_parse_id(ctx, ctx->dict.in, ps) == 0) { - _update(ctx, e, PARAM_QUALIFIER_IN); - } else if (_parse_id(ctx, ctx->dict.out, ps) == 0) { - _update(ctx, e, PARAM_QUALIFIER_OUT); - } else if (_parse_id(ctx, ctx->dict.inout, ps) == 0) { - _update(ctx, e, PARAM_QUALIFIER_INOUT); - } - return 0; -} - -static int -_parse_fully_specified_type(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_layout_qualifier(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, LAYOUT_QUALIFIER_NONE); - - if (_parse_invariant_qualifier(ctx, &p)) { - _emit(ctx, &p.out, TYPE_VARIANT); - } - - if (_parse_centroid_qualifier(ctx, &p)) { - _emit(ctx, &p.out, TYPE_CENTER); - } - if (_parse_storage_qualifier(ctx, &p)) { - _emit(ctx, &p.out, TYPE_QUALIFIER_NONE); - } - _parse_parameter_qualifier(ctx, &p); - if (_parse_precision(ctx, &p)) { - _emit(ctx, &p.out, PRECISION_DEFAULT); - } - if (_parse_type_specifier(ctx, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_function_header(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_fully_specified_type(ctx, &p)) { - return -1; - } - if (_parse_function_decl_identifier(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_LPAREN, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_function_identifier(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p; - unsigned int e; - - if (_parse_identifier(ctx, ps)) { - return -1; - } - e = _emit(ctx, &ps->out, FUNCTION_CALL_NONARRAY); - - p = *ps; - if (_parse_token(ctx, SL_PP_LBRACKET, &p)) { - return 0; - } - if (_parse_constant_expression(ctx, &p)) { - _error(ctx, "expected constant integral expression"); - return -1; - } - if (_parse_token(ctx, SL_PP_RBRACKET, &p)) { - _error(ctx, "expected `]'"); - return -1; - } - _update(ctx, e, FUNCTION_CALL_ARRAY); - *ps = p; - return 0; -} - - -static int -_parse_function_call_header(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_function_identifier(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_LPAREN, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_assign_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int op; - - if (_parse_unary_expression(ctx, &p)) { - return -1; - } - - if (_parse_token(ctx, SL_PP_ASSIGN, &p) == 0) { - op = OP_ASSIGN; - } else if (_parse_token(ctx, SL_PP_MULASSIGN, &p) == 0) { - op = OP_MULASSIGN; - } else if (_parse_token(ctx, SL_PP_DIVASSIGN, &p) == 0) { - op = OP_DIVASSIGN; - } else if (_parse_token(ctx, SL_PP_ADDASSIGN, &p) == 0) { - op = OP_ADDASSIGN; - } else if (_parse_token(ctx, SL_PP_SUBASSIGN, &p) == 0) { - op = OP_SUBASSIGN; - } else { - return -1; - } - - if (_parse_assignment_expression(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, op); - - *ps = p; - return 0; -} - - -static int -_parse_assignment_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_assign_expression(ctx, ps) == 0) { - return 0; - } - - if (_parse_conditional_expression(ctx, ps) == 0) { - return 0; - } - - return -1; -} - - -static int -_parse_function_call_header_with_parameters(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_function_call_header(ctx, &p)) { - return -1; - } - if (_parse_assignment_expression(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_END); - for (;;) { - *ps = p; - if (_parse_token(ctx, SL_PP_COMMA, &p)) { - return 0; - } - if (_parse_assignment_expression(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, OP_END); - } -} - - -static int -_parse_function_call_header_no_parameters(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_function_call_header(ctx, ps)) { - return -1; - } - _parse_id(ctx, ctx->dict._void, ps); - return 0; -} - - -static int -_parse_function_call_generic(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_function_call_header_with_parameters(ctx, &p) == 0) { - if (_parse_token(ctx, SL_PP_RPAREN, &p) == 0) { - *ps = p; - return 0; - } - _error(ctx, "expected `)'"); - return -1; - } - - p = *ps; - if (_parse_function_call_header_no_parameters(ctx, &p) == 0) { - if (_parse_token(ctx, SL_PP_RPAREN, &p) == 0) { - *ps = p; - return 0; - } - _error(ctx, "expected `)'"); - return -1; - } - - return -1; -} - - -static int -_parse_method_call(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - _emit(ctx, &p.out, OP_METHOD); - if (_parse_identifier(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_DOT, &p)) { - return -1; - } - if (_parse_function_call_generic(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_END); - *ps = p; - return 0; -} - - -static int -_parse_regular_function_call(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - _emit(ctx, &p.out, OP_CALL); - if (_parse_function_call_generic(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_END); - *ps = p; - return 0; -} - - -static int -_parse_function_call(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_regular_function_call(ctx, ps) == 0) { - return 0; - } - - if (_parse_method_call(ctx, ps) == 0) { - return 0; - } - - return -1; -} - - -static int -_parse_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_assignment_expression(ctx, &p)) { - return -1; - } - - for (;;) { - *ps = p; - if (_parse_token(ctx, SL_PP_COMMA, &p)) { - return 0; - } - if (_parse_assignment_expression(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, OP_SEQUENCE); - } -} - - -static int -_parse_postfix_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p; - - if (_parse_function_call(ctx, ps)) { - if (_parse_primary_expression(ctx, ps)) { - return -1; - } - } - - for (p = *ps;;) { - *ps = p; - if (_parse_token(ctx, SL_PP_INCREMENT, &p) == 0) { - _emit(ctx, &p.out, OP_POSTINCREMENT); - } else if (_parse_token(ctx, SL_PP_DECREMENT, &p) == 0) { - _emit(ctx, &p.out, OP_POSTDECREMENT); - } else if (_parse_token(ctx, SL_PP_LBRACKET, &p) == 0) { - if (_parse_expression(ctx, &p)) { - _error(ctx, "expected an integral expression"); - return -1; - } - if (_parse_token(ctx, SL_PP_RBRACKET, &p)) { - _error(ctx, "expected `]'"); - return -1; - } - _emit(ctx, &p.out, OP_SUBSCRIPT); - } else if (_parse_token(ctx, SL_PP_DOT, &p) == 0) { - _emit(ctx, &p.out, OP_FIELD); - if (_parse_identifier(ctx, &p)) { - return 0; - } - } else { - return 0; - } - } -} - - -static int -_parse_unary_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p; - unsigned int op; - - if (_parse_postfix_expression(ctx, ps) == 0) { - return 0; - } - - p = *ps; - if (_parse_token(ctx, SL_PP_INCREMENT, &p) == 0) { - op = OP_PREINCREMENT; - } else if (_parse_token(ctx, SL_PP_DECREMENT, &p) == 0) { - op = OP_PREDECREMENT; - } else if (_parse_token(ctx, SL_PP_PLUS, &p) == 0) { - op = OP_PLUS; - } else if (_parse_token(ctx, SL_PP_MINUS, &p) == 0) { - op = OP_MINUS; - } else if (_parse_token(ctx, SL_PP_NOT, &p) == 0) { - op = OP_NOT; - } else { - return -1; - } - - if (_parse_unary_expression(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, op); - *ps = p; - return 0; -} - - -static int -_parse_multiplicative_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_unary_expression(ctx, &p)) { - return -1; - } - for (;;) { - unsigned int op; - - *ps = p; - if (_parse_token(ctx, SL_PP_STAR, &p) == 0) { - op = OP_MULTIPLY; - } else if (_parse_token(ctx, SL_PP_SLASH, &p) == 0) { - op = OP_DIVIDE; - } else { - return 0; - } - if (_parse_unary_expression(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, op); - } -} - - -static int -_parse_additive_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_multiplicative_expression(ctx, &p)) { - return -1; - } - for (;;) { - unsigned int op; - - *ps = p; - if (_parse_token(ctx, SL_PP_PLUS, &p) == 0) { - op = OP_ADD; - } else if (_parse_token(ctx, SL_PP_MINUS, &p) == 0) { - op = OP_SUBTRACT; - } else { - return 0; - } - if (_parse_multiplicative_expression(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, op); - } -} - - -static int -_parse_relational_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_additive_expression(ctx, &p)) { - return -1; - } - for (;;) { - unsigned int op; - - *ps = p; - if (_parse_token(ctx, SL_PP_LESS, &p) == 0) { - op = OP_LESS; - } else if (_parse_token(ctx, SL_PP_GREATER, &p) == 0) { - op = OP_GREATER; - } else if (_parse_token(ctx, SL_PP_LESSEQUAL, &p) == 0) { - op = OP_LESSEQUAL; - } else if (_parse_token(ctx, SL_PP_GREATEREQUAL, &p) == 0) { - op = OP_GREATEREQUAL; - } else { - return 0; - } - if (_parse_additive_expression(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, op); - } -} - - -static int -_parse_equality_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_relational_expression(ctx, &p)) { - return -1; - } - for (;;) { - unsigned int op; - - *ps = p; - if (_parse_token(ctx, SL_PP_EQUAL, &p) == 0) { - op = OP_EQUAL; - } else if (_parse_token(ctx, SL_PP_NOTEQUAL, &p) == 0) { - op = OP_NOTEQUAL; - } else { - return 0; - } - if (_parse_relational_expression(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, op); - } -} - - -static int -_parse_logical_and_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_equality_expression(ctx, &p)) { - return -1; - } - for (;;) { - *ps = p; - if (_parse_token(ctx, SL_PP_AND, &p)) { - return 0; - } - if (_parse_equality_expression(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, OP_LOGICALAND); - } -} - - -static int -_parse_logical_xor_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_logical_and_expression(ctx, &p)) { - return -1; - } - for (;;) { - *ps = p; - if (_parse_token(ctx, SL_PP_XOR, &p)) { - return 0; - } - if (_parse_logical_and_expression(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, OP_LOGICALXOR); - } -} - - -static int -_parse_logical_or_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_logical_xor_expression(ctx, &p)) { - return -1; - } - for (;;) { - *ps = p; - if (_parse_token(ctx, SL_PP_OR, &p)) { - return 0; - } - if (_parse_logical_xor_expression(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, OP_LOGICALOR); - } -} - - -static int -_parse_conditional_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_logical_or_expression(ctx, &p)) { - return -1; - } - for (;;) { - *ps = p; - if (_parse_token(ctx, SL_PP_QUESTION, &p)) { - return 0; - } - if (_parse_expression(ctx, &p)) { - return 0; - } - if (_parse_token(ctx, SL_PP_COLON, &p)) { - return 0; - } - if (_parse_conditional_expression(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, OP_SELECT); - } -} - - -static int -_parse_constant_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_conditional_expression(ctx, ps)) { - return -1; - } - _emit(ctx, &ps->out, OP_END); - return 0; -} - - -static int -_parse_parameter_declarator_array(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_token(ctx, SL_PP_LBRACKET, &p)) { - return -1; - } - if (_parse_constant_expression(ctx, &p)) { - _error(ctx, "expected constant integral expression"); - return -1; - } - if (_parse_token(ctx, SL_PP_RBRACKET, &p)) { - _error(ctx, "expected `]'"); - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_parameter_declarator(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e; - - if (_parse_type_specifier(ctx, &p)) { - return -1; - } - if (_parse_identifier(ctx, &p)) { - return -1; - } - e = _emit(ctx, &p.out, PARAMETER_ARRAY_PRESENT); - if (_parse_parameter_declarator_array(ctx, &p)) { - _update(ctx, e, PARAMETER_ARRAY_NOT_PRESENT); - } - *ps = p; - return 0; -} - - -static int -_parse_parameter_type_specifier_array(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_token(ctx, SL_PP_LBRACKET, &p)) { - return -1; - } - if (_parse_constant_expression(ctx, &p)) { - _error(ctx, "expected constant integral expression"); - return -1; - } - if (_parse_token(ctx, SL_PP_RBRACKET, &p)) { - _error(ctx, "expected `]'"); - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_parameter_type_specifier(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e; - - if (_parse_type_specifier(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, '\0'); - - e = _emit(ctx, &p.out, PARAMETER_ARRAY_PRESENT); - if (_parse_parameter_type_specifier_array(ctx, &p)) { - _update(ctx, e, PARAMETER_ARRAY_NOT_PRESENT); - } - *ps = p; - return 0; -} - - -static int -_parse_parameter_declaration(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e = _emit(ctx, &p.out, PARAMETER_NEXT); - - (void) e; - - if (_parse_storage_qualifier(ctx, &p)) { - _emit(ctx, &p.out, TYPE_QUALIFIER_NONE); - } - _parse_parameter_qualifier(ctx, &p); - if (_parse_precision(ctx, &p)) { - _emit(ctx, &p.out, PRECISION_DEFAULT); - } - if (_parse_parameter_declarator(ctx, &p) == 0) { - *ps = p; - return 0; - } - if (_parse_parameter_type_specifier(ctx, &p) == 0) { - *ps = p; - return 0; - } - - return -1; -} - - -static int -_parse_function_header_with_parameters(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_function_header(ctx, &p)) { - return -1; - } - if (_parse_parameter_declaration(ctx, &p)) { - return -1; - } - - for (;;) { - *ps = p; - if (_parse_token(ctx, SL_PP_COMMA, &p)) { - return 0; - } - if (_parse_parameter_declaration(ctx, &p)) { - return 0; - } - } -} - - -static int -_parse_function_declarator(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_function_header_with_parameters(ctx, ps) == 0) { - return 0; - } - - if (_parse_function_header(ctx, ps) == 0) { - return 0; - } - - return -1; -} - - -static int -_parse_function_prototype(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_function_header(ctx, &p) == 0) { - if (_parse_id(ctx, ctx->dict._void, &p) == 0) { - if (_parse_token(ctx, SL_PP_RPAREN, &p) == 0) { - _emit(ctx, &p.out, PARAMETER_NONE); - *ps = p; - return 0; - } - _error(ctx, "expected `)'"); - return -1; - } - } - - p = *ps; - if (_parse_function_declarator(ctx, &p) == 0) { - if (_parse_token(ctx, SL_PP_RPAREN, &p) == 0) { - _emit(ctx, &p.out, PARAMETER_NONE); - *ps = p; - return 0; - } - _error(ctx, "expected `)'"); - return -1; - } - - return -1; -} - - -static int -_parse_precision(struct parse_context *ctx, - struct parse_state *ps) -{ - const struct sl_pp_token_info *input = _fetch_token(ctx, ps->in); - int id; - unsigned int precision; - - if (!input || input->token != SL_PP_IDENTIFIER) { - return -1; - } - id = input->data.identifier; - - if (id == ctx->dict.lowp) { - precision = PRECISION_LOW; - } else if (id == ctx->dict.mediump) { - precision = PRECISION_MEDIUM; - } else if (id == ctx->dict.highp) { - precision = PRECISION_HIGH; - } else { - return -1; - } - - _parse_token(ctx, SL_PP_IDENTIFIER, ps); - _emit(ctx, &ps->out, precision); - return 0; -} - - -static int -_parse_prectype(struct parse_context *ctx, - struct parse_state *ps) -{ - const struct sl_pp_token_info *input = _fetch_token(ctx, ps->in); - int id; - unsigned int type; - - if (!input || input->token != SL_PP_IDENTIFIER) { - return -1; - } - id = input->data.identifier; - - if (id == ctx->dict._int) { - type = TYPE_SPECIFIER_INT; - } else if (id == ctx->dict._float) { - type = TYPE_SPECIFIER_FLOAT; - } else if (id == ctx->dict.sampler1D) { - type = TYPE_SPECIFIER_SAMPLER1D; - } else if (id == ctx->dict.sampler2D) { - type = TYPE_SPECIFIER_SAMPLER2D; - } else if (id == ctx->dict.sampler3D) { - type = TYPE_SPECIFIER_SAMPLER3D; - } else if (id == ctx->dict.samplerCube) { - type = TYPE_SPECIFIER_SAMPLERCUBE; - } else if (id == ctx->dict.sampler1DShadow) { - type = TYPE_SPECIFIER_SAMPLER1DSHADOW; - } else if (id == ctx->dict.sampler2DShadow) { - type = TYPE_SPECIFIER_SAMPLER2DSHADOW; - } else if (id == ctx->dict.sampler2DRect) { - if (!ctx->texture_rectangle) { - _error(ctx, "GL_ARB_texture_rectangle extension must be enabled " - "in order to use a rect sampler"); - return -1; - } - type = TYPE_SPECIFIER_SAMPLER2DRECT; - } else if (id == ctx->dict.sampler2DRectShadow) { - if (!ctx->texture_rectangle) { - _error(ctx, "GL_ARB_texture_rectangle extension must be enabled " - "in order to use a rect sampler"); - return -1; - } - type = TYPE_SPECIFIER_SAMPLER2DRECTSHADOW; - } else if (id == ctx->dict.sampler1DArray) { - type = TYPE_SPECIFIER_SAMPLER_1D_ARRAY; - } else if (id == ctx->dict.sampler2DArray) { - type = TYPE_SPECIFIER_SAMPLER_2D_ARRAY; - } else if (id == ctx->dict.sampler1DArrayShadow) { - type = TYPE_SPECIFIER_SAMPLER_1D_ARRAY_SHADOW; - } else if (id == ctx->dict.sampler2DArrayShadow) { - type = TYPE_SPECIFIER_SAMPLER_2D_ARRAY_SHADOW; - } else { - return -1; - } - - _parse_token(ctx, SL_PP_IDENTIFIER, ps); - _emit(ctx, &ps->out, type); - return 0; -} - - -static int -_parse_precision_stmt(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_id(ctx, ctx->dict.precision, &p)) { - return -1; - } - if (_parse_precision(ctx, &p)) { - return -1; - } - if (_parse_prectype(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_floatconstant(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - _emit(ctx, &p.out, OP_PUSH_FLOAT); - if (_parse_float(ctx, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_intconstant(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - _emit(ctx, &p.out, OP_PUSH_INT); - if (_parse_uint(ctx, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_boolconstant(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_id(ctx, ctx->dict._false, ps) == 0) { - _emit(ctx, &ps->out, OP_PUSH_BOOL); - _emit(ctx, &ps->out, 2); /* radix */ - _emit(ctx, &ps->out, '0'); - _emit(ctx, &ps->out, '\0'); - return 0; - } - - if (_parse_id(ctx, ctx->dict._true, ps) == 0) { - _emit(ctx, &ps->out, OP_PUSH_BOOL); - _emit(ctx, &ps->out, 2); /* radix */ - _emit(ctx, &ps->out, '1'); - _emit(ctx, &ps->out, '\0'); - return 0; - } - - return -1; -} - - -static int -_parse_variable_identifier(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - _emit(ctx, &p.out, OP_PUSH_IDENTIFIER); - if (_parse_identifier(ctx, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_primary_expression(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p; - - if (_parse_floatconstant(ctx, ps) == 0) { - return 0; - } - if (_parse_boolconstant(ctx, ps) == 0) { - return 0; - } - if (_parse_intconstant(ctx, ps) == 0) { - return 0; - } - if (_parse_variable_identifier(ctx, ps) == 0) { - return 0; - } - - p = *ps; - if (_parse_token(ctx, SL_PP_LPAREN, &p)) { - return -1; - } - if (_parse_expression(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_RPAREN, &p)) { - return -1; - } - - *ps = p; - return 0; -} - - -static int -_parse_asm_argument(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_variable_identifier(ctx, ps) == 0) { - struct parse_state p = *ps; - - if (_parse_token(ctx, SL_PP_DOT, &p)) { - return 0; - } - _emit(ctx, &p.out, OP_FIELD); - if (_parse_identifier(ctx, &p)) { - return 0; - } - *ps = p; - return 0; - } - - if (_parse_floatconstant(ctx, ps) == 0) { - return 0; - } - - return -1; -} - - -static int -_parse_asm_arguments(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_asm_argument(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_END); - - for (;;) { - *ps = p; - if (_parse_token(ctx, SL_PP_COMMA, &p)) { - return 0; - } - if (_parse_asm_argument(ctx, &p)) { - return 0; - } - _emit(ctx, &p.out, OP_END); - } -} - - -static int -_parse_asm_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_id(ctx, ctx->dict.___asm, &p)) { - return -1; - } - if (_parse_identifier(ctx, &p)) { - return -1; - } - /* optional arguments */ - _parse_asm_arguments(ctx, &p); - if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_END); - *ps = p; - return 0; -} - - -static int -_parse_selection_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - _emit(ctx, &p.out, OP_IF); - if (_parse_id(ctx, ctx->dict._if, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_LPAREN, &p)) { - _error(ctx, "expected `('"); - return -1; - } - if (_parse_expression(ctx, &p)) { - _error(ctx, "expected an expression"); - return -1; - } - if (_parse_token(ctx, SL_PP_RPAREN, &p)) { - _error(ctx, "expected `)'"); - return -1; - } - _emit(ctx, &p.out, OP_END); - if (_parse_statement(ctx, &p)) { - return -1; - } - - *ps = p; - if (_parse_id(ctx, ctx->dict._else, &p) == 0) { - if (_parse_statement(ctx, &p) == 0) { - *ps = p; - return 0; - } - } - - _emit(ctx, &ps->out, OP_EXPRESSION); - _emit(ctx, &ps->out, OP_PUSH_VOID); - _emit(ctx, &ps->out, OP_END); - return 0; -} - - -static int -_parse_expression_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_expression(ctx, &p)) { - _emit(ctx, &p.out, OP_PUSH_VOID); - } - if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_END); - *ps = p; - return 0; -} - - -static int -_parse_for_init_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e = _emit(ctx, &p.out, OP_EXPRESSION); - - if (_parse_expression_statement(ctx, &p) == 0) { - *ps = p; - return 0; - } - - if (_parse_declaration(ctx, &p) == 0) { - _update(ctx, e, OP_DECLARE); - *ps = p; - return 0; - } - - return -1; -} - - -static int -_parse_initializer(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_assignment_expression(ctx, ps) == 0) { - _emit(ctx, &ps->out, OP_END); - return 0; - } - return -1; -} - - -static int -_parse_condition_initializer(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - _emit(ctx, &p.out, OP_DECLARE); - _emit(ctx, &p.out, DECLARATION_INIT_DECLARATOR_LIST); - if (_parse_fully_specified_type(ctx, &p)) { - return -1; - } - _emit(ctx, &p.out, VARIABLE_IDENTIFIER); - if (_parse_identifier(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_ASSIGN, &p)) { - _error(ctx, "expected `='"); - return -1; - } - _emit(ctx, &p.out, VARIABLE_INITIALIZER); - if (_parse_initializer(ctx, &p)) { - _error(ctx, "expected an initialiser"); - return -1; - } - _emit(ctx, &p.out, DECLARATOR_NONE); - *ps = p; - return 0; -} - - -static int -_parse_condition(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p; - - if (_parse_condition_initializer(ctx, ps) == 0) { - return 0; - } - - p = *ps; - _emit(ctx, &p.out, OP_EXPRESSION); - if (_parse_expression(ctx, &p) == 0) { - _emit(ctx, &p.out, OP_END); - *ps = p; - return 0; - } - - return -1; -} - - -static int -_parse_for_rest_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_condition(ctx, &p)) { - _emit(ctx, &p.out, OP_EXPRESSION); - _emit(ctx, &p.out, OP_PUSH_BOOL); - _emit(ctx, &p.out, 2); - _emit(ctx, &p.out, '1'); - _emit(ctx, &p.out, '\0'); - _emit(ctx, &p.out, OP_END); - } - if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) { - return -1; - } - if (_parse_expression(ctx, &p)) { - _emit(ctx, &p.out, OP_PUSH_VOID); - } - _emit(ctx, &p.out, OP_END); - *ps = p; - return 0; -} - - -static int -_parse_iteration_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_id(ctx, ctx->dict._while, &p) == 0) { - _emit(ctx, &p.out, OP_WHILE); - if (_parse_token(ctx, SL_PP_LPAREN, &p)) { - _error(ctx, "expected `('"); - return -1; - } - if (_parse_condition(ctx, &p)) { - _error(ctx, "expected an expression"); - return -1; - } - if (_parse_token(ctx, SL_PP_RPAREN, &p)) { - _error(ctx, "expected `)'"); - return -1; - } - if (_parse_statement(ctx, &p)) { - return -1; - } - *ps = p; - return 0; - } - - if (_parse_id(ctx, ctx->dict._do, &p) == 0) { - _emit(ctx, &p.out, OP_DO); - if (_parse_statement(ctx, &p)) { - return -1; - } - if (_parse_id(ctx, ctx->dict._while, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_LPAREN, &p)) { - _error(ctx, "expected `('"); - return -1; - } - if (_parse_expression(ctx, &p)) { - _error(ctx, "expected an expression"); - return -1; - } - if (_parse_token(ctx, SL_PP_RPAREN, &p)) { - _error(ctx, "expected `)'"); - return -1; - } - _emit(ctx, &p.out, OP_END); - if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) { - _error(ctx, "expected `;'"); - return -1; - } - *ps = p; - return 0; - } - - if (_parse_id(ctx, ctx->dict._for, &p) == 0) { - _emit(ctx, &p.out, OP_FOR); - if (_parse_token(ctx, SL_PP_LPAREN, &p)) { - _error(ctx, "expected `('"); - return -1; - } - if (_parse_for_init_statement(ctx, &p)) { - return -1; - } - if (_parse_for_rest_statement(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_RPAREN, &p)) { - _error(ctx, "expected `)'"); - return -1; - } - if (_parse_statement(ctx, &p)) { - return -1; - } - *ps = p; - return 0; - } - - return -1; -} - - -static int -_parse_jump_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e = _emit(ctx, &p.out, 0); - - if (_parse_id(ctx, ctx->dict._continue, &p) == 0) { - _update(ctx, e, OP_CONTINUE); - } else if (_parse_id(ctx, ctx->dict._break, &p) == 0) { - _update(ctx, e, OP_BREAK); - } else if (_parse_id(ctx, ctx->dict._return, &p) == 0) { - _update(ctx, e, OP_RETURN); - if (_parse_expression(ctx, &p)) { - _emit(ctx, &p.out, OP_PUSH_VOID); - } - _emit(ctx, &p.out, OP_END); - } else if (ctx->shader_type == 1 && _parse_id(ctx, ctx->dict.discard, &p) == 0) { - _update(ctx, e, OP_DISCARD); - } else { - return -1; - } - if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_simple_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p; - unsigned int e; - - if (_parse_selection_statement(ctx, ps) == 0) { - return 0; - } - - if (_parse_iteration_statement(ctx, ps) == 0) { - return 0; - } - - if (_parse_jump_statement(ctx, ps) == 0) { - return 0; - } - - p = *ps; - e = _emit(ctx, &p.out, OP_EXPRESSION); - if (_parse_expression_statement(ctx, &p) == 0) { - *ps = p; - return 0; - } - - if (_parse_precision_stmt(ctx, &p) == 0) { - _update(ctx, e, OP_PRECISION); - *ps = p; - return 0; - } - - if (ctx->parsing_builtin && _parse_asm_statement(ctx, &p) == 0) { - _update(ctx, e, OP_ASM); - *ps = p; - return 0; - } - - if (_parse_declaration(ctx, &p) == 0) { - _update(ctx, e, OP_DECLARE); - *ps = p; - return 0; - } - - return -1; -} - - -static int -_parse_compound_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_token(ctx, SL_PP_LBRACE, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_BLOCK_BEGIN_NEW_SCOPE); - _parse_statement_list(ctx, &p); - if (_parse_token(ctx, SL_PP_RBRACE, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_END); - *ps = p; - return 0; -} - - -static int -_parse_statement(struct parse_context *ctx, - struct parse_state *ps) -{ - if (_parse_compound_statement(ctx, ps) == 0) { - return 0; - } - - if (_parse_simple_statement(ctx, ps) == 0) { - return 0; - } - - return -1; -} - - -static int -_parse_statement_list(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_statement(ctx, &p)) { - return -1; - } - - for (;;) { - *ps = p; - if (_parse_statement(ctx, &p)) { - return 0; - } - } -} - - -static int -_parse_compound_statement_no_new_scope(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_token(ctx, SL_PP_LBRACE, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_BLOCK_BEGIN_NO_NEW_SCOPE); - _parse_statement_list(ctx, &p); - if (_parse_token(ctx, SL_PP_RBRACE, &p)) { - return -1; - } - _emit(ctx, &p.out, OP_END); - *ps = p; - return 0; -} - - -static int -_parse_function_definition(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_function_prototype(ctx, &p)) { - return -1; - } - if (_parse_compound_statement_no_new_scope(ctx, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_invariant_stmt(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_id(ctx, ctx->dict.invariant, &p)) { - return -1; - } - if (_parse_identifier(ctx, &p)) { - return -1; - } - if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) { - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_single_declaration(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e; - - if (_parse_fully_specified_type(ctx, &p)) { - return -1; - } - - e = _emit(ctx, &p.out, VARIABLE_IDENTIFIER); - if (_parse_identifier(ctx, &p)) { - _update(ctx, e, VARIABLE_NONE); - *ps = p; - return 0; - } - - e = _emit(ctx, &p.out, VARIABLE_NONE); - *ps = p; - - if (_parse_token(ctx, SL_PP_ASSIGN, &p) == 0) { - _update(ctx, e, VARIABLE_INITIALIZER); - if (_parse_initializer(ctx, &p) == 0) { - *ps = p; - return 0; - } - _error(ctx, "expected an initialiser"); - return -1; - } - p = *ps; - - if (_parse_token(ctx, SL_PP_LBRACKET, &p) == 0) { - if (_parse_constant_expression(ctx, &p)) { - _update(ctx, e, VARIABLE_ARRAY_UNKNOWN); - } else { - _update(ctx, e, VARIABLE_ARRAY_EXPLICIT); - } - if (_parse_token(ctx, SL_PP_RBRACKET, &p) == 0) { - *ps = p; - return 0; - } - _error(ctx, "expected `]'"); - return -1; - } - return 0; -} - - -static int -_parse_init_declarator_list(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - - if (_parse_single_declaration(ctx, &p)) { - return -1; - } - - for (;;) { - unsigned int e; - - *ps = p; - if (_parse_token(ctx, SL_PP_COMMA, &p)) { - break; - } - _emit(ctx, &p.out, DECLARATOR_NEXT); - _emit(ctx, &p.out, VARIABLE_IDENTIFIER); - if (_parse_identifier(ctx, &p)) { - break; - } - - e = _emit(ctx, &p.out, VARIABLE_NONE); - *ps = p; - - if (_parse_token(ctx, SL_PP_ASSIGN, &p) == 0) { - if (_parse_initializer(ctx, &p) == 0) { - _update(ctx, e, VARIABLE_INITIALIZER); - *ps = p; - continue; - } - _error(ctx, "expected an initialiser"); - break; - } - p = *ps; - - if (_parse_token(ctx, SL_PP_LBRACKET, &p) == 0) { - unsigned int arr; - - if (_parse_constant_expression(ctx, &p)) { - arr = VARIABLE_ARRAY_UNKNOWN; - } else { - arr = VARIABLE_ARRAY_EXPLICIT; - } - if (_parse_token(ctx, SL_PP_RBRACKET, &p) == 0) { - _update(ctx, e, arr); - *ps = p; - continue; - } - _error(ctx, "expected `]'"); - break; - } - p = *ps; - } - - _emit(ctx, &ps->out, DECLARATOR_NONE); - return 0; -} - - -static int -_parse_declaration(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e = _emit(ctx, &p.out, DECLARATION_FUNCTION_PROTOTYPE); - - if (_parse_function_prototype(ctx, &p)) { - if (_parse_init_declarator_list(ctx, &p)) { - return -1; - } - _update(ctx, e, DECLARATION_INIT_DECLARATOR_LIST); - } - if (_parse_token(ctx, SL_PP_SEMICOLON, &p)) { - _error(ctx, "expected `;'"); - return -1; - } - *ps = p; - return 0; -} - - -static int -_parse_external_declaration(struct parse_context *ctx, - struct parse_state *ps) -{ - struct parse_state p = *ps; - unsigned int e = _emit(ctx, &p.out, 0); - - if (_parse_precision_stmt(ctx, &p) == 0) { - _update(ctx, e, DEFAULT_PRECISION); - *ps = p; - return 0; - } - - if (_parse_function_definition(ctx, &p) == 0) { - _update(ctx, e, EXTERNAL_FUNCTION_DEFINITION); - *ps = p; - return 0; - } - - if (_parse_invariant_stmt(ctx, &p) == 0) { - _update(ctx, e, INVARIANT_STMT); - *ps = p; - return 0; - } - - if (_parse_declaration(ctx, &p) == 0) { - _update(ctx, e, EXTERNAL_DECLARATION); - *ps = p; - return 0; - } - - _error(ctx, "expected an identifier"); - return -1; -} - - -static int -_parse_extensions(struct parse_context *ctx, - struct parse_state *ps) -{ - for (;;) { - const struct sl_pp_token_info *input = _fetch_token(ctx, ps->in); - unsigned int enable; - - if (!input) { - return -1; - } - - switch (input->token) { - case SL_PP_EXTENSION_REQUIRE: - case SL_PP_EXTENSION_ENABLE: - case SL_PP_EXTENSION_WARN: - enable = 1; - break; - case SL_PP_EXTENSION_DISABLE: - enable = 0; - break; - default: - return 0; - } - - ps->in++; - if (input->data.extension == ctx->dict.all) { - ctx->fragment_coord_conventions = enable; - } - else if (input->data.extension == ctx->dict._GL_ARB_fragment_coord_conventions) { - ctx->fragment_coord_conventions = enable; - } - else if (input->data.extension == ctx->dict._GL_ARB_texture_rectangle) { - ctx->texture_rectangle = enable; - } - } -} - - -static int -_parse_translation_unit(struct parse_context *ctx, - struct parse_state *ps) -{ - _emit(ctx, &ps->out, REVISION); - if (_parse_extensions(ctx, ps)) { - return -1; - } - if (_parse_external_declaration(ctx, ps)) { - return -1; - } - for (;;) { - if (_parse_extensions(ctx, ps)) { - return -1; - } - if (_parse_external_declaration(ctx, ps)) { - break; - } - } - _emit(ctx, &ps->out, EXTERNAL_NULL); - if (_parse_token(ctx, SL_PP_EOF, ps)) { - return -1; - } - return 0; -} - - -#define ADD_NAME_STR(CTX, NAME, STR)\ - do {\ - (CTX).dict.NAME = sl_pp_context_add_unique_str((CTX).context, (STR));\ - if ((CTX).dict.NAME == -1) {\ - return -1;\ - }\ - } while (0) - -#define ADD_NAME(CTX, NAME) ADD_NAME_STR(CTX, NAME, #NAME) - - -int -sl_cl_compile(struct sl_pp_context *context, - unsigned int shader_type, - unsigned int parsing_builtin, - unsigned char **output, - unsigned int *cboutput, - char *error, - unsigned int cberror) -{ - struct parse_context ctx; - struct parse_state ps; - - ctx.context = context; - - ADD_NAME_STR(ctx, _void, "void"); - ADD_NAME_STR(ctx, _float, "float"); - ADD_NAME_STR(ctx, _int, "int"); - ADD_NAME_STR(ctx, _bool, "bool"); - ADD_NAME(ctx, vec2); - ADD_NAME(ctx, vec3); - ADD_NAME(ctx, vec4); - ADD_NAME(ctx, bvec2); - ADD_NAME(ctx, bvec3); - ADD_NAME(ctx, bvec4); - ADD_NAME(ctx, ivec2); - ADD_NAME(ctx, ivec3); - ADD_NAME(ctx, ivec4); - ADD_NAME(ctx, mat2); - ADD_NAME(ctx, mat3); - ADD_NAME(ctx, mat4); - ADD_NAME(ctx, mat2x3); - ADD_NAME(ctx, mat3x2); - ADD_NAME(ctx, mat2x4); - ADD_NAME(ctx, mat4x2); - ADD_NAME(ctx, mat3x4); - ADD_NAME(ctx, mat4x3); - ADD_NAME(ctx, sampler1D); - ADD_NAME(ctx, sampler2D); - ADD_NAME(ctx, sampler3D); - ADD_NAME(ctx, samplerCube); - ADD_NAME(ctx, sampler1DShadow); - ADD_NAME(ctx, sampler2DShadow); - ADD_NAME(ctx, sampler2DRect); - ADD_NAME(ctx, sampler2DRectShadow); - ADD_NAME(ctx, sampler1DArray); - ADD_NAME(ctx, sampler2DArray); - ADD_NAME(ctx, sampler1DArrayShadow); - ADD_NAME(ctx, sampler2DArrayShadow); - - ADD_NAME(ctx, invariant); - - ADD_NAME(ctx, centroid); - - ADD_NAME(ctx, precision); - ADD_NAME(ctx, lowp); - ADD_NAME(ctx, mediump); - ADD_NAME(ctx, highp); - - ADD_NAME_STR(ctx, _const, "const"); - ADD_NAME(ctx, attribute); - ADD_NAME(ctx, varying); - ADD_NAME(ctx, uniform); - ADD_NAME(ctx, __fixed_output); - ADD_NAME(ctx, __fixed_input); - - ADD_NAME(ctx, in); - ADD_NAME(ctx, out); - ADD_NAME(ctx, inout); - - ADD_NAME(ctx, layout); - ADD_NAME(ctx, origin_upper_left); - ADD_NAME(ctx, pixel_center_integer); - - ADD_NAME_STR(ctx, _struct, "struct"); - - ADD_NAME(ctx, __constructor); - ADD_NAME(ctx, __operator); - ADD_NAME_STR(ctx, ___asm, "__asm"); - - ADD_NAME_STR(ctx, _if, "if"); - ADD_NAME_STR(ctx, _else, "else"); - ADD_NAME_STR(ctx, _for, "for"); - ADD_NAME_STR(ctx, _while, "while"); - ADD_NAME_STR(ctx, _do, "do"); - - ADD_NAME_STR(ctx, _continue, "continue"); - ADD_NAME_STR(ctx, _break, "break"); - ADD_NAME_STR(ctx, _return, "return"); - ADD_NAME(ctx, discard); - - ADD_NAME_STR(ctx, _false, "false"); - ADD_NAME_STR(ctx, _true, "true"); - - ADD_NAME(ctx, all); - ADD_NAME_STR(ctx, _GL_ARB_fragment_coord_conventions, "GL_ARB_fragment_coord_conventions"); - ADD_NAME_STR(ctx, _GL_ARB_texture_rectangle, "GL_ARB_texture_rectangle"); - - ctx.out_buf = NULL; - ctx.out_cap = 0; - - ctx.shader_type = shader_type; - ctx.parsing_builtin = 1; - - ctx.fragment_coord_conventions = 0; - ctx.texture_rectangle = 1; - - ctx.error[0] = '\0'; - ctx.process_error = 0; - - ctx.tokens_cap = 1024; - ctx.tokens_read = 0; - ctx.tokens = malloc(ctx.tokens_cap * sizeof(struct sl_pp_token_info)); - if (!ctx.tokens) { - strncpy(error, "out of memory", cberror - 1); - error[cberror - 1] = '\0'; - return -1; - } - - ps.in = 0; - ps.out = 0; - - if (_parse_translation_unit(&ctx, &ps)) { - strncpy(error, ctx.error, cberror); - free(ctx.tokens); - return -1; - } - - *output = ctx.out_buf; - *cboutput = ps.out; - free(ctx.tokens); - return 0; -} diff --git a/src/glsl/cl/sl_cl_parse.h b/src/glsl/cl/sl_cl_parse.h deleted file mode 100644 index a954d43927..0000000000 --- a/src/glsl/cl/sl_cl_parse.h +++ /dev/null @@ -1,42 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#ifndef SL_CL_PARSE_H -#define SL_CL_PARSE_H - -struct sl_pp_context; - -int -sl_cl_compile(struct sl_pp_context *context, - unsigned int shader_type, - unsigned int parsing_builtin, - unsigned char **output, - unsigned int *cboutput, - char *error, - unsigned int cberror); - -#endif /* SL_CL_PARSE_H */ diff --git a/src/glsl/configure.ac b/src/glsl/configure.ac new file mode 100644 index 0000000000..73ce67de3d --- /dev/null +++ b/src/glsl/configure.ac @@ -0,0 +1,69 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.61) +AC_INIT(glsl, XXXXX, idr@freedesktop.org, glsl) +AC_CONFIG_SRCDIR([Makefile.am]) +AM_CONFIG_HEADER([config.h]) +AC_CONFIG_FILES([glcpp/Makefile]) + +AM_INIT_AUTOMAKE +LT_INIT + +AM_MAINTAINER_MODE + +# Checks for programs. +AC_PROG_CXX +AC_PROG_CC +AC_PROG_MAKE_SET +AC_PROG_YACC +AC_PROG_LEX + +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +# Checks for libraries. + +# Checks for header files. + +# Checks for typedefs, structures, and compiler characteristics. + +# Checks for library functions. +AC_HEADER_STDC + +AH_TOP([#ifndef GLSL_CONFIG_H +#define GLSL_CONFIG_H]) +AH_BOTTOM([#endif /* GLSL_CONFIG_H */]) + +PKG_CHECK_MODULES([talloc], [talloc >= 2.0]) + +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug], + [use debug compiler flags and macros @<:@default=disabled@:>@])], + [enable_debug="$enableval"], + [enable_debug=no] +) +if test "x$enable_debug" = xyes; then + DEFINES="$DEFINES -DDEBUG" + if test "x$GCC" = xyes; then + # Remove any -g or -O flags from the command line + CFLAGS=[`echo $CFLAGS | sed 's/-g[^ \t]*[ \t]*//g;s/-O[^ \t]*[ \t]*//g'`] + CFLAGS="$CFLAGS -O0 -ggdb3 -fstack-protector -D_FORTIFY_SOURCE=2" + fi + if test "x$GXX" = xyes; then + # Remove any -g flags from the command line + CXXFLAGS=[`echo $CXXFLAGS | sed 's/-g[^ \t]*[ \t]*//g;s/-O[^ \t]*[ \t]*//g'`] + CXXFLAGS="$CXXFLAGS -O0 -ggdb3 -fstack-protector -D_FORTIFY_SOURCE=2" + fi +fi + +if test "x$GXX" = xyes ; then + WARN="-Wall -Wextra -Wunsafe-loop-optimizations -Wstack-protector" +else + WARN="" +fi + +CFLAGS="$CFLAGS $WARN" +CXXFLAGS="$CXXFLAGS $WARN" +YFLAGS="-d -v" + +AC_OUTPUT([Makefile]) diff --git a/src/glsl/glcpp/.gitignore b/src/glsl/glcpp/.gitignore new file mode 100644 index 0000000000..dbc37e1926 --- /dev/null +++ b/src/glsl/glcpp/.gitignore @@ -0,0 +1,8 @@ +glcpp +glcpp-parse.output +*.o +*.lo +*.la +.libs +*~ +tests/*.out diff --git a/src/glsl/glcpp/Makefile.am b/src/glsl/glcpp/Makefile.am new file mode 100644 index 0000000000..81147e6e12 --- /dev/null +++ b/src/glsl/glcpp/Makefile.am @@ -0,0 +1,44 @@ +# Copyright © 2010 Intel Corporation +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, and/or sell copies of the Software, and to permit persons to whom +# the Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +# AUTHORS, COPYRIGHT HOLDERS, AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +# USE OR OTHER DEALINGS IN THE SOFTWARE. + +noinst_LTLIBRARIES = libglcpp.la +libglcpp_la_SOURCES = \ + glcpp-lex.l \ + glcpp-parse.y \ + glcpp.h \ + pp.c + +BUILT_SOURCES = glcpp-parse.h glcpp-parse.c glcpp-lex.c +CLEANFILES = $(BUILT_SOURCES) + +glcpp-parse.h: glcpp-parse.c + +bin_PROGRAMS = glcpp +glcpp_LDADD = libglcpp.la +glcpp_LDFLAGS = @LDFLAGS@ $(talloc_LIBS) +glcpp_SOURCES = glcpp.c + +.l.c: + $(LEXCOMPILE) --outfile="$@" $< + +test: glcpp + @(cd tests; ./glcpp-test) diff --git a/src/glsl/glcpp/README b/src/glsl/glcpp/README new file mode 100644 index 0000000000..0b5ef508ce --- /dev/null +++ b/src/glsl/glcpp/README @@ -0,0 +1,32 @@ +glcpp -- GLSL "C" preprocessor + +This is a simple preprocessor designed to provide the preprocessing +needs of the GLSL language. The requirements for this preprocessor are +specified in the GLSL 1.30 specification availble from: + +http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.30.10.pdf + +This specification is not precise on some semantics, (for example, +#define and #if), defining these merely "as is standard for C++ +preprocessors". To fill in these details, I've been using a draft of +the C99 standard as available from: + +http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf + +Any downstream compiler accepting output from glcpp should be prepared +to encounter and deal with the following preprocessor macros: + + #line + #pragma + #extension + +All other macros will be handles according to the GLSL specification +and will not appear in the output. + +Known limitations +----------------- +The __LINE__ and __FILE__ macros are not yet supported. + +A file that ends with a function-like macro name as the last +non-whitespace token will result in a parse error, (where it should be +passed through as is).
\ No newline at end of file diff --git a/src/glsl/glcpp/glcpp-lex.c b/src/glsl/glcpp/glcpp-lex.c new file mode 100644 index 0000000000..0f99ea1bbb --- /dev/null +++ b/src/glsl/glcpp/glcpp-lex.c @@ -0,0 +1,2691 @@ +#line 2 "glcpp/glcpp-lex.c" + +#line 4 "glcpp/glcpp-lex.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE glcpp_restart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via glcpp_restart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void glcpp_restart (FILE *input_file ,yyscan_t yyscanner ); +void glcpp__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE glcpp__create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void glcpp__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void glcpp__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void glcpp_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void glcpp_pop_buffer_state (yyscan_t yyscanner ); + +static void glcpp_ensure_buffer_stack (yyscan_t yyscanner ); +static void glcpp__load_buffer_state (yyscan_t yyscanner ); +static void glcpp__init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER glcpp__flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE glcpp__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE glcpp__scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE glcpp__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *glcpp_alloc (yy_size_t ,yyscan_t yyscanner ); +void *glcpp_realloc (void *,yy_size_t ,yyscan_t yyscanner ); +void glcpp_free (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer glcpp__create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + glcpp_ensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + glcpp_ensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define glcpp_wrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 43 +#define YY_END_OF_BUFFER 44 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_acclist[137] = + { 0, + 3, 3, 44, 39, 43, 40, 43, 41, 43, 43, + 38, 43, 43, 38, 43, 38, 43, 38, 43, 25, + 39, 43, 24, 39, 43, 38, 43, 38, 43, 38, + 43, 37, 39, 43, 37, 39, 43, 38, 43, 40, + 43, 23, 43, 43, 3, 43, 4, 43, 5, 43, + 42, 43, 39, 18, 40, 32, 35, 33, 2, 1, + 25, 39, 25, 39, 39, 24, 39, 24, 39, 27, + 29, 31, 30, 28, 37, 39, 37, 39, 34, 40, + 23, 23, 3, 4, 5, 6, 5, 7, 1, 26, + 39, 37, 39,16398, 26, 39, 37, 39, 18, 37, + + 39,16399,16400, 8206, 18, 8206, 37, 39, 8207, 18, + 8208, 18,16401, 19,16396, 22, 36, 37, 39, 21, + 8209, 18, 19, 8204, 18,16397,16404, 8205, 18, 11, + 18, 9, 8, 8212, 10, 18 + } ; + +static yyconst flex_int16_t yy_accept[164] = + { 0, + 1, 1, 1, 1, 1, 2, 3, 3, 3, 4, + 6, 8, 10, 11, 13, 14, 16, 18, 20, 23, + 26, 28, 30, 32, 35, 38, 40, 42, 44, 45, + 47, 49, 51, 53, 54, 54, 55, 56, 57, 58, + 59, 60, 61, 63, 65, 66, 68, 70, 71, 72, + 73, 74, 75, 77, 79, 80, 81, 82, 83, 83, + 83, 83, 83, 83, 83, 83, 84, 85, 86, 87, + 88, 89, 90, 92, 94, 94, 94, 94, 94, 94, + 95, 95, 95, 95, 95, 97, 99, 99, 99, 99, + 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, + + 100, 102, 102, 103, 104, 104, 104, 104, 104, 106, + 106, 107, 107, 107, 107, 107, 107, 107, 109, 109, + 109, 111, 111, 113, 114, 115, 115, 116, 116, 116, + 116, 117, 117, 120, 121, 121, 123, 124, 124, 124, + 126, 127, 127, 127, 127, 128, 128, 128, 130, 130, + 132, 132, 133, 134, 134, 134, 134, 135, 135, 135, + 137, 137, 137 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 5, 1, 6, 1, 7, 8, 1, 9, + 7, 10, 7, 7, 7, 7, 11, 12, 13, 13, + 13, 13, 13, 13, 13, 14, 14, 1, 7, 15, + 16, 17, 1, 1, 18, 18, 18, 18, 18, 18, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 20, 19, 19, 21, 19, 19, + 7, 1, 7, 7, 19, 1, 22, 18, 18, 23, + + 24, 25, 26, 19, 27, 19, 19, 28, 29, 30, + 31, 32, 19, 33, 34, 35, 36, 37, 19, 38, + 19, 19, 7, 39, 7, 7, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[40] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[182] = + { 0, + 0, 38, 0, 0, 38, 39, 499, 498, 500, 48, + 43, 552, 496, 44, 63, 495, 59, 65, 87, 125, + 58, 67, 68, 164, 203, 40, 75, 241, 552, 494, + 552, 140, 552, 140, 493, 552, 144, 492, 491, 487, + 486, 485, 156, 179, 267, 0, 209, 472, 471, 470, + 469, 468, 446, 124, 466, 153, 462, 458, 154, 198, + 159, 155, 183, 160, 193, 460, 552, 222, 552, 227, + 552, 459, 204, 161, 231, 232, 238, 243, 236, 303, + 245, 180, 247, 249, 281, 56, 257, 271, 248, 259, + 252, 264, 455, 454, 297, 299, 312, 313, 320, 294, + + 407, 295, 427, 426, 321, 296, 324, 425, 552, 424, + 552, 327, 329, 195, 328, 331, 332, 230, 334, 378, + 552, 377, 552, 371, 370, 335, 365, 337, 358, 342, + 360, 344, 326, 255, 340, 552, 260, 338, 246, 552, + 197, 364, 192, 352, 382, 348, 186, 552, 420, 552, + 423, 184, 141, 437, 421, 447, 79, 476, 346, 552, + 453, 552, 515, 517, 519, 521, 523, 525, 71, 527, + 529, 531, 533, 535, 537, 539, 541, 543, 545, 547, + 549 + } ; + +static yyconst flex_int16_t yy_def[182] = + { 0, + 162, 1, 163, 163, 164, 164, 165, 165, 162, 166, + 167, 162, 167, 167, 167, 167, 167, 167, 162, 166, + 167, 167, 167, 168, 168, 167, 167, 167, 162, 169, + 162, 170, 162, 20, 167, 162, 167, 167, 167, 167, + 167, 171, 19, 20, 20, 20, 20, 167, 167, 167, + 167, 167, 25, 25, 167, 167, 28, 28, 167, 167, + 167, 167, 167, 167, 167, 169, 162, 170, 162, 170, + 162, 171, 45, 25, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 20, 25, 167, 167, 167, 167, + 167, 167, 172, 173, 167, 167, 167, 167, 167, 167, + + 25, 167, 174, 175, 167, 167, 167, 172, 162, 173, + 162, 167, 167, 167, 167, 167, 167, 25, 167, 174, + 162, 175, 162, 176, 177, 167, 178, 167, 167, 167, + 167, 167, 25, 167, 176, 162, 177, 167, 178, 162, + 179, 167, 180, 167, 162, 167, 179, 162, 167, 162, + 167, 180, 167, 181, 167, 167, 167, 181, 167, 162, + 167, 0, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162 + } ; + +static yyconst flex_int16_t yy_nxt[592] = + { 0, + 10, 11, 12, 13, 14, 15, 16, 17, 16, 16, + 18, 19, 20, 20, 21, 22, 23, 24, 24, 24, + 24, 24, 25, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 26, 27, + 31, 31, 36, 28, 37, 36, 36, 32, 32, 35, + 36, 35, 35, 35, 35, 35, 35, 35, 35, 38, + 36, 36, 35, 35, 35, 36, 40, 36, 39, 36, + 36, 66, 48, 49, 41, 42, 56, 36, 55, 53, + 57, 36, 50, 51, 52, 101, 35, 34, 35, 36, + 35, 35, 35, 35, 35, 35, 35, 35, 43, 43, + + 34, 35, 35, 35, 34, 34, 44, 45, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 44, 34, 45, 35, 35, 36, 35, 35, + 35, 35, 35, 35, 35, 35, 46, 46, 46, 35, + 35, 35, 69, 36, 47, 37, 36, 53, 74, 70, + 71, 34, 34, 34, 56, 36, 36, 36, 57, 34, + 47, 36, 36, 35, 34, 35, 36, 35, 35, 35, + 35, 35, 35, 35, 35, 34, 34, 75, 35, 35, + 35, 81, 36, 80, 53, 36, 36, 86, 148, 83, + 34, 34, 34, 34, 36, 36, 129, 36, 34, 148, + + 36, 98, 35, 34, 35, 36, 35, 35, 35, 35, + 35, 35, 35, 35, 34, 82, 84, 35, 35, 35, + 34, 34, 34, 85, 69, 76, 54, 77, 34, 69, + 78, 162, 162, 36, 36, 79, 70, 71, 36, 85, + 36, 35, 58, 36, 34, 36, 39, 36, 140, 36, + 36, 36, 133, 53, 36, 87, 145, 36, 88, 36, + 90, 36, 36, 59, 60, 89, 36, 61, 62, 99, + 92, 104, 63, 36, 97, 91, 64, 65, 73, 73, + 73, 100, 106, 102, 73, 105, 34, 107, 73, 73, + 73, 73, 34, 34, 34, 103, 36, 36, 36, 36, + + 34, 36, 34, 93, 93, 94, 93, 93, 93, 93, + 93, 93, 93, 93, 36, 36, 34, 93, 93, 93, + 112, 113, 36, 36, 119, 95, 36, 117, 125, 36, + 36, 36, 96, 36, 36, 114, 36, 36, 115, 36, + 36, 93, 136, 116, 36, 124, 36, 159, 160, 53, + 36, 127, 128, 126, 36, 131, 130, 134, 132, 129, + 36, 141, 36, 143, 146, 149, 150, 140, 138, 142, + 142, 142, 36, 136, 144, 151, 151, 151, 155, 123, + 121, 153, 35, 145, 36, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 154, + + 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, + 35, 149, 150, 36, 149, 150, 111, 109, 123, 121, + 118, 156, 156, 156, 151, 151, 151, 35, 35, 36, + 35, 35, 35, 35, 35, 157, 35, 35, 159, 160, + 143, 35, 35, 35, 159, 160, 111, 109, 161, 161, + 161, 36, 67, 35, 161, 161, 161, 35, 36, 53, + 36, 36, 36, 36, 36, 35, 35, 35, 36, 35, + 35, 35, 35, 35, 157, 35, 35, 36, 36, 36, + 35, 35, 35, 36, 36, 36, 67, 36, 36, 162, + + 29, 29, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 35, 29, 29, 30, 30, 33, + 33, 34, 34, 35, 35, 53, 53, 68, 68, 72, + 72, 108, 108, 110, 110, 120, 120, 122, 122, 135, + 135, 137, 137, 139, 139, 147, 147, 152, 152, 158, + 158, 9, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162 + + } ; + +static yyconst flex_int16_t yy_chk[592] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 5, 6, 26, 2, 11, 11, 14, 5, 6, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 14, + 21, 17, 10, 10, 10, 15, 17, 18, 15, 22, + 23, 169, 21, 21, 18, 18, 27, 27, 26, 86, + 27, 157, 22, 23, 23, 86, 10, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 32, 153, 20, 37, 37, 54, 54, 32, + 32, 34, 34, 34, 56, 56, 59, 62, 56, 34, + 20, 61, 64, 20, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 34, 43, 59, 24, 24, + 24, 62, 82, 61, 74, 63, 152, 74, 147, 64, + 44, 44, 44, 43, 143, 65, 114, 114, 44, 141, + + 60, 82, 24, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 44, 63, 65, 25, 25, 25, + 47, 47, 47, 73, 68, 60, 25, 60, 47, 70, + 60, 68, 68, 75, 76, 60, 70, 70, 79, 73, + 77, 25, 28, 28, 47, 78, 28, 81, 139, 83, + 89, 84, 118, 118, 91, 75, 134, 134, 76, 87, + 77, 90, 137, 28, 28, 76, 92, 28, 28, 83, + 79, 89, 28, 88, 81, 78, 28, 28, 45, 45, + 45, 84, 91, 87, 45, 90, 45, 92, 45, 45, + 45, 45, 85, 85, 85, 88, 100, 102, 106, 95, + + 85, 96, 45, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 97, 98, 85, 80, 80, 80, + 95, 96, 99, 105, 102, 80, 107, 100, 106, 112, + 115, 113, 80, 116, 117, 97, 119, 126, 98, 128, + 138, 80, 135, 99, 130, 105, 132, 159, 159, 133, + 146, 112, 113, 107, 144, 116, 115, 119, 117, 129, + 129, 128, 131, 130, 138, 142, 142, 127, 126, 129, + 129, 129, 125, 124, 132, 142, 142, 142, 146, 122, + 120, 144, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 149, 149, 155, 151, 151, 110, 108, 104, 103, + 101, 149, 149, 149, 151, 151, 151, 154, 154, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 156, 156, + 155, 154, 154, 154, 161, 161, 94, 93, 156, 156, + 156, 72, 66, 58, 161, 161, 161, 57, 55, 53, + 52, 51, 50, 49, 48, 154, 158, 158, 158, 158, + 158, 158, 158, 158, 158, 158, 158, 42, 41, 40, + 158, 158, 158, 39, 38, 35, 30, 16, 13, 9, + + 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 158, 163, 163, 164, 164, 165, + 165, 166, 166, 167, 167, 168, 168, 170, 170, 171, + 171, 172, 172, 173, 173, 174, 174, 175, 175, 176, + 176, 177, 177, 178, 178, 179, 179, 180, 180, 181, + 181, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162 + + } ; + +#define YY_TRAILING_MASK 0x2000 +#define YY_TRAILING_HEAD_MASK 0x4000 +#define REJECT \ +{ \ +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ \ +yy_cp = yyg->yy_full_match; /* restore poss. backed-over text */ \ +yyg->yy_lp = yyg->yy_full_lp; /* restore orig. accepting pos. */ \ +yyg->yy_state_ptr = yyg->yy_full_state; /* restore orig. state */ \ +yy_current_state = *yyg->yy_state_ptr; /* restore curr. state */ \ +++yyg->yy_lp; \ +goto find_rule; \ +} + +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "glcpp/glcpp-lex.l" +#line 2 "glcpp/glcpp-lex.l" +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "glcpp.h" +#include "glcpp-parse.h" + +/* Flex annoyingly generates some functions without making them + * static. Let's declare them here. */ +int glcpp_get_column (yyscan_t yyscanner); +void glcpp_set_column (int column_no , yyscan_t yyscanner); + +#define YY_NO_INPUT + +#define YY_USER_ACTION \ + do { \ + yylloc->first_column = yycolumn + 1; \ + yylloc->first_line = yylineno; \ + yycolumn += yyleng; \ + } while(0); + +#define YY_USER_INIT \ + do { \ + yylineno = 1; \ + yycolumn = 1; \ + yylloc->source = 0; \ + } while(0) + +#line 709 "glcpp/glcpp-lex.c" + +#define INITIAL 0 +#define DONE 1 +#define COMMENT 2 +#define UNREACHABLE 3 + +#define YY_EXTRA_TYPE glcpp_parser_t * + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + yy_state_type *yy_state_buf; + yy_state_type *yy_state_ptr; + char *yy_full_match; + int yy_lp; + + /* These are only needed for trailing context rules, + * but there's no conditional variable for that yet. */ + int yy_looking_for_trail_begin; + int yy_full_lp; + int *yy_full_state; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int glcpp_lex_init (yyscan_t* scanner); + +int glcpp_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int glcpp_lex_destroy (yyscan_t yyscanner ); + +int glcpp_get_debug (yyscan_t yyscanner ); + +void glcpp_set_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE glcpp_get_extra (yyscan_t yyscanner ); + +void glcpp_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *glcpp_get_in (yyscan_t yyscanner ); + +void glcpp_set_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *glcpp_get_out (yyscan_t yyscanner ); + +void glcpp_set_out (FILE * out_str ,yyscan_t yyscanner ); + +int glcpp_get_leng (yyscan_t yyscanner ); + +char *glcpp_get_text (yyscan_t yyscanner ); + +int glcpp_get_lineno (yyscan_t yyscanner ); + +void glcpp_set_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * glcpp_get_lval (yyscan_t yyscanner ); + +void glcpp_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *glcpp_get_lloc (yyscan_t yyscanner ); + + void glcpp_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int glcpp_wrap (yyscan_t yyscanner ); +#else +extern int glcpp_wrap (yyscan_t yyscanner ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + + static void yy_push_state (int new_state ,yyscan_t yyscanner); + + static void yy_pop_state (yyscan_t yyscanner ); + + static int yy_top_state (yyscan_t yyscanner ); + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int glcpp_lex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int glcpp_lex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 76 "glcpp/glcpp-lex.l" + + + /* Single-line comments */ +#line 972 "glcpp/glcpp-lex.c" + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + /* Create the reject buffer large enough to save one state per allowed character. */ + if ( ! yyg->yy_state_buf ) + yyg->yy_state_buf = (yy_state_type *)glcpp_alloc(YY_STATE_BUF_SIZE ,yyscanner); + if ( ! yyg->yy_state_buf ) + YY_FATAL_ERROR( "out of dynamic memory in glcpp_lex()" ); + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + glcpp_ensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + glcpp__load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; + yy_current_state += YY_AT_BOL(); + + yyg->yy_state_ptr = yyg->yy_state_buf; + *yyg->yy_state_ptr++ = yy_current_state; + +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 163 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *yyg->yy_state_ptr++ = yy_current_state; + ++yy_cp; + } + while ( yy_current_state != 162 ); + +yy_find_action: + yy_current_state = *--yyg->yy_state_ptr; + yyg->yy_lp = yy_accept[yy_current_state]; +find_rule: /* we branch to this label when backing up */ + for ( ; ; ) /* until we find what rule we matched */ + { + if ( yyg->yy_lp && yyg->yy_lp < yy_accept[yy_current_state + 1] ) + { + yy_act = yy_acclist[yyg->yy_lp]; + if ( yy_act & YY_TRAILING_HEAD_MASK || + yyg->yy_looking_for_trail_begin ) + { + if ( yy_act == yyg->yy_looking_for_trail_begin ) + { + yyg->yy_looking_for_trail_begin = 0; + yy_act &= ~YY_TRAILING_HEAD_MASK; + break; + } + } + else if ( yy_act & YY_TRAILING_MASK ) + { + yyg->yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK; + yyg->yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK; + yyg->yy_full_match = yy_cp; + yyg->yy_full_state = yyg->yy_state_ptr; + yyg->yy_full_lp = yyg->yy_lp; + } + else + { + yyg->yy_full_match = yy_cp; + yyg->yy_full_state = yyg->yy_state_ptr; + yyg->yy_full_lp = yyg->yy_lp; + break; + } + ++yyg->yy_lp; + goto find_rule; + } + --yy_cp; + yy_current_state = *--yyg->yy_state_ptr; + yyg->yy_lp = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +YY_RULE_SETUP +#line 79 "glcpp/glcpp-lex.l" +{ +} + YY_BREAK +/* Multi-line comments */ +case 2: +YY_RULE_SETUP +#line 83 "glcpp/glcpp-lex.l" +{ yy_push_state(COMMENT, yyscanner); } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 84 "glcpp/glcpp-lex.l" + + YY_BREAK +case 4: +/* rule 4 can match eol */ +YY_RULE_SETUP +#line 85 "glcpp/glcpp-lex.l" +{ yylineno++; yycolumn = 0; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 86 "glcpp/glcpp-lex.l" + + YY_BREAK +case 6: +/* rule 6 can match eol */ +YY_RULE_SETUP +#line 87 "glcpp/glcpp-lex.l" +{ yylineno++; yycolumn = 0; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 88 "glcpp/glcpp-lex.l" +{ + yy_pop_state(yyscanner); + if (yyextra->space_tokens) + return SPACE; +} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 94 "glcpp/glcpp-lex.l" +{ + yylval->str = talloc_strdup (yyextra, yytext); + yyextra->space_tokens = 0; + return HASH_VERSION; +} + YY_BREAK +/* glcpp doesn't handle #extension, #version, or #pragma directives. + * Simply pass them through to the main compiler's lexer/parser. */ +case 9: +YY_RULE_SETUP +#line 102 "glcpp/glcpp-lex.l" +{ + yylval->str = talloc_strdup (yyextra, yytext); + yylineno++; + yycolumn = 0; + return OTHER; +} + YY_BREAK +case 10: +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 109 "glcpp/glcpp-lex.l" +{ + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; + yylloc->source = strtol(ptr, NULL, 0); +} + YY_BREAK +case 11: +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 125 "glcpp/glcpp-lex.l" +{ + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; +} + YY_BREAK +case 12: +/* rule 12 can match eol */ +YY_RULE_SETUP +#line 140 "glcpp/glcpp-lex.l" +{ + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_IFDEF; +} + YY_BREAK +case 13: +/* rule 13 can match eol */ +YY_RULE_SETUP +#line 146 "glcpp/glcpp-lex.l" +{ + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_IFNDEF; +} + YY_BREAK +case 14: +/* rule 14 can match eol */ +YY_RULE_SETUP +#line 152 "glcpp/glcpp-lex.l" +{ + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_IF; +} + YY_BREAK +case 15: +/* rule 15 can match eol */ +YY_RULE_SETUP +#line 158 "glcpp/glcpp-lex.l" +{ + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_ELIF; +} + YY_BREAK +case 16: +/* rule 16 can match eol */ +YY_RULE_SETUP +#line 164 "glcpp/glcpp-lex.l" +{ + yyextra->space_tokens = 0; + return HASH_ELSE; +} + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 169 "glcpp/glcpp-lex.l" +{ + yyextra->space_tokens = 0; + return HASH_ENDIF; +} + YY_BREAK +/* When skipping (due to an #if 0 or similar) consume anything + * up to a newline. We do this with less priority than any + * #if-related directive (#if, #elif, #else, #endif), but with + * more priority than any other directive or token to avoid + * any side-effects from skipped content. + * + * We use the lexing_if flag to avoid skipping any part of an + * if conditional expression. */ +case 18: +/* rule 18 can match eol */ +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 182 "glcpp/glcpp-lex.l" +{ + /* Since this rule always matches, YY_USER_ACTION gets called for it, + * wrongly incrementing yycolumn. We undo that effect here. */ + yycolumn -= yyleng; + if (yyextra->lexing_if || + yyextra->skip_stack == NULL || + yyextra->skip_stack->type == SKIP_NO_SKIP) + { + REJECT; + } +} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 194 "glcpp/glcpp-lex.l" +{ + char *p; + for (p = yytext; !isalpha(p[0]); p++); /* skip " # " */ + p += 5; /* skip "error" */ + glcpp_error(yylloc, yyextra, "#error%s", p); +} + YY_BREAK +case 20: +YY_RULE_SETUP +#line 201 "glcpp/glcpp-lex.l" +{ + yyextra->space_tokens = 0; + return HASH_DEFINE_FUNC; +} + YY_BREAK +case 21: +YY_RULE_SETUP +#line 206 "glcpp/glcpp-lex.l" +{ + yyextra->space_tokens = 0; + return HASH_DEFINE_OBJ; +} + YY_BREAK +case 22: +YY_RULE_SETUP +#line 211 "glcpp/glcpp-lex.l" +{ + yyextra->space_tokens = 0; + return HASH_UNDEF; +} + YY_BREAK +case 23: +YY_RULE_SETUP +#line 216 "glcpp/glcpp-lex.l" +{ + yyextra->space_tokens = 0; + return HASH; +} + YY_BREAK +case 24: +YY_RULE_SETUP +#line 221 "glcpp/glcpp-lex.l" +{ + yylval->str = talloc_strdup (yyextra, yytext); + return INTEGER_STRING; +} + YY_BREAK +case 25: +YY_RULE_SETUP +#line 226 "glcpp/glcpp-lex.l" +{ + yylval->str = talloc_strdup (yyextra, yytext); + return INTEGER_STRING; +} + YY_BREAK +case 26: +YY_RULE_SETUP +#line 231 "glcpp/glcpp-lex.l" +{ + yylval->str = talloc_strdup (yyextra, yytext); + return INTEGER_STRING; +} + YY_BREAK +case 27: +YY_RULE_SETUP +#line 236 "glcpp/glcpp-lex.l" +{ + return LEFT_SHIFT; +} + YY_BREAK +case 28: +YY_RULE_SETUP +#line 240 "glcpp/glcpp-lex.l" +{ + return RIGHT_SHIFT; +} + YY_BREAK +case 29: +YY_RULE_SETUP +#line 244 "glcpp/glcpp-lex.l" +{ + return LESS_OR_EQUAL; +} + YY_BREAK +case 30: +YY_RULE_SETUP +#line 248 "glcpp/glcpp-lex.l" +{ + return GREATER_OR_EQUAL; +} + YY_BREAK +case 31: +YY_RULE_SETUP +#line 252 "glcpp/glcpp-lex.l" +{ + return EQUAL; +} + YY_BREAK +case 32: +YY_RULE_SETUP +#line 256 "glcpp/glcpp-lex.l" +{ + return NOT_EQUAL; +} + YY_BREAK +case 33: +YY_RULE_SETUP +#line 260 "glcpp/glcpp-lex.l" +{ + return AND; +} + YY_BREAK +case 34: +YY_RULE_SETUP +#line 264 "glcpp/glcpp-lex.l" +{ + return OR; +} + YY_BREAK +case 35: +YY_RULE_SETUP +#line 268 "glcpp/glcpp-lex.l" +{ + return PASTE; +} + YY_BREAK +case 36: +YY_RULE_SETUP +#line 272 "glcpp/glcpp-lex.l" +{ + return DEFINED; +} + YY_BREAK +case 37: +YY_RULE_SETUP +#line 276 "glcpp/glcpp-lex.l" +{ + yylval->str = talloc_strdup (yyextra, yytext); + return IDENTIFIER; +} + YY_BREAK +case 38: +YY_RULE_SETUP +#line 281 "glcpp/glcpp-lex.l" +{ + return yytext[0]; +} + YY_BREAK +case 39: +YY_RULE_SETUP +#line 285 "glcpp/glcpp-lex.l" +{ + yylval->str = talloc_strdup (yyextra, yytext); + return OTHER; +} + YY_BREAK +case 40: +YY_RULE_SETUP +#line 290 "glcpp/glcpp-lex.l" +{ + if (yyextra->space_tokens) { + return SPACE; + } +} + YY_BREAK +case 41: +/* rule 41 can match eol */ +YY_RULE_SETUP +#line 296 "glcpp/glcpp-lex.l" +{ + yyextra->lexing_if = 0; + yylineno++; + yycolumn = 0; + return NEWLINE; +} + YY_BREAK +/* Handle missing newline at EOF. */ +case YY_STATE_EOF(INITIAL): +#line 304 "glcpp/glcpp-lex.l" +{ + BEGIN DONE; /* Don't keep matching this rule forever. */ + yyextra->lexing_if = 0; + return NEWLINE; +} + YY_BREAK +/* We don't actually use the UNREACHABLE start condition. We + only have this action here so that we can pretend to call some + generated functions, (to avoid "defined but not used" + warnings. */ +case 42: +YY_RULE_SETUP +#line 314 "glcpp/glcpp-lex.l" +{ + unput('.'); + yy_top_state(yyextra); +} + YY_BREAK +case 43: +YY_RULE_SETUP +#line 319 "glcpp/glcpp-lex.l" +ECHO; + YY_BREAK +#line 1489 "glcpp/glcpp-lex.c" + case YY_STATE_EOF(DONE): + case YY_STATE_EOF(COMMENT): + case YY_STATE_EOF(UNREACHABLE): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * glcpp_lex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( glcpp_wrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of glcpp_lex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + glcpp_restart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) glcpp_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + yy_current_state += YY_AT_BOL(); + + yyg->yy_state_ptr = yyg->yy_state_buf; + *yyg->yy_state_ptr++ = yy_current_state; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 163 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *yyg->yy_state_ptr++ = yy_current_state; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + + register YY_CHAR yy_c = 1; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 163 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 162); + if ( ! yy_is_jam ) + *yyg->yy_state_ptr++ = yy_current_state; + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) +{ + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_cp = yyg->yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yyg->yy_hold_char; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yyg->yy_n_chars + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + yyg->yytext_ptr = yy_bp; + yyg->yy_hold_char = *yy_cp; + yyg->yy_c_buf_p = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + glcpp_restart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( glcpp_wrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void glcpp_restart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + glcpp_ensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + glcpp__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + glcpp__init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + glcpp__load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void glcpp__switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * glcpp_pop_buffer_state(); + * glcpp_push_buffer_state(new_buffer); + */ + glcpp_ensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + glcpp__load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (glcpp_wrap()) processing, but the only time this flag + * is looked at is after glcpp_wrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void glcpp__load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE glcpp__create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) glcpp_alloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in glcpp__create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) glcpp_alloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in glcpp__create_buffer()" ); + + b->yy_is_our_buffer = 1; + + glcpp__init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with glcpp__create_buffer() + * @param yyscanner The scanner object. + */ + void glcpp__delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + glcpp_free((void *) b->yy_ch_buf ,yyscanner ); + + glcpp_free((void *) b ,yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a glcpp_restart() or at EOF. + */ + static void glcpp__init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + glcpp__flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then glcpp__init_buffer was _probably_ + * called from glcpp_restart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void glcpp__flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + glcpp__load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void glcpp_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + glcpp_ensure_buffer_stack(yyscanner); + + /* This block is copied from glcpp__switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from glcpp__switch_to_buffer. */ + glcpp__load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void glcpp_pop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + glcpp__delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + glcpp__load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void glcpp_ensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)glcpp_alloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in glcpp_ensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)glcpp_realloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in glcpp_ensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE glcpp__scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) glcpp_alloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in glcpp__scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + glcpp__switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to glcpp_lex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * glcpp__scan_bytes() instead. + */ +YY_BUFFER_STATE glcpp__scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return glcpp__scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to glcpp_lex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE glcpp__scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) glcpp_alloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in glcpp__scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = glcpp__scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in glcpp__scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + + static void yy_push_state (int new_state , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth ) + { + yy_size_t new_size; + + yyg->yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yyg->yy_start_stack_depth * sizeof( int ); + + if ( ! yyg->yy_start_stack ) + yyg->yy_start_stack = (int *) glcpp_alloc(new_size ,yyscanner ); + + else + yyg->yy_start_stack = (int *) glcpp_realloc((void *) yyg->yy_start_stack,new_size ,yyscanner ); + + if ( ! yyg->yy_start_stack ) + YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); + } + + yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); +} + + static void yy_pop_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( --yyg->yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]); +} + + static int yy_top_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1]; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE glcpp_get_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int glcpp_get_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int glcpp_get_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *glcpp_get_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *glcpp_get_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int glcpp_get_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *glcpp_get_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void glcpp_set_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void glcpp_set_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "glcpp_set_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void glcpp_set_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "glcpp_set_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see glcpp__switch_to_buffer + */ +void glcpp_set_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void glcpp_set_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int glcpp_get_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void glcpp_set_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * glcpp_get_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void glcpp_set_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *glcpp_get_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void glcpp_set_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* glcpp_lex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int glcpp_lex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) glcpp_alloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* glcpp_lex_init_extra has the same functionality as glcpp_lex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to glcpp_alloc in + * the yyextra field. + */ + +int glcpp_lex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + glcpp_set_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) glcpp_alloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + glcpp_set_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from glcpp_lex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + + yyg->yy_state_buf = 0; + yyg->yy_state_ptr = 0; + yyg->yy_full_match = 0; + yyg->yy_lp = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * glcpp_lex_init() + */ + return 0; +} + +/* glcpp_lex_destroy is for both reentrant and non-reentrant scanners. */ +int glcpp_lex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + glcpp__delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + glcpp_pop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + glcpp_free(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + glcpp_free(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + glcpp_free ( yyg->yy_state_buf , yyscanner); + yyg->yy_state_buf = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * glcpp_lex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + glcpp_free ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *glcpp_alloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *glcpp_realloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void glcpp_free (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see glcpp_realloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 319 "glcpp/glcpp-lex.l" + + + +void +glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader) +{ + glcpp__scan_string(shader,parser->scanner); +} + diff --git a/src/glsl/glcpp/glcpp-lex.l b/src/glsl/glcpp/glcpp-lex.l new file mode 100644 index 0000000000..8eb84ed138 --- /dev/null +++ b/src/glsl/glcpp/glcpp-lex.l @@ -0,0 +1,325 @@ +%{ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "glcpp.h" +#include "glcpp-parse.h" + +/* Flex annoyingly generates some functions without making them + * static. Let's declare them here. */ +int glcpp_get_column (yyscan_t yyscanner); +void glcpp_set_column (int column_no , yyscan_t yyscanner); + +#define YY_NO_INPUT + +#define YY_USER_ACTION \ + do { \ + yylloc->first_column = yycolumn + 1; \ + yylloc->first_line = yylineno; \ + yycolumn += yyleng; \ + } while(0); + +#define YY_USER_INIT \ + do { \ + yylineno = 1; \ + yycolumn = 1; \ + yylloc->source = 0; \ + } while(0) +%} + +%option bison-bridge bison-locations reentrant noyywrap +%option extra-type="glcpp_parser_t *" +%option prefix="glcpp_" +%option stack +%option never-interactive + +%x DONE COMMENT UNREACHABLE + +SPACE [[:space:]] +NONSPACE [^[:space:]] +NEWLINE [\n] +HSPACE [ \t] +HASH ^{HSPACE}*#{HSPACE}* +IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]* +PUNCTUATION [][(){}.&*~!/%<>^|;,=+-] +OTHER [^][(){}.&*~!/%<>^|;,=#[:space:]+-]+ + +DIGITS [0-9][0-9]* +DECIMAL_INTEGER [1-9][0-9]*[uU]? +OCTAL_INTEGER 0[0-7]*[uU]? +HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]? + +%% + + /* Single-line comments */ +"//"[^\n]* { +} + + /* Multi-line comments */ +"/*" { yy_push_state(COMMENT, yyscanner); } +<COMMENT>[^*\n]* +<COMMENT>[^*\n]*\n { yylineno++; yycolumn = 0; } +<COMMENT>"*"+[^*/\n]* +<COMMENT>"*"+[^*/\n]*\n { yylineno++; yycolumn = 0; } +<COMMENT>"*"+"/" { + yy_pop_state(yyscanner); + if (yyextra->space_tokens) + return SPACE; +} + +{HASH}version { + yylval->str = talloc_strdup (yyextra, yytext); + yyextra->space_tokens = 0; + return HASH_VERSION; +} + + /* glcpp doesn't handle #extension, #version, or #pragma directives. + * Simply pass them through to the main compiler's lexer/parser. */ +{HASH}(extension|pragma)[^\n]+ { + yylval->str = talloc_strdup (yyextra, yytext); + yylineno++; + yycolumn = 0; + return OTHER; +} + +{HASH}line{HSPACE}+{DIGITS}{HSPACE}+{DIGITS}{HSPACE}*$ { + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; + yylloc->source = strtol(ptr, NULL, 0); +} + +{HASH}line{HSPACE}+{DIGITS}{HSPACE}*$ { + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; +} + +{HASH}ifdef/.*\n { + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_IFDEF; +} + +{HASH}ifndef/.*\n { + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_IFNDEF; +} + +{HASH}if/[^_a-zA-Z0-9].*\n { + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_IF; +} + +{HASH}elif/.*\n { + yyextra->lexing_if = 1; + yyextra->space_tokens = 0; + return HASH_ELIF; +} + +{HASH}else/.*\n { + yyextra->space_tokens = 0; + return HASH_ELSE; +} + +{HASH}endif/.*\n { + yyextra->space_tokens = 0; + return HASH_ENDIF; +} + + /* When skipping (due to an #if 0 or similar) consume anything + * up to a newline. We do this with less priority than any + * #if-related directive (#if, #elif, #else, #endif), but with + * more priority than any other directive or token to avoid + * any side-effects from skipped content. + * + * We use the lexing_if flag to avoid skipping any part of an + * if conditional expression. */ +[^\n]+/\n { + /* Since this rule always matches, YY_USER_ACTION gets called for it, + * wrongly incrementing yycolumn. We undo that effect here. */ + yycolumn -= yyleng; + if (yyextra->lexing_if || + yyextra->skip_stack == NULL || + yyextra->skip_stack->type == SKIP_NO_SKIP) + { + REJECT; + } +} + +{HASH}error.* { + char *p; + for (p = yytext; !isalpha(p[0]); p++); /* skip " # " */ + p += 5; /* skip "error" */ + glcpp_error(yylloc, yyextra, "#error%s", p); +} + +{HASH}define{HSPACE}+/{IDENTIFIER}"(" { + yyextra->space_tokens = 0; + return HASH_DEFINE_FUNC; +} + +{HASH}define { + yyextra->space_tokens = 0; + return HASH_DEFINE_OBJ; +} + +{HASH}undef { + yyextra->space_tokens = 0; + return HASH_UNDEF; +} + +{HASH} { + yyextra->space_tokens = 0; + return HASH; +} + +{DECIMAL_INTEGER} { + yylval->str = talloc_strdup (yyextra, yytext); + return INTEGER_STRING; +} + +{OCTAL_INTEGER} { + yylval->str = talloc_strdup (yyextra, yytext); + return INTEGER_STRING; +} + +{HEXADECIMAL_INTEGER} { + yylval->str = talloc_strdup (yyextra, yytext); + return INTEGER_STRING; +} + +"<<" { + return LEFT_SHIFT; +} + +">>" { + return RIGHT_SHIFT; +} + +"<=" { + return LESS_OR_EQUAL; +} + +">=" { + return GREATER_OR_EQUAL; +} + +"==" { + return EQUAL; +} + +"!=" { + return NOT_EQUAL; +} + +"&&" { + return AND; +} + +"||" { + return OR; +} + +"##" { + return PASTE; +} + +"defined" { + return DEFINED; +} + +{IDENTIFIER} { + yylval->str = talloc_strdup (yyextra, yytext); + return IDENTIFIER; +} + +{PUNCTUATION} { + return yytext[0]; +} + +{OTHER}+ { + yylval->str = talloc_strdup (yyextra, yytext); + return OTHER; +} + +{HSPACE}+ { + if (yyextra->space_tokens) { + return SPACE; + } +} + +\n { + yyextra->lexing_if = 0; + yylineno++; + yycolumn = 0; + return NEWLINE; +} + + /* Handle missing newline at EOF. */ +<INITIAL><<EOF>> { + BEGIN DONE; /* Don't keep matching this rule forever. */ + yyextra->lexing_if = 0; + return NEWLINE; +} + + /* We don't actually use the UNREACHABLE start condition. We + only have this action here so that we can pretend to call some + generated functions, (to avoid "defined but not used" + warnings. */ +<UNREACHABLE>. { + unput('.'); + yy_top_state(yyextra); +} + +%% + +void +glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader) +{ + yy_scan_string(shader, parser->scanner); +} diff --git a/src/glsl/glcpp/glcpp-parse.c b/src/glsl/glcpp/glcpp-parse.c new file mode 100644 index 0000000000..91eb0bf972 --- /dev/null +++ b/src/glsl/glcpp/glcpp-parse.c @@ -0,0 +1,4168 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 1 + + + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 1 "glcpp/glcpp-parse.y" + +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <inttypes.h> + +#include "glcpp.h" +#include "main/core.h" /* for struct gl_extensions */ + +#define glcpp_print(stream, str) stream = talloc_strdup_append(stream, str) +#define glcpp_printf(stream, fmt, args, ...) \ + stream = talloc_asprintf_append(stream, fmt, args) + +static void +yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error); + +static void +_define_object_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *macro, + token_list_t *replacements); + +static void +_define_function_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *macro, + string_list_t *parameters, + token_list_t *replacements); + +static string_list_t * +_string_list_create (void *ctx); + +static void +_string_list_append_item (string_list_t *list, const char *str); + +static int +_string_list_contains (string_list_t *list, const char *member, int *index); + +static int +_string_list_length (string_list_t *list); + +static int +_string_list_equal (string_list_t *a, string_list_t *b); + +static argument_list_t * +_argument_list_create (void *ctx); + +static void +_argument_list_append (argument_list_t *list, token_list_t *argument); + +static int +_argument_list_length (argument_list_t *list); + +static token_list_t * +_argument_list_member_at (argument_list_t *list, int index); + +/* Note: This function talloc_steal()s the str pointer. */ +static token_t * +_token_create_str (void *ctx, int type, char *str); + +static token_t * +_token_create_ival (void *ctx, int type, int ival); + +static token_list_t * +_token_list_create (void *ctx); + +/* Note: This function adds a talloc_reference() to token. + * + * You may want to talloc_unlink any current reference if you no + * longer need it. */ +static void +_token_list_append (token_list_t *list, token_t *token); + +static void +_token_list_append_list (token_list_t *list, token_list_t *tail); + +static int +_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b); + +static active_list_t * +_active_list_push (active_list_t *list, + const char *identifier, + token_node_t *marker); + +static active_list_t * +_active_list_pop (active_list_t *list); + +int +_active_list_contains (active_list_t *list, const char *identifier); + +static void +_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list); + +static void +_glcpp_parser_expand_token_list (glcpp_parser_t *parser, + token_list_t *list); + +static void +_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser, + token_list_t *list); + +static void +_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc, + int condition); + +static void +_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc, + const char *type, int condition); + +static void +_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc); + +#define yylex glcpp_parser_lex + +static int +glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser); + +static void +glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list); + +static void +add_builtin_define(glcpp_parser_t *parser, const char *name, int value); + + + +/* Line 189 of yacc.c */ +#line 223 "glcpp/glcpp-parse.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + COMMA_FINAL = 258, + DEFINED = 259, + ELIF_EXPANDED = 260, + HASH = 261, + HASH_DEFINE_FUNC = 262, + HASH_DEFINE_OBJ = 263, + HASH_ELIF = 264, + HASH_ELSE = 265, + HASH_ENDIF = 266, + HASH_IF = 267, + HASH_IFDEF = 268, + HASH_IFNDEF = 269, + HASH_UNDEF = 270, + HASH_VERSION = 271, + IDENTIFIER = 272, + IF_EXPANDED = 273, + INTEGER = 274, + INTEGER_STRING = 275, + NEWLINE = 276, + OTHER = 277, + PLACEHOLDER = 278, + SPACE = 279, + PASTE = 280, + OR = 281, + AND = 282, + NOT_EQUAL = 283, + EQUAL = 284, + GREATER_OR_EQUAL = 285, + LESS_OR_EQUAL = 286, + RIGHT_SHIFT = 287, + LEFT_SHIFT = 288, + UNARY = 289 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 311 "glcpp/glcpp-parse.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 2 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 606 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 57 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 17 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 101 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 162 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 289 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 47, 2, 2, 2, 43, 30, 2, + 45, 46, 41, 39, 49, 40, 54, 42, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 55, + 33, 56, 34, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 50, 2, 51, 29, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 52, 28, 53, 48, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 31, 32, 35, 36, 37, 38, 44 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 4, 7, 9, 11, 13, 16, 20, + 24, 29, 36, 44, 48, 52, 55, 60, 65, 69, + 72, 75, 78, 82, 85, 87, 89, 91, 95, 99, + 103, 107, 111, 115, 119, 123, 127, 131, 135, 139, + 143, 147, 151, 155, 159, 163, 166, 169, 172, 175, + 179, 181, 185, 187, 190, 193, 194, 196, 197, 199, + 202, 207, 209, 211, 214, 216, 219, 221, 223, 225, + 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, + 247, 249, 251, 253, 255, 257, 259, 261, 263, 265, + 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, + 287, 289 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 58, 0, -1, -1, 58, 59, -1, 61, -1, 65, + -1, 60, -1, 6, 66, -1, 18, 63, 21, -1, + 5, 63, 21, -1, 8, 17, 67, 21, -1, 7, + 17, 45, 46, 67, 21, -1, 7, 17, 45, 64, + 46, 67, 21, -1, 15, 17, 21, -1, 12, 70, + 21, -1, 12, 21, -1, 13, 17, 68, 21, -1, + 14, 17, 68, 21, -1, 9, 70, 21, -1, 9, + 21, -1, 10, 21, -1, 11, 21, -1, 16, 62, + 21, -1, 6, 21, -1, 20, -1, 19, -1, 62, + -1, 63, 26, 63, -1, 63, 27, 63, -1, 63, + 28, 63, -1, 63, 29, 63, -1, 63, 30, 63, + -1, 63, 31, 63, -1, 63, 32, 63, -1, 63, + 35, 63, -1, 63, 36, 63, -1, 63, 34, 63, + -1, 63, 33, 63, -1, 63, 37, 63, -1, 63, + 38, 63, -1, 63, 40, 63, -1, 63, 39, 63, + -1, 63, 43, 63, -1, 63, 42, 63, -1, 63, + 41, 63, -1, 47, 63, -1, 48, 63, -1, 40, + 63, -1, 39, 63, -1, 45, 63, 46, -1, 17, + -1, 64, 49, 17, -1, 21, -1, 71, 21, -1, + 71, 21, -1, -1, 71, -1, -1, 71, -1, 4, + 17, -1, 4, 45, 17, 46, -1, 72, -1, 69, + -1, 70, 69, -1, 72, -1, 71, 72, -1, 17, + -1, 20, -1, 73, -1, 22, -1, 24, -1, 50, + -1, 51, -1, 45, -1, 46, -1, 52, -1, 53, + -1, 54, -1, 30, -1, 41, -1, 39, -1, 40, + -1, 48, -1, 47, -1, 42, -1, 43, -1, 38, + -1, 37, -1, 33, -1, 34, -1, 36, -1, 35, + -1, 32, -1, 31, -1, 29, -1, 28, -1, 27, + -1, 26, -1, 55, -1, 49, -1, 56, -1, 25, + -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 187, 187, 189, 193, 196, 201, 202, 206, 209, + 215, 218, 221, 224, 232, 251, 261, 266, 271, 290, + 305, 308, 311, 320, 324, 333, 338, 339, 342, 345, + 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, + 378, 381, 384, 387, 390, 393, 396, 399, 402, 405, + 411, 416, 424, 425, 429, 435, 436, 439, 441, 448, + 452, 456, 461, 467, 475, 481, 489, 493, 497, 501, + 505, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, + 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, + 541, 542 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "COMMA_FINAL", "DEFINED", + "ELIF_EXPANDED", "HASH", "HASH_DEFINE_FUNC", "HASH_DEFINE_OBJ", + "HASH_ELIF", "HASH_ELSE", "HASH_ENDIF", "HASH_IF", "HASH_IFDEF", + "HASH_IFNDEF", "HASH_UNDEF", "HASH_VERSION", "IDENTIFIER", "IF_EXPANDED", + "INTEGER", "INTEGER_STRING", "NEWLINE", "OTHER", "PLACEHOLDER", "SPACE", + "PASTE", "OR", "AND", "'|'", "'^'", "'&'", "NOT_EQUAL", "EQUAL", "'<'", + "'>'", "GREATER_OR_EQUAL", "LESS_OR_EQUAL", "RIGHT_SHIFT", "LEFT_SHIFT", + "'+'", "'-'", "'*'", "'/'", "'%'", "UNARY", "'('", "')'", "'!'", "'~'", + "','", "'['", "']'", "'{'", "'}'", "'.'", "';'", "'='", "$accept", + "input", "line", "expanded_line", "control_line", "integer_constant", + "expression", "identifier_list", "text_line", "non_directive", + "replacement_list", "junk", "conditional_token", "conditional_tokens", + "pp_tokens", "preprocessing_token", "operator", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 124, 94, + 38, 283, 284, 60, 62, 285, 286, 287, 288, 43, + 45, 42, 47, 37, 289, 40, 41, 33, 126, 44, + 91, 93, 123, 125, 46, 59, 61 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 57, 58, 58, 59, 59, 59, 59, 60, 60, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 62, 62, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 64, 64, 65, 65, 66, 67, 67, 68, 68, 69, + 69, 69, 70, 70, 71, 71, 72, 72, 72, 72, + 72, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 2, 1, 1, 1, 2, 3, 3, + 4, 6, 7, 3, 3, 2, 4, 4, 3, 2, + 2, 2, 3, 2, 1, 1, 1, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, + 1, 3, 1, 2, 2, 0, 1, 0, 1, 2, + 4, 1, 1, 2, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 66, 0, 67, 52, 69, + 70, 101, 97, 96, 95, 94, 78, 93, 92, 88, + 89, 91, 90, 87, 86, 80, 81, 79, 84, 85, + 73, 74, 83, 82, 99, 71, 72, 75, 76, 77, + 98, 100, 3, 6, 4, 5, 0, 64, 68, 25, + 24, 0, 0, 0, 0, 0, 26, 0, 23, 7, + 0, 0, 55, 0, 19, 62, 0, 61, 20, 21, + 15, 0, 57, 57, 0, 0, 0, 53, 65, 48, + 47, 0, 45, 46, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 54, 0, 0, 56, 59, 0, 18, + 63, 14, 0, 58, 0, 13, 22, 8, 49, 27, + 28, 29, 30, 31, 32, 33, 37, 36, 34, 35, + 38, 39, 41, 40, 44, 43, 42, 50, 55, 0, + 10, 0, 16, 17, 0, 55, 0, 60, 11, 0, + 51, 12 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 52, 53, 54, 66, 67, 149, 55, 69, + 115, 122, 75, 76, 116, 57, 58 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -147 +static const yytype_int16 yypact[] = +{ + -147, 112, -147, 28, -10, 55, 62, 152, -15, 59, + 192, 85, 86, 87, 51, -147, 28, -147, -147, -147, + -147, -147, -147, -147, -147, -147, -147, -147, -147, -147, + -147, -147, -147, -147, -147, -147, -147, -147, -147, -147, + -147, -147, -147, -147, -147, -147, -147, -147, -147, -147, + -147, -147, -147, -147, -147, -147, 312, -147, -147, -147, + -147, 28, 28, 28, 28, 28, -147, 428, -147, -147, + 352, 63, 392, 17, -147, -147, 232, -147, -147, -147, + -147, 272, 392, 392, 84, 89, 451, -147, -147, -147, + -147, 469, -147, -147, -147, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, -147, 60, 90, 392, -147, 96, -147, + -147, -147, 93, 392, 94, -147, -147, -147, -147, 489, + 505, 520, 534, 547, 558, 558, 18, 18, 18, 18, + 563, 563, 23, 23, -147, -147, -147, -147, 392, 32, + -147, 61, -147, -147, 110, 392, 118, -147, -147, 149, + -147, -147 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -147, -147, -147, -147, -147, 157, -11, -147, -147, -147, + -146, 92, -68, 200, 0, -7, -147 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 77, 56, 154, 77, 70, 86, 78, 15, 120, 159, + 17, 68, 19, 120, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 117, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 59, 60, 88, + 89, 90, 91, 92, 93, 106, 107, 108, 109, 110, + 111, 112, 118, 88, 110, 111, 112, 61, 62, 77, + 59, 60, 71, 63, 77, 64, 65, 147, 155, 72, + 79, 156, 123, 123, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 82, 83, 84, 125, 148, 157, 114, 88, + 126, 150, 2, 151, 152, 153, 88, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 158, 17, 18, 19, 160, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 73, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 15, + 161, 85, 17, 74, 19, 124, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 73, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 15, + 81, 0, 17, 80, 19, 0, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 73, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 15, + 0, 0, 17, 119, 19, 0, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 73, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 15, + 0, 0, 17, 121, 19, 0, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 0, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 15, + 0, 0, 17, 87, 19, 0, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 0, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 15, + 0, 0, 17, 113, 19, 0, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 0, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 15, + 0, 0, 17, 0, 19, 0, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 0, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 94, + 0, 0, 0, 0, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 127, 0, 0, 0, 0, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 0, 0, 128, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 108, 109, 110, 111, 112 +}; + +static const yytype_int16 yycheck[] = +{ + 7, 1, 148, 10, 4, 16, 21, 17, 76, 155, + 20, 21, 22, 81, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 17, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 19, 20, 56, + 61, 62, 63, 64, 65, 37, 38, 39, 40, 41, + 42, 43, 45, 70, 41, 42, 43, 39, 40, 76, + 19, 20, 17, 45, 81, 47, 48, 17, 46, 17, + 21, 49, 82, 83, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 17, 17, 17, 21, 46, 46, 45, 116, + 21, 21, 0, 17, 21, 21, 123, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 21, 20, 21, 22, 17, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 4, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 17, + 21, 14, 20, 21, 22, 83, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 4, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 17, + 10, -1, 20, 21, 22, -1, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 4, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 17, + -1, -1, 20, 21, 22, -1, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 4, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 17, + -1, -1, 20, 21, 22, -1, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, -1, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 17, + -1, -1, 20, 21, 22, -1, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, -1, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 17, + -1, -1, 20, 21, 22, -1, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, -1, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 17, + -1, -1, 20, -1, 22, -1, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, -1, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 21, + -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 21, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, -1, -1, 46, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 39, 40, 41, 42, 43 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 58, 0, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 59, 60, 61, 65, 71, 72, 73, 19, + 20, 39, 40, 45, 47, 48, 62, 63, 21, 66, + 71, 17, 17, 4, 21, 69, 70, 72, 21, 21, + 21, 70, 17, 17, 17, 62, 63, 21, 72, 63, + 63, 63, 63, 63, 21, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 21, 45, 67, 71, 17, 45, 21, + 69, 21, 68, 71, 68, 21, 21, 21, 46, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 17, 46, 64, + 21, 17, 21, 21, 67, 46, 49, 46, 21, 67, + 17, 21 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, parser, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, &yylloc, parser) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, parser); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, glcpp_parser_t *parser) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parser) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + glcpp_parser_t *parser; +#endif +{ + if (!yyvaluep) + return; + YYUSE (yylocationp); + YYUSE (parser); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, glcpp_parser_t *parser) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, parser) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + glcpp_parser_t *parser; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parser); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, glcpp_parser_t *parser) +#else +static void +yy_reduce_print (yyvsp, yylsp, yyrule, parser) + YYSTYPE *yyvsp; + YYLTYPE *yylsp; + int yyrule; + glcpp_parser_t *parser; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , parser); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, yylsp, Rule, parser); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, glcpp_parser_t *parser) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, yylocationp, parser) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + YYLTYPE *yylocationp; + glcpp_parser_t *parser; +#endif +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (parser); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (glcpp_parser_t *parser); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (glcpp_parser_t *parser) +#else +int +yyparse (parser) + glcpp_parser_t *parser; +#endif +#endif +{ +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Location data for the lookahead symbol. */ +YYLTYPE yylloc; + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls; + YYLTYPE *yylsp; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[2]; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yyls = yylsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + yylsp = yyls; + +#if YYLTYPE_IS_TRIVIAL + /* Initialize the default location before parsing starts. */ + yylloc.first_line = yylloc.last_line = 1; + yylloc.first_column = yylloc.last_column = 1; +#endif + +/* User initialization code. */ + +/* Line 1242 of yacc.c */ +#line 154 "glcpp/glcpp-parse.y" +{ + yylloc.first_line = 1; + yylloc.first_column = 1; + yylloc.last_line = 1; + yylloc.last_column = 1; + yylloc.source = 0; +} + +/* Line 1242 of yacc.c */ +#line 1616 "glcpp/glcpp-parse.c" + yylsp[0] = yylloc; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 4: + +/* Line 1455 of yacc.c */ +#line 193 "glcpp/glcpp-parse.y" + { + glcpp_print(parser->output, "\n"); + ;} + break; + + case 5: + +/* Line 1455 of yacc.c */ +#line 196 "glcpp/glcpp-parse.y" + { + _glcpp_parser_print_expanded_token_list (parser, (yyvsp[(1) - (1)].token_list)); + glcpp_print(parser->output, "\n"); + talloc_free ((yyvsp[(1) - (1)].token_list)); + ;} + break; + + case 8: + +/* Line 1455 of yacc.c */ +#line 206 "glcpp/glcpp-parse.y" + { + _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (3)]), (yyvsp[(2) - (3)].ival)); + ;} + break; + + case 9: + +/* Line 1455 of yacc.c */ +#line 209 "glcpp/glcpp-parse.y" + { + _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (3)]), "elif", (yyvsp[(2) - (3)].ival)); + ;} + break; + + case 10: + +/* Line 1455 of yacc.c */ +#line 215 "glcpp/glcpp-parse.y" + { + _define_object_macro (parser, & (yylsp[(2) - (4)]), (yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].token_list)); + ;} + break; + + case 11: + +/* Line 1455 of yacc.c */ +#line 218 "glcpp/glcpp-parse.y" + { + _define_function_macro (parser, & (yylsp[(2) - (6)]), (yyvsp[(2) - (6)].str), NULL, (yyvsp[(5) - (6)].token_list)); + ;} + break; + + case 12: + +/* Line 1455 of yacc.c */ +#line 221 "glcpp/glcpp-parse.y" + { + _define_function_macro (parser, & (yylsp[(2) - (7)]), (yyvsp[(2) - (7)].str), (yyvsp[(4) - (7)].string_list), (yyvsp[(6) - (7)].token_list)); + ;} + break; + + case 13: + +/* Line 1455 of yacc.c */ +#line 224 "glcpp/glcpp-parse.y" + { + macro_t *macro = hash_table_find (parser->defines, (yyvsp[(2) - (3)].str)); + if (macro) { + hash_table_remove (parser->defines, (yyvsp[(2) - (3)].str)); + talloc_free (macro); + } + talloc_free ((yyvsp[(2) - (3)].str)); + ;} + break; + + case 14: + +/* Line 1455 of yacc.c */ +#line 232 "glcpp/glcpp-parse.y" + { + /* Be careful to only evaluate the 'if' expression if + * we are not skipping. When we are skipping, we + * simply push a new 0-valued 'if' onto the skip + * stack. + * + * This avoids generating diagnostics for invalid + * expressions that are being skipped. */ + if (parser->skip_stack == NULL || + parser->skip_stack->type == SKIP_NO_SKIP) + { + _glcpp_parser_expand_if (parser, IF_EXPANDED, (yyvsp[(2) - (3)].token_list)); + } + else + { + _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (3)]), 0); + parser->skip_stack->type = SKIP_TO_ENDIF; + } + ;} + break; + + case 15: + +/* Line 1455 of yacc.c */ +#line 251 "glcpp/glcpp-parse.y" + { + /* #if without an expression is only an error if we + * are not skipping */ + if (parser->skip_stack == NULL || + parser->skip_stack->type == SKIP_NO_SKIP) + { + glcpp_error(& (yylsp[(1) - (2)]), parser, "#if with no expression"); + } + _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (2)]), 0); + ;} + break; + + case 16: + +/* Line 1455 of yacc.c */ +#line 261 "glcpp/glcpp-parse.y" + { + macro_t *macro = hash_table_find (parser->defines, (yyvsp[(2) - (4)].str)); + talloc_free ((yyvsp[(2) - (4)].str)); + _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (4)]), macro != NULL); + ;} + break; + + case 17: + +/* Line 1455 of yacc.c */ +#line 266 "glcpp/glcpp-parse.y" + { + macro_t *macro = hash_table_find (parser->defines, (yyvsp[(2) - (4)].str)); + talloc_free ((yyvsp[(2) - (4)].str)); + _glcpp_parser_skip_stack_push_if (parser, & (yylsp[(1) - (4)]), macro == NULL); + ;} + break; + + case 18: + +/* Line 1455 of yacc.c */ +#line 271 "glcpp/glcpp-parse.y" + { + /* Be careful to only evaluate the 'elif' expression + * if we are not skipping. When we are skipping, we + * simply change to a 0-valued 'elif' on the skip + * stack. + * + * This avoids generating diagnostics for invalid + * expressions that are being skipped. */ + if (parser->skip_stack && + parser->skip_stack->type == SKIP_TO_ELSE) + { + _glcpp_parser_expand_if (parser, ELIF_EXPANDED, (yyvsp[(2) - (3)].token_list)); + } + else + { + _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (3)]), + "elif", 0); + } + ;} + break; + + case 19: + +/* Line 1455 of yacc.c */ +#line 290 "glcpp/glcpp-parse.y" + { + /* #elif without an expression is an error unless we + * are skipping. */ + if (parser->skip_stack && + parser->skip_stack->type == SKIP_TO_ELSE) + { + glcpp_error(& (yylsp[(1) - (2)]), parser, "#elif with no expression"); + } + else + { + _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (2)]), + "elif", 0); + glcpp_warning(& (yylsp[(1) - (2)]), parser, "ignoring illegal #elif without expression"); + } + ;} + break; + + case 20: + +/* Line 1455 of yacc.c */ +#line 305 "glcpp/glcpp-parse.y" + { + _glcpp_parser_skip_stack_change_if (parser, & (yylsp[(1) - (2)]), "else", 1); + ;} + break; + + case 21: + +/* Line 1455 of yacc.c */ +#line 308 "glcpp/glcpp-parse.y" + { + _glcpp_parser_skip_stack_pop (parser, & (yylsp[(1) - (2)])); + ;} + break; + + case 22: + +/* Line 1455 of yacc.c */ +#line 311 "glcpp/glcpp-parse.y" + { + macro_t *macro = hash_table_find (parser->defines, "__VERSION__"); + if (macro) { + hash_table_remove (parser->defines, "__VERSION__"); + talloc_free (macro); + } + add_builtin_define (parser, "__VERSION__", (yyvsp[(2) - (3)].ival)); + glcpp_printf(parser->output, "#version %" PRIiMAX, (yyvsp[(2) - (3)].ival)); + ;} + break; + + case 24: + +/* Line 1455 of yacc.c */ +#line 324 "glcpp/glcpp-parse.y" + { + if (strlen ((yyvsp[(1) - (1)].str)) >= 3 && strncmp ((yyvsp[(1) - (1)].str), "0x", 2) == 0) { + (yyval.ival) = strtoll ((yyvsp[(1) - (1)].str) + 2, NULL, 16); + } else if ((yyvsp[(1) - (1)].str)[0] == '0') { + (yyval.ival) = strtoll ((yyvsp[(1) - (1)].str), NULL, 8); + } else { + (yyval.ival) = strtoll ((yyvsp[(1) - (1)].str), NULL, 10); + } + ;} + break; + + case 25: + +/* Line 1455 of yacc.c */ +#line 333 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (1)].ival); + ;} + break; + + case 27: + +/* Line 1455 of yacc.c */ +#line 339 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) || (yyvsp[(3) - (3)].ival); + ;} + break; + + case 28: + +/* Line 1455 of yacc.c */ +#line 342 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) && (yyvsp[(3) - (3)].ival); + ;} + break; + + case 29: + +/* Line 1455 of yacc.c */ +#line 345 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) | (yyvsp[(3) - (3)].ival); + ;} + break; + + case 30: + +/* Line 1455 of yacc.c */ +#line 348 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) ^ (yyvsp[(3) - (3)].ival); + ;} + break; + + case 31: + +/* Line 1455 of yacc.c */ +#line 351 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) & (yyvsp[(3) - (3)].ival); + ;} + break; + + case 32: + +/* Line 1455 of yacc.c */ +#line 354 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) != (yyvsp[(3) - (3)].ival); + ;} + break; + + case 33: + +/* Line 1455 of yacc.c */ +#line 357 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) == (yyvsp[(3) - (3)].ival); + ;} + break; + + case 34: + +/* Line 1455 of yacc.c */ +#line 360 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) >= (yyvsp[(3) - (3)].ival); + ;} + break; + + case 35: + +/* Line 1455 of yacc.c */ +#line 363 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) <= (yyvsp[(3) - (3)].ival); + ;} + break; + + case 36: + +/* Line 1455 of yacc.c */ +#line 366 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) > (yyvsp[(3) - (3)].ival); + ;} + break; + + case 37: + +/* Line 1455 of yacc.c */ +#line 369 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) < (yyvsp[(3) - (3)].ival); + ;} + break; + + case 38: + +/* Line 1455 of yacc.c */ +#line 372 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) >> (yyvsp[(3) - (3)].ival); + ;} + break; + + case 39: + +/* Line 1455 of yacc.c */ +#line 375 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) << (yyvsp[(3) - (3)].ival); + ;} + break; + + case 40: + +/* Line 1455 of yacc.c */ +#line 378 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) - (yyvsp[(3) - (3)].ival); + ;} + break; + + case 41: + +/* Line 1455 of yacc.c */ +#line 381 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) + (yyvsp[(3) - (3)].ival); + ;} + break; + + case 42: + +/* Line 1455 of yacc.c */ +#line 384 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) % (yyvsp[(3) - (3)].ival); + ;} + break; + + case 43: + +/* Line 1455 of yacc.c */ +#line 387 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) / (yyvsp[(3) - (3)].ival); + ;} + break; + + case 44: + +/* Line 1455 of yacc.c */ +#line 390 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(1) - (3)].ival) * (yyvsp[(3) - (3)].ival); + ;} + break; + + case 45: + +/* Line 1455 of yacc.c */ +#line 393 "glcpp/glcpp-parse.y" + { + (yyval.ival) = ! (yyvsp[(2) - (2)].ival); + ;} + break; + + case 46: + +/* Line 1455 of yacc.c */ +#line 396 "glcpp/glcpp-parse.y" + { + (yyval.ival) = ~ (yyvsp[(2) - (2)].ival); + ;} + break; + + case 47: + +/* Line 1455 of yacc.c */ +#line 399 "glcpp/glcpp-parse.y" + { + (yyval.ival) = - (yyvsp[(2) - (2)].ival); + ;} + break; + + case 48: + +/* Line 1455 of yacc.c */ +#line 402 "glcpp/glcpp-parse.y" + { + (yyval.ival) = + (yyvsp[(2) - (2)].ival); + ;} + break; + + case 49: + +/* Line 1455 of yacc.c */ +#line 405 "glcpp/glcpp-parse.y" + { + (yyval.ival) = (yyvsp[(2) - (3)].ival); + ;} + break; + + case 50: + +/* Line 1455 of yacc.c */ +#line 411 "glcpp/glcpp-parse.y" + { + (yyval.string_list) = _string_list_create (parser); + _string_list_append_item ((yyval.string_list), (yyvsp[(1) - (1)].str)); + talloc_steal ((yyval.string_list), (yyvsp[(1) - (1)].str)); + ;} + break; + + case 51: + +/* Line 1455 of yacc.c */ +#line 416 "glcpp/glcpp-parse.y" + { + (yyval.string_list) = (yyvsp[(1) - (3)].string_list); + _string_list_append_item ((yyval.string_list), (yyvsp[(3) - (3)].str)); + talloc_steal ((yyval.string_list), (yyvsp[(3) - (3)].str)); + ;} + break; + + case 52: + +/* Line 1455 of yacc.c */ +#line 424 "glcpp/glcpp-parse.y" + { (yyval.token_list) = NULL; ;} + break; + + case 54: + +/* Line 1455 of yacc.c */ +#line 429 "glcpp/glcpp-parse.y" + { + yyerror (& (yylsp[(1) - (2)]), parser, "Invalid tokens after #"); + ;} + break; + + case 55: + +/* Line 1455 of yacc.c */ +#line 435 "glcpp/glcpp-parse.y" + { (yyval.token_list) = NULL; ;} + break; + + case 58: + +/* Line 1455 of yacc.c */ +#line 441 "glcpp/glcpp-parse.y" + { + glcpp_warning(&(yylsp[(1) - (1)]), parser, "extra tokens at end of directive"); + ;} + break; + + case 59: + +/* Line 1455 of yacc.c */ +#line 448 "glcpp/glcpp-parse.y" + { + int v = hash_table_find (parser->defines, (yyvsp[(2) - (2)].str)) ? 1 : 0; + (yyval.token) = _token_create_ival (parser, INTEGER, v); + ;} + break; + + case 60: + +/* Line 1455 of yacc.c */ +#line 452 "glcpp/glcpp-parse.y" + { + int v = hash_table_find (parser->defines, (yyvsp[(3) - (4)].str)) ? 1 : 0; + (yyval.token) = _token_create_ival (parser, INTEGER, v); + ;} + break; + + case 62: + +/* Line 1455 of yacc.c */ +#line 461 "glcpp/glcpp-parse.y" + { + parser->space_tokens = 1; + (yyval.token_list) = _token_list_create (parser); + _token_list_append ((yyval.token_list), (yyvsp[(1) - (1)].token)); + talloc_unlink (parser, (yyvsp[(1) - (1)].token)); + ;} + break; + + case 63: + +/* Line 1455 of yacc.c */ +#line 467 "glcpp/glcpp-parse.y" + { + (yyval.token_list) = (yyvsp[(1) - (2)].token_list); + _token_list_append ((yyval.token_list), (yyvsp[(2) - (2)].token)); + talloc_unlink (parser, (yyvsp[(2) - (2)].token)); + ;} + break; + + case 64: + +/* Line 1455 of yacc.c */ +#line 475 "glcpp/glcpp-parse.y" + { + parser->space_tokens = 1; + (yyval.token_list) = _token_list_create (parser); + _token_list_append ((yyval.token_list), (yyvsp[(1) - (1)].token)); + talloc_unlink (parser, (yyvsp[(1) - (1)].token)); + ;} + break; + + case 65: + +/* Line 1455 of yacc.c */ +#line 481 "glcpp/glcpp-parse.y" + { + (yyval.token_list) = (yyvsp[(1) - (2)].token_list); + _token_list_append ((yyval.token_list), (yyvsp[(2) - (2)].token)); + talloc_unlink (parser, (yyvsp[(2) - (2)].token)); + ;} + break; + + case 66: + +/* Line 1455 of yacc.c */ +#line 489 "glcpp/glcpp-parse.y" + { + (yyval.token) = _token_create_str (parser, IDENTIFIER, (yyvsp[(1) - (1)].str)); + (yyval.token)->location = yylloc; + ;} + break; + + case 67: + +/* Line 1455 of yacc.c */ +#line 493 "glcpp/glcpp-parse.y" + { + (yyval.token) = _token_create_str (parser, INTEGER_STRING, (yyvsp[(1) - (1)].str)); + (yyval.token)->location = yylloc; + ;} + break; + + case 68: + +/* Line 1455 of yacc.c */ +#line 497 "glcpp/glcpp-parse.y" + { + (yyval.token) = _token_create_ival (parser, (yyvsp[(1) - (1)].ival), (yyvsp[(1) - (1)].ival)); + (yyval.token)->location = yylloc; + ;} + break; + + case 69: + +/* Line 1455 of yacc.c */ +#line 501 "glcpp/glcpp-parse.y" + { + (yyval.token) = _token_create_str (parser, OTHER, (yyvsp[(1) - (1)].str)); + (yyval.token)->location = yylloc; + ;} + break; + + case 70: + +/* Line 1455 of yacc.c */ +#line 505 "glcpp/glcpp-parse.y" + { + (yyval.token) = _token_create_ival (parser, SPACE, SPACE); + (yyval.token)->location = yylloc; + ;} + break; + + case 71: + +/* Line 1455 of yacc.c */ +#line 512 "glcpp/glcpp-parse.y" + { (yyval.ival) = '['; ;} + break; + + case 72: + +/* Line 1455 of yacc.c */ +#line 513 "glcpp/glcpp-parse.y" + { (yyval.ival) = ']'; ;} + break; + + case 73: + +/* Line 1455 of yacc.c */ +#line 514 "glcpp/glcpp-parse.y" + { (yyval.ival) = '('; ;} + break; + + case 74: + +/* Line 1455 of yacc.c */ +#line 515 "glcpp/glcpp-parse.y" + { (yyval.ival) = ')'; ;} + break; + + case 75: + +/* Line 1455 of yacc.c */ +#line 516 "glcpp/glcpp-parse.y" + { (yyval.ival) = '{'; ;} + break; + + case 76: + +/* Line 1455 of yacc.c */ +#line 517 "glcpp/glcpp-parse.y" + { (yyval.ival) = '}'; ;} + break; + + case 77: + +/* Line 1455 of yacc.c */ +#line 518 "glcpp/glcpp-parse.y" + { (yyval.ival) = '.'; ;} + break; + + case 78: + +/* Line 1455 of yacc.c */ +#line 519 "glcpp/glcpp-parse.y" + { (yyval.ival) = '&'; ;} + break; + + case 79: + +/* Line 1455 of yacc.c */ +#line 520 "glcpp/glcpp-parse.y" + { (yyval.ival) = '*'; ;} + break; + + case 80: + +/* Line 1455 of yacc.c */ +#line 521 "glcpp/glcpp-parse.y" + { (yyval.ival) = '+'; ;} + break; + + case 81: + +/* Line 1455 of yacc.c */ +#line 522 "glcpp/glcpp-parse.y" + { (yyval.ival) = '-'; ;} + break; + + case 82: + +/* Line 1455 of yacc.c */ +#line 523 "glcpp/glcpp-parse.y" + { (yyval.ival) = '~'; ;} + break; + + case 83: + +/* Line 1455 of yacc.c */ +#line 524 "glcpp/glcpp-parse.y" + { (yyval.ival) = '!'; ;} + break; + + case 84: + +/* Line 1455 of yacc.c */ +#line 525 "glcpp/glcpp-parse.y" + { (yyval.ival) = '/'; ;} + break; + + case 85: + +/* Line 1455 of yacc.c */ +#line 526 "glcpp/glcpp-parse.y" + { (yyval.ival) = '%'; ;} + break; + + case 86: + +/* Line 1455 of yacc.c */ +#line 527 "glcpp/glcpp-parse.y" + { (yyval.ival) = LEFT_SHIFT; ;} + break; + + case 87: + +/* Line 1455 of yacc.c */ +#line 528 "glcpp/glcpp-parse.y" + { (yyval.ival) = RIGHT_SHIFT; ;} + break; + + case 88: + +/* Line 1455 of yacc.c */ +#line 529 "glcpp/glcpp-parse.y" + { (yyval.ival) = '<'; ;} + break; + + case 89: + +/* Line 1455 of yacc.c */ +#line 530 "glcpp/glcpp-parse.y" + { (yyval.ival) = '>'; ;} + break; + + case 90: + +/* Line 1455 of yacc.c */ +#line 531 "glcpp/glcpp-parse.y" + { (yyval.ival) = LESS_OR_EQUAL; ;} + break; + + case 91: + +/* Line 1455 of yacc.c */ +#line 532 "glcpp/glcpp-parse.y" + { (yyval.ival) = GREATER_OR_EQUAL; ;} + break; + + case 92: + +/* Line 1455 of yacc.c */ +#line 533 "glcpp/glcpp-parse.y" + { (yyval.ival) = EQUAL; ;} + break; + + case 93: + +/* Line 1455 of yacc.c */ +#line 534 "glcpp/glcpp-parse.y" + { (yyval.ival) = NOT_EQUAL; ;} + break; + + case 94: + +/* Line 1455 of yacc.c */ +#line 535 "glcpp/glcpp-parse.y" + { (yyval.ival) = '^'; ;} + break; + + case 95: + +/* Line 1455 of yacc.c */ +#line 536 "glcpp/glcpp-parse.y" + { (yyval.ival) = '|'; ;} + break; + + case 96: + +/* Line 1455 of yacc.c */ +#line 537 "glcpp/glcpp-parse.y" + { (yyval.ival) = AND; ;} + break; + + case 97: + +/* Line 1455 of yacc.c */ +#line 538 "glcpp/glcpp-parse.y" + { (yyval.ival) = OR; ;} + break; + + case 98: + +/* Line 1455 of yacc.c */ +#line 539 "glcpp/glcpp-parse.y" + { (yyval.ival) = ';'; ;} + break; + + case 99: + +/* Line 1455 of yacc.c */ +#line 540 "glcpp/glcpp-parse.y" + { (yyval.ival) = ','; ;} + break; + + case 100: + +/* Line 1455 of yacc.c */ +#line 541 "glcpp/glcpp-parse.y" + { (yyval.ival) = '='; ;} + break; + + case 101: + +/* Line 1455 of yacc.c */ +#line 542 "glcpp/glcpp-parse.y" + { (yyval.ival) = PASTE; ;} + break; + + + +/* Line 1455 of yacc.c */ +#line 2643 "glcpp/glcpp-parse.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, parser, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (&yylloc, parser, yymsg); + } + else + { + yyerror (&yylloc, parser, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + yyerror_range[0] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, parser); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[0] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[0] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, parser); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + yyerror_range[1] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the lookahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, parser, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, parser); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, parser); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 1675 of yacc.c */ +#line 545 "glcpp/glcpp-parse.y" + + +string_list_t * +_string_list_create (void *ctx) +{ + string_list_t *list; + + list = talloc (ctx, string_list_t); + list->head = NULL; + list->tail = NULL; + + return list; +} + +void +_string_list_append_item (string_list_t *list, const char *str) +{ + string_node_t *node; + + node = talloc (list, string_node_t); + node->str = talloc_strdup (node, str); + + node->next = NULL; + + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; +} + +int +_string_list_contains (string_list_t *list, const char *member, int *index) +{ + string_node_t *node; + int i; + + if (list == NULL) + return 0; + + for (i = 0, node = list->head; node; i++, node = node->next) { + if (strcmp (node->str, member) == 0) { + if (index) + *index = i; + return 1; + } + } + + return 0; +} + +int +_string_list_length (string_list_t *list) +{ + int length = 0; + string_node_t *node; + + if (list == NULL) + return 0; + + for (node = list->head; node; node = node->next) + length++; + + return length; +} + +int +_string_list_equal (string_list_t *a, string_list_t *b) +{ + string_node_t *node_a, *node_b; + + if (a == NULL && b == NULL) + return 1; + + if (a == NULL || b == NULL) + return 0; + + for (node_a = a->head, node_b = b->head; + node_a && node_b; + node_a = node_a->next, node_b = node_b->next) + { + if (strcmp (node_a->str, node_b->str)) + return 0; + } + + /* Catch the case of lists being different lengths, (which + * would cause the loop above to terminate after the shorter + * list). */ + return node_a == node_b; +} + +argument_list_t * +_argument_list_create (void *ctx) +{ + argument_list_t *list; + + list = talloc (ctx, argument_list_t); + list->head = NULL; + list->tail = NULL; + + return list; +} + +void +_argument_list_append (argument_list_t *list, token_list_t *argument) +{ + argument_node_t *node; + + node = talloc (list, argument_node_t); + node->argument = argument; + + node->next = NULL; + + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; +} + +int +_argument_list_length (argument_list_t *list) +{ + int length = 0; + argument_node_t *node; + + if (list == NULL) + return 0; + + for (node = list->head; node; node = node->next) + length++; + + return length; +} + +token_list_t * +_argument_list_member_at (argument_list_t *list, int index) +{ + argument_node_t *node; + int i; + + if (list == NULL) + return NULL; + + node = list->head; + for (i = 0; i < index; i++) { + node = node->next; + if (node == NULL) + break; + } + + if (node) + return node->argument; + + return NULL; +} + +/* Note: This function talloc_steal()s the str pointer. */ +token_t * +_token_create_str (void *ctx, int type, char *str) +{ + token_t *token; + + token = talloc (ctx, token_t); + token->type = type; + token->value.str = talloc_steal (token, str); + + return token; +} + +token_t * +_token_create_ival (void *ctx, int type, int ival) +{ + token_t *token; + + token = talloc (ctx, token_t); + token->type = type; + token->value.ival = ival; + + return token; +} + +token_list_t * +_token_list_create (void *ctx) +{ + token_list_t *list; + + list = talloc (ctx, token_list_t); + list->head = NULL; + list->tail = NULL; + list->non_space_tail = NULL; + + return list; +} + +void +_token_list_append (token_list_t *list, token_t *token) +{ + token_node_t *node; + + node = talloc (list, token_node_t); + node->token = talloc_reference (list, token); + + node->next = NULL; + + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; + if (token->type != SPACE) + list->non_space_tail = node; +} + +void +_token_list_append_list (token_list_t *list, token_list_t *tail) +{ + if (tail == NULL || tail->head == NULL) + return; + + if (list->head == NULL) { + list->head = tail->head; + } else { + list->tail->next = tail->head; + } + + list->tail = tail->tail; + list->non_space_tail = tail->non_space_tail; +} + +static token_list_t * +_token_list_copy (void *ctx, token_list_t *other) +{ + token_list_t *copy; + token_node_t *node; + + if (other == NULL) + return NULL; + + copy = _token_list_create (ctx); + for (node = other->head; node; node = node->next) + _token_list_append (copy, node->token); + + return copy; +} + +static void +_token_list_trim_trailing_space (token_list_t *list) +{ + token_node_t *tail, *next; + + if (list->non_space_tail) { + tail = list->non_space_tail->next; + list->non_space_tail->next = NULL; + list->tail = list->non_space_tail; + + while (tail) { + next = tail->next; + talloc_free (tail); + tail = next; + } + } +} + +int +_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b) +{ + token_node_t *node_a, *node_b; + + node_a = a->head; + node_b = b->head; + + while (1) + { + if (node_a == NULL && node_b == NULL) + break; + + if (node_a == NULL || node_b == NULL) + return 0; + + if (node_a->token->type == SPACE) { + node_a = node_a->next; + continue; + } + + if (node_b->token->type == SPACE) { + node_b = node_b->next; + continue; + } + + if (node_a->token->type != node_b->token->type) + return 0; + + switch (node_a->token->type) { + case INTEGER: + if (node_a->token->value.ival != + node_b->token->value.ival) + { + return 0; + } + break; + case IDENTIFIER: + case INTEGER_STRING: + case OTHER: + if (strcmp (node_a->token->value.str, + node_b->token->value.str)) + { + return 0; + } + break; + } + + node_a = node_a->next; + node_b = node_b->next; + } + + return 1; +} + +static void +_token_print (char **out, token_t *token) +{ + if (token->type < 256) { + glcpp_printf (*out, "%c", token->type); + return; + } + + switch (token->type) { + case INTEGER: + glcpp_printf (*out, "%" PRIiMAX, token->value.ival); + break; + case IDENTIFIER: + case INTEGER_STRING: + case OTHER: + glcpp_print (*out, token->value.str); + break; + case SPACE: + glcpp_print (*out, " "); + break; + case LEFT_SHIFT: + glcpp_print (*out, "<<"); + break; + case RIGHT_SHIFT: + glcpp_print (*out, ">>"); + break; + case LESS_OR_EQUAL: + glcpp_print (*out, "<="); + break; + case GREATER_OR_EQUAL: + glcpp_print (*out, ">="); + break; + case EQUAL: + glcpp_print (*out, "=="); + break; + case NOT_EQUAL: + glcpp_print (*out, "!="); + break; + case AND: + glcpp_print (*out, "&&"); + break; + case OR: + glcpp_print (*out, "||"); + break; + case PASTE: + glcpp_print (*out, "##"); + break; + case COMMA_FINAL: + glcpp_print (*out, ","); + break; + case PLACEHOLDER: + /* Nothing to print. */ + break; + default: + assert(!"Error: Don't know how to print token."); + break; + } +} + +/* Return a new token (talloc()ed off of 'token') formed by pasting + * 'token' and 'other'. Note that this function may return 'token' or + * 'other' directly rather than allocating anything new. + * + * Caution: Only very cursory error-checking is performed to see if + * the final result is a valid single token. */ +static token_t * +_token_paste (glcpp_parser_t *parser, token_t *token, token_t *other) +{ + token_t *combined = NULL; + + /* Pasting a placeholder onto anything makes no change. */ + if (other->type == PLACEHOLDER) + return token; + + /* When 'token' is a placeholder, just return 'other'. */ + if (token->type == PLACEHOLDER) + return other; + + /* A very few single-character punctuators can be combined + * with another to form a multi-character punctuator. */ + switch (token->type) { + case '<': + if (other->type == '<') + combined = _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT); + else if (other->type == '=') + combined = _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL); + break; + case '>': + if (other->type == '>') + combined = _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT); + else if (other->type == '=') + combined = _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL); + break; + case '=': + if (other->type == '=') + combined = _token_create_ival (token, EQUAL, EQUAL); + break; + case '!': + if (other->type == '=') + combined = _token_create_ival (token, NOT_EQUAL, NOT_EQUAL); + break; + case '&': + if (other->type == '&') + combined = _token_create_ival (token, AND, AND); + break; + case '|': + if (other->type == '|') + combined = _token_create_ival (token, OR, OR); + break; + } + + if (combined != NULL) { + /* Inherit the location from the first token */ + combined->location = token->location; + return combined; + } + + /* Two string-valued tokens can usually just be mashed + * together. + * + * XXX: This isn't actually legitimate. Several things here + * should result in a diagnostic since the result cannot be a + * valid, single pre-processing token. For example, pasting + * "123" and "abc" is not legal, but we don't catch that + * here. */ + if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) && + (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING)) + { + char *str; + + str = talloc_asprintf (token, "%s%s", token->value.str, + other->value.str); + combined = _token_create_str (token, token->type, str); + combined->location = token->location; + return combined; + } + + glcpp_error (&token->location, parser, ""); + glcpp_print (parser->info_log, "Pasting \""); + _token_print (&parser->info_log, token); + glcpp_print (parser->info_log, "\" and \""); + _token_print (&parser->info_log, other); + glcpp_print (parser->info_log, "\" does not give a valid preprocessing token.\n"); + + return token; +} + +static void +_token_list_print (glcpp_parser_t *parser, token_list_t *list) +{ + token_node_t *node; + + if (list == NULL) + return; + + for (node = list->head; node; node = node->next) + _token_print (&parser->output, node->token); +} + +void +yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error) +{ + glcpp_error(locp, parser, "%s", error); +} + +static void add_builtin_define(glcpp_parser_t *parser, + const char *name, int value) +{ + token_t *tok; + token_list_t *list; + + tok = _token_create_ival (parser, INTEGER, value); + + list = _token_list_create(parser); + _token_list_append(list, tok); + _define_object_macro(parser, NULL, name, list); + + talloc_unlink(parser, tok); +} + +glcpp_parser_t * +glcpp_parser_create (const struct gl_extensions *extensions) +{ + glcpp_parser_t *parser; + int language_version; + + parser = talloc (NULL, glcpp_parser_t); + + glcpp_lex_init_extra (parser, &parser->scanner); + parser->defines = hash_table_ctor (32, hash_table_string_hash, + hash_table_string_compare); + parser->active = NULL; + parser->lexing_if = 0; + parser->space_tokens = 1; + parser->newline_as_space = 0; + parser->in_control_line = 0; + parser->paren_count = 0; + + parser->skip_stack = NULL; + + parser->lex_from_list = NULL; + parser->lex_from_node = NULL; + + parser->output = talloc_strdup(parser, ""); + parser->info_log = talloc_strdup(parser, ""); + parser->error = 0; + + /* Add pre-defined macros. */ + add_builtin_define(parser, "GL_ARB_draw_buffers", 1); + add_builtin_define(parser, "GL_ARB_texture_rectangle", 1); + + if (extensions != NULL) { + if (extensions->EXT_texture_array) { + add_builtin_define(parser, "GL_EXT_texture_array", 1); + } + + if (extensions->ARB_fragment_coord_conventions) + add_builtin_define(parser, "GL_ARB_fragment_coord_conventions", + 1); + } + + language_version = 110; + add_builtin_define(parser, "__VERSION__", language_version); + + return parser; +} + +int +glcpp_parser_parse (glcpp_parser_t *parser) +{ + return yyparse (parser); +} + +void +glcpp_parser_destroy (glcpp_parser_t *parser) +{ + glcpp_lex_destroy (parser->scanner); + hash_table_dtor (parser->defines); + talloc_free (parser); +} + +typedef enum function_status +{ + FUNCTION_STATUS_SUCCESS, + FUNCTION_NOT_A_FUNCTION, + FUNCTION_UNBALANCED_PARENTHESES +} function_status_t; + +/* Find a set of function-like macro arguments by looking for a + * balanced set of parentheses. + * + * When called, 'node' should be the opening-parenthesis token, (or + * perhaps preceeding SPACE tokens). Upon successful return *last will + * be the last consumed node, (corresponding to the closing right + * parenthesis). + * + * Return values: + * + * FUNCTION_STATUS_SUCCESS: + * + * Successfully parsed a set of function arguments. + * + * FUNCTION_NOT_A_FUNCTION: + * + * Macro name not followed by a '('. This is not an error, but + * simply that the macro name should be treated as a non-macro. + * + * FUNCTION_UNBALANCED_PARENTHESES + * + * Macro name is not followed by a balanced set of parentheses. + */ +static function_status_t +_arguments_parse (argument_list_t *arguments, + token_node_t *node, + token_node_t **last) +{ + token_list_t *argument; + int paren_count; + + node = node->next; + + /* Ignore whitespace before first parenthesis. */ + while (node && node->token->type == SPACE) + node = node->next; + + if (node == NULL || node->token->type != '(') + return FUNCTION_NOT_A_FUNCTION; + + node = node->next; + + argument = _token_list_create (arguments); + _argument_list_append (arguments, argument); + + for (paren_count = 1; node; node = node->next) { + if (node->token->type == '(') + { + paren_count++; + } + else if (node->token->type == ')') + { + paren_count--; + if (paren_count == 0) + break; + } + + if (node->token->type == ',' && + paren_count == 1) + { + _token_list_trim_trailing_space (argument); + argument = _token_list_create (arguments); + _argument_list_append (arguments, argument); + } + else { + if (argument->head == NULL) { + /* Don't treat initial whitespace as + * part of the arguement. */ + if (node->token->type == SPACE) + continue; + } + _token_list_append (argument, node->token); + } + } + + if (paren_count) + return FUNCTION_UNBALANCED_PARENTHESES; + + *last = node; + + return FUNCTION_STATUS_SUCCESS; +} + +static token_list_t * +_token_list_create_with_one_space (void *ctx) +{ + token_list_t *list; + token_t *space; + + list = _token_list_create (ctx); + space = _token_create_ival (list, SPACE, SPACE); + _token_list_append (list, space); + + return list; +} + +static void +_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list) +{ + token_list_t *expanded; + token_t *token; + + expanded = _token_list_create (parser); + token = _token_create_ival (parser, type, type); + _token_list_append (expanded, token); + _glcpp_parser_expand_token_list (parser, list); + _token_list_append_list (expanded, list); + glcpp_parser_lex_from (parser, expanded); +} + +/* This is a helper function that's essentially part of the + * implementation of _glcpp_parser_expand_node. It shouldn't be called + * except for by that function. + * + * Returns NULL if node is a simple token with no expansion, (that is, + * although 'node' corresponds to an identifier defined as a + * function-like macro, it is not followed with a parenthesized + * argument list). + * + * Compute the complete expansion of node (which is a function-like + * macro) and subsequent nodes which are arguments. + * + * Returns the token list that results from the expansion and sets + * *last to the last node in the list that was consumed by the + * expansion. Specifically, *last will be set as follows: as the + * token of the closing right parenthesis. + */ +static token_list_t * +_glcpp_parser_expand_function (glcpp_parser_t *parser, + token_node_t *node, + token_node_t **last) + +{ + macro_t *macro; + const char *identifier; + argument_list_t *arguments; + function_status_t status; + token_list_t *substituted; + int parameter_index; + + identifier = node->token->value.str; + + macro = hash_table_find (parser->defines, identifier); + + assert (macro->is_function); + + arguments = _argument_list_create (parser); + status = _arguments_parse (arguments, node, last); + + switch (status) { + case FUNCTION_STATUS_SUCCESS: + break; + case FUNCTION_NOT_A_FUNCTION: + return NULL; + case FUNCTION_UNBALANCED_PARENTHESES: + glcpp_error (&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier); + return NULL; + } + + /* Replace a macro defined as empty with a SPACE token. */ + if (macro->replacements == NULL) { + talloc_free (arguments); + return _token_list_create_with_one_space (parser); + } + + if (! ((_argument_list_length (arguments) == + _string_list_length (macro->parameters)) || + (_string_list_length (macro->parameters) == 0 && + _argument_list_length (arguments) == 1 && + arguments->head->argument->head == NULL))) + { + glcpp_error (&node->token->location, parser, + "Error: macro %s invoked with %d arguments (expected %d)\n", + identifier, + _argument_list_length (arguments), + _string_list_length (macro->parameters)); + return NULL; + } + + /* Perform argument substitution on the replacement list. */ + substituted = _token_list_create (arguments); + + for (node = macro->replacements->head; node; node = node->next) + { + if (node->token->type == IDENTIFIER && + _string_list_contains (macro->parameters, + node->token->value.str, + ¶meter_index)) + { + token_list_t *argument; + argument = _argument_list_member_at (arguments, + parameter_index); + /* Before substituting, we expand the argument + * tokens, or append a placeholder token for + * an empty argument. */ + if (argument->head) { + token_list_t *expanded_argument; + expanded_argument = _token_list_copy (parser, + argument); + _glcpp_parser_expand_token_list (parser, + expanded_argument); + _token_list_append_list (substituted, + expanded_argument); + } else { + token_t *new_token; + + new_token = _token_create_ival (substituted, + PLACEHOLDER, + PLACEHOLDER); + _token_list_append (substituted, new_token); + } + } else { + _token_list_append (substituted, node->token); + } + } + + /* After argument substitution, and before further expansion + * below, implement token pasting. */ + + _token_list_trim_trailing_space (substituted); + + node = substituted->head; + while (node) + { + token_node_t *next_non_space; + + /* Look ahead for a PASTE token, skipping space. */ + next_non_space = node->next; + while (next_non_space && next_non_space->token->type == SPACE) + next_non_space = next_non_space->next; + + if (next_non_space == NULL) + break; + + if (next_non_space->token->type != PASTE) { + node = next_non_space; + continue; + } + + /* Now find the next non-space token after the PASTE. */ + next_non_space = next_non_space->next; + while (next_non_space && next_non_space->token->type == SPACE) + next_non_space = next_non_space->next; + + if (next_non_space == NULL) { + yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n"); + return NULL; + } + + node->token = _token_paste (parser, node->token, next_non_space->token); + node->next = next_non_space->next; + if (next_non_space == substituted->tail) + substituted->tail = node; + + node = node->next; + } + + substituted->non_space_tail = substituted->tail; + + return substituted; +} + +/* Compute the complete expansion of node, (and subsequent nodes after + * 'node' in the case that 'node' is a function-like macro and + * subsequent nodes are arguments). + * + * Returns NULL if node is a simple token with no expansion. + * + * Otherwise, returns the token list that results from the expansion + * and sets *last to the last node in the list that was consumed by + * the expansion. Specifically, *last will be set as follows: + * + * As 'node' in the case of object-like macro expansion. + * + * As the token of the closing right parenthesis in the case of + * function-like macro expansion. + */ +static token_list_t * +_glcpp_parser_expand_node (glcpp_parser_t *parser, + token_node_t *node, + token_node_t **last) +{ + token_t *token = node->token; + const char *identifier; + macro_t *macro; + + /* We only expand identifiers */ + if (token->type != IDENTIFIER) { + /* We change any COMMA into a COMMA_FINAL to prevent + * it being mistaken for an argument separator + * later. */ + if (token->type == ',') { + token->type = COMMA_FINAL; + token->value.ival = COMMA_FINAL; + } + + return NULL; + } + + /* Look up this identifier in the hash table. */ + identifier = token->value.str; + macro = hash_table_find (parser->defines, identifier); + + /* Not a macro, so no expansion needed. */ + if (macro == NULL) + return NULL; + + /* Finally, don't expand this macro if we're already actively + * expanding it, (to avoid infinite recursion). */ + if (_active_list_contains (parser->active, identifier)) { + /* We change the token type here from IDENTIFIER to + * OTHER to prevent any future expansion of this + * unexpanded token. */ + char *str; + token_list_t *expansion; + token_t *final; + + str = talloc_strdup (parser, token->value.str); + final = _token_create_str (parser, OTHER, str); + expansion = _token_list_create (parser); + _token_list_append (expansion, final); + *last = node; + return expansion; + } + + if (! macro->is_function) + { + *last = node; + + /* Replace a macro defined as empty with a SPACE token. */ + if (macro->replacements == NULL) + return _token_list_create_with_one_space (parser); + + return _token_list_copy (parser, macro->replacements); + } + + return _glcpp_parser_expand_function (parser, node, last); +} + +/* Push a new identifier onto the active list, returning the new list. + * + * Here, 'marker' is the token node that appears in the list after the + * expansion of 'identifier'. That is, when the list iterator begins + * examinging 'marker', then it is time to pop this node from the + * active stack. + */ +active_list_t * +_active_list_push (active_list_t *list, + const char *identifier, + token_node_t *marker) +{ + active_list_t *node; + + node = talloc (list, active_list_t); + node->identifier = talloc_strdup (node, identifier); + node->marker = marker; + node->next = list; + + return node; +} + +active_list_t * +_active_list_pop (active_list_t *list) +{ + active_list_t *node = list; + + if (node == NULL) + return NULL; + + node = list->next; + talloc_free (list); + + return node; +} + +int +_active_list_contains (active_list_t *list, const char *identifier) +{ + active_list_t *node; + + if (list == NULL) + return 0; + + for (node = list; node; node = node->next) + if (strcmp (node->identifier, identifier) == 0) + return 1; + + return 0; +} + +/* Walk over the token list replacing nodes with their expansion. + * Whenever nodes are expanded the walking will walk over the new + * nodes, continuing to expand as necessary. The results are placed in + * 'list' itself; + */ +static void +_glcpp_parser_expand_token_list (glcpp_parser_t *parser, + token_list_t *list) +{ + token_node_t *node_prev; + token_node_t *node, *last = NULL; + token_list_t *expansion; + + if (list == NULL) + return; + + _token_list_trim_trailing_space (list); + + node_prev = NULL; + node = list->head; + + while (node) { + + while (parser->active && parser->active->marker == node) + parser->active = _active_list_pop (parser->active); + + /* Find the expansion for node, which will replace all + * nodes from node to last, inclusive. */ + expansion = _glcpp_parser_expand_node (parser, node, &last); + if (expansion) { + token_node_t *n; + + for (n = node; n != last->next; n = n->next) + while (parser->active && + parser->active->marker == n) + { + parser->active = _active_list_pop (parser->active); + } + + parser->active = _active_list_push (parser->active, + node->token->value.str, + last->next); + + /* Splice expansion into list, supporting a + * simple deletion if the expansion is + * empty. */ + if (expansion->head) { + if (node_prev) + node_prev->next = expansion->head; + else + list->head = expansion->head; + expansion->tail->next = last->next; + if (last == list->tail) + list->tail = expansion->tail; + } else { + if (node_prev) + node_prev->next = last->next; + else + list->head = last->next; + if (last == list->tail) + list->tail = NULL; + } + } else { + node_prev = node; + } + node = node_prev ? node_prev->next : list->head; + } + + while (parser->active) + parser->active = _active_list_pop (parser->active); + + list->non_space_tail = list->tail; +} + +void +_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser, + token_list_t *list) +{ + if (list == NULL) + return; + + _glcpp_parser_expand_token_list (parser, list); + + _token_list_trim_trailing_space (list); + + _token_list_print (parser, list); +} + +static void +_check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc, + const char *identifier) +{ + /* According to the GLSL specification, macro names starting with "__" + * or "GL_" are reserved for future use. So, don't allow them. + */ + if (strncmp(identifier, "__", 2) == 0) { + glcpp_error (loc, parser, "Macro names starting with \"__\" are reserved.\n"); + } + if (strncmp(identifier, "GL_", 3) == 0) { + glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n"); + } +} + +static int +_macro_equal (macro_t *a, macro_t *b) +{ + if (a->is_function != b->is_function) + return 0; + + if (a->is_function) { + if (! _string_list_equal (a->parameters, b->parameters)) + return 0; + } + + return _token_list_equal_ignoring_space (a->replacements, + b->replacements); +} + +void +_define_object_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *identifier, + token_list_t *replacements) +{ + macro_t *macro, *previous; + + if (loc != NULL) + _check_for_reserved_macro_name(parser, loc, identifier); + + macro = talloc (parser, macro_t); + + macro->is_function = 0; + macro->parameters = NULL; + macro->identifier = talloc_strdup (macro, identifier); + macro->replacements = talloc_steal (macro, replacements); + + previous = hash_table_find (parser->defines, identifier); + if (previous) { + if (_macro_equal (macro, previous)) { + talloc_free (macro); + return; + } + glcpp_error (loc, parser, "Redefinition of macro %s\n", + identifier); + } + + hash_table_insert (parser->defines, macro, identifier); +} + +void +_define_function_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *identifier, + string_list_t *parameters, + token_list_t *replacements) +{ + macro_t *macro, *previous; + + _check_for_reserved_macro_name(parser, loc, identifier); + + macro = talloc (parser, macro_t); + + macro->is_function = 1; + macro->parameters = talloc_steal (macro, parameters); + macro->identifier = talloc_strdup (macro, identifier); + macro->replacements = talloc_steal (macro, replacements); + + previous = hash_table_find (parser->defines, identifier); + if (previous) { + if (_macro_equal (macro, previous)) { + talloc_free (macro); + return; + } + glcpp_error (loc, parser, "Redefinition of macro %s\n", + identifier); + } + + hash_table_insert (parser->defines, macro, identifier); +} + +static int +glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser) +{ + token_node_t *node; + int ret; + + if (parser->lex_from_list == NULL) { + ret = glcpp_lex (yylval, yylloc, parser->scanner); + + /* XXX: This ugly block of code exists for the sole + * purpose of converting a NEWLINE token into a SPACE + * token, but only in the case where we have seen a + * function-like macro name, but have not yet seen its + * closing parenthesis. + * + * There's perhaps a more compact way to do this with + * mid-rule actions in the grammar. + * + * I'm definitely not pleased with the complexity of + * this code here. + */ + if (parser->newline_as_space) + { + if (ret == '(') { + parser->paren_count++; + } else if (ret == ')') { + parser->paren_count--; + if (parser->paren_count == 0) + parser->newline_as_space = 0; + } else if (ret == NEWLINE) { + ret = SPACE; + } else if (ret != SPACE) { + if (parser->paren_count == 0) + parser->newline_as_space = 0; + } + } + else if (parser->in_control_line) + { + if (ret == NEWLINE) + parser->in_control_line = 0; + } + else if (ret == HASH_DEFINE_OBJ || ret == HASH_DEFINE_FUNC || + ret == HASH_UNDEF || ret == HASH_IF || + ret == HASH_IFDEF || ret == HASH_IFNDEF || + ret == HASH_ELIF || ret == HASH_ELSE || + ret == HASH_ENDIF || ret == HASH) + { + parser->in_control_line = 1; + } + else if (ret == IDENTIFIER) + { + macro_t *macro; + macro = hash_table_find (parser->defines, + yylval->str); + if (macro && macro->is_function) { + parser->newline_as_space = 1; + parser->paren_count = 0; + } + } + + return ret; + } + + node = parser->lex_from_node; + + if (node == NULL) { + talloc_free (parser->lex_from_list); + parser->lex_from_list = NULL; + return NEWLINE; + } + + *yylval = node->token->value; + ret = node->token->type; + + parser->lex_from_node = node->next; + + return ret; +} + +static void +glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list) +{ + token_node_t *node; + + assert (parser->lex_from_list == NULL); + + /* Copy list, eliminating any space tokens. */ + parser->lex_from_list = _token_list_create (parser); + + for (node = list->head; node; node = node->next) { + if (node->token->type == SPACE) + continue; + _token_list_append (parser->lex_from_list, node->token); + } + + talloc_free (list); + + parser->lex_from_node = parser->lex_from_list->head; + + /* It's possible the list consisted of nothing but whitespace. */ + if (parser->lex_from_node == NULL) { + talloc_free (parser->lex_from_list); + parser->lex_from_list = NULL; + } +} + +static void +_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc, + int condition) +{ + skip_type_t current = SKIP_NO_SKIP; + skip_node_t *node; + + if (parser->skip_stack) + current = parser->skip_stack->type; + + node = talloc (parser, skip_node_t); + node->loc = *loc; + + if (current == SKIP_NO_SKIP) { + if (condition) + node->type = SKIP_NO_SKIP; + else + node->type = SKIP_TO_ELSE; + } else { + node->type = SKIP_TO_ENDIF; + } + + node->next = parser->skip_stack; + parser->skip_stack = node; +} + +static void +_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc, + const char *type, int condition) +{ + if (parser->skip_stack == NULL) { + glcpp_error (loc, parser, "%s without #if\n", type); + return; + } + + if (parser->skip_stack->type == SKIP_TO_ELSE) { + if (condition) + parser->skip_stack->type = SKIP_NO_SKIP; + } else { + parser->skip_stack->type = SKIP_TO_ENDIF; + } +} + +static void +_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc) +{ + skip_node_t *node; + + if (parser->skip_stack == NULL) { + glcpp_error (loc, parser, "#endif without #if\n"); + return; + } + + node = parser->skip_stack; + parser->skip_stack = node->next; + talloc_free (node); +} + diff --git a/src/glsl/glcpp/glcpp-parse.h b/src/glsl/glcpp/glcpp-parse.h new file mode 100644 index 0000000000..50758930e9 --- /dev/null +++ b/src/glsl/glcpp/glcpp-parse.h @@ -0,0 +1,101 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + COMMA_FINAL = 258, + DEFINED = 259, + ELIF_EXPANDED = 260, + HASH = 261, + HASH_DEFINE_FUNC = 262, + HASH_DEFINE_OBJ = 263, + HASH_ELIF = 264, + HASH_ELSE = 265, + HASH_ENDIF = 266, + HASH_IF = 267, + HASH_IFDEF = 268, + HASH_IFNDEF = 269, + HASH_UNDEF = 270, + HASH_VERSION = 271, + IDENTIFIER = 272, + IF_EXPANDED = 273, + INTEGER = 274, + INTEGER_STRING = 275, + NEWLINE = 276, + OTHER = 277, + PLACEHOLDER = 278, + SPACE = 279, + PASTE = 280, + OR = 281, + AND = 282, + NOT_EQUAL = 283, + EQUAL = 284, + GREATER_OR_EQUAL = 285, + LESS_OR_EQUAL = 286, + RIGHT_SHIFT = 287, + LEFT_SHIFT = 288, + UNARY = 289 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + diff --git a/src/glsl/glcpp/glcpp-parse.y b/src/glsl/glcpp/glcpp-parse.y new file mode 100644 index 0000000000..3c28edf688 --- /dev/null +++ b/src/glsl/glcpp/glcpp-parse.y @@ -0,0 +1,1850 @@ +%{ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <inttypes.h> + +#include "glcpp.h" +#include "main/core.h" /* for struct gl_extensions */ + +#define glcpp_print(stream, str) stream = talloc_strdup_append(stream, str) +#define glcpp_printf(stream, fmt, args, ...) \ + stream = talloc_asprintf_append(stream, fmt, args) + +static void +yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error); + +static void +_define_object_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *macro, + token_list_t *replacements); + +static void +_define_function_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *macro, + string_list_t *parameters, + token_list_t *replacements); + +static string_list_t * +_string_list_create (void *ctx); + +static void +_string_list_append_item (string_list_t *list, const char *str); + +static int +_string_list_contains (string_list_t *list, const char *member, int *index); + +static int +_string_list_length (string_list_t *list); + +static int +_string_list_equal (string_list_t *a, string_list_t *b); + +static argument_list_t * +_argument_list_create (void *ctx); + +static void +_argument_list_append (argument_list_t *list, token_list_t *argument); + +static int +_argument_list_length (argument_list_t *list); + +static token_list_t * +_argument_list_member_at (argument_list_t *list, int index); + +/* Note: This function talloc_steal()s the str pointer. */ +static token_t * +_token_create_str (void *ctx, int type, char *str); + +static token_t * +_token_create_ival (void *ctx, int type, int ival); + +static token_list_t * +_token_list_create (void *ctx); + +/* Note: This function adds a talloc_reference() to token. + * + * You may want to talloc_unlink any current reference if you no + * longer need it. */ +static void +_token_list_append (token_list_t *list, token_t *token); + +static void +_token_list_append_list (token_list_t *list, token_list_t *tail); + +static int +_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b); + +static active_list_t * +_active_list_push (active_list_t *list, + const char *identifier, + token_node_t *marker); + +static active_list_t * +_active_list_pop (active_list_t *list); + +int +_active_list_contains (active_list_t *list, const char *identifier); + +static void +_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list); + +static void +_glcpp_parser_expand_token_list (glcpp_parser_t *parser, + token_list_t *list); + +static void +_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser, + token_list_t *list); + +static void +_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc, + int condition); + +static void +_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc, + const char *type, int condition); + +static void +_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc); + +#define yylex glcpp_parser_lex + +static int +glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser); + +static void +glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list); + +static void +add_builtin_define(glcpp_parser_t *parser, const char *name, int value); + +%} + +%pure-parser +%error-verbose + +%locations +%initial-action { + @$.first_line = 1; + @$.first_column = 1; + @$.last_line = 1; + @$.last_column = 1; + @$.source = 0; +} + +%parse-param {glcpp_parser_t *parser} +%lex-param {glcpp_parser_t *parser} + +%expect 0 +%token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_UNDEF HASH_VERSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING NEWLINE OTHER PLACEHOLDER SPACE +%token PASTE +%type <ival> expression INTEGER operator SPACE integer_constant +%type <str> IDENTIFIER INTEGER_STRING OTHER +%type <string_list> identifier_list +%type <token> preprocessing_token conditional_token +%type <token_list> pp_tokens replacement_list text_line conditional_tokens +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQUAL NOT_EQUAL +%left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL +%left LEFT_SHIFT RIGHT_SHIFT +%left '+' '-' +%left '*' '/' '%' +%right UNARY + +%% + +input: + /* empty */ +| input line +; + +line: + control_line { + glcpp_print(parser->output, "\n"); + } +| text_line { + _glcpp_parser_print_expanded_token_list (parser, $1); + glcpp_print(parser->output, "\n"); + talloc_free ($1); + } +| expanded_line +| HASH non_directive +; + +expanded_line: + IF_EXPANDED expression NEWLINE { + _glcpp_parser_skip_stack_push_if (parser, & @1, $2); + } +| ELIF_EXPANDED expression NEWLINE { + _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2); + } +; + +control_line: + HASH_DEFINE_OBJ IDENTIFIER replacement_list NEWLINE { + _define_object_macro (parser, & @2, $2, $3); + } +| HASH_DEFINE_FUNC IDENTIFIER '(' ')' replacement_list NEWLINE { + _define_function_macro (parser, & @2, $2, NULL, $5); + } +| HASH_DEFINE_FUNC IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE { + _define_function_macro (parser, & @2, $2, $4, $6); + } +| HASH_UNDEF IDENTIFIER NEWLINE { + macro_t *macro = hash_table_find (parser->defines, $2); + if (macro) { + hash_table_remove (parser->defines, $2); + talloc_free (macro); + } + talloc_free ($2); + } +| HASH_IF conditional_tokens NEWLINE { + /* Be careful to only evaluate the 'if' expression if + * we are not skipping. When we are skipping, we + * simply push a new 0-valued 'if' onto the skip + * stack. + * + * This avoids generating diagnostics for invalid + * expressions that are being skipped. */ + if (parser->skip_stack == NULL || + parser->skip_stack->type == SKIP_NO_SKIP) + { + _glcpp_parser_expand_if (parser, IF_EXPANDED, $2); + } + else + { + _glcpp_parser_skip_stack_push_if (parser, & @1, 0); + parser->skip_stack->type = SKIP_TO_ENDIF; + } + } +| HASH_IF NEWLINE { + /* #if without an expression is only an error if we + * are not skipping */ + if (parser->skip_stack == NULL || + parser->skip_stack->type == SKIP_NO_SKIP) + { + glcpp_error(& @1, parser, "#if with no expression"); + } + _glcpp_parser_skip_stack_push_if (parser, & @1, 0); + } +| HASH_IFDEF IDENTIFIER junk NEWLINE { + macro_t *macro = hash_table_find (parser->defines, $2); + talloc_free ($2); + _glcpp_parser_skip_stack_push_if (parser, & @1, macro != NULL); + } +| HASH_IFNDEF IDENTIFIER junk NEWLINE { + macro_t *macro = hash_table_find (parser->defines, $2); + talloc_free ($2); + _glcpp_parser_skip_stack_push_if (parser, & @1, macro == NULL); + } +| HASH_ELIF conditional_tokens NEWLINE { + /* Be careful to only evaluate the 'elif' expression + * if we are not skipping. When we are skipping, we + * simply change to a 0-valued 'elif' on the skip + * stack. + * + * This avoids generating diagnostics for invalid + * expressions that are being skipped. */ + if (parser->skip_stack && + parser->skip_stack->type == SKIP_TO_ELSE) + { + _glcpp_parser_expand_if (parser, ELIF_EXPANDED, $2); + } + else + { + _glcpp_parser_skip_stack_change_if (parser, & @1, + "elif", 0); + } + } +| HASH_ELIF NEWLINE { + /* #elif without an expression is an error unless we + * are skipping. */ + if (parser->skip_stack && + parser->skip_stack->type == SKIP_TO_ELSE) + { + glcpp_error(& @1, parser, "#elif with no expression"); + } + else + { + _glcpp_parser_skip_stack_change_if (parser, & @1, + "elif", 0); + glcpp_warning(& @1, parser, "ignoring illegal #elif without expression"); + } + } +| HASH_ELSE NEWLINE { + _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1); + } +| HASH_ENDIF NEWLINE { + _glcpp_parser_skip_stack_pop (parser, & @1); + } +| HASH_VERSION integer_constant NEWLINE { + macro_t *macro = hash_table_find (parser->defines, "__VERSION__"); + if (macro) { + hash_table_remove (parser->defines, "__VERSION__"); + talloc_free (macro); + } + add_builtin_define (parser, "__VERSION__", $2); + glcpp_printf(parser->output, "#version %" PRIiMAX, $2); + } +| HASH NEWLINE +; + +integer_constant: + INTEGER_STRING { + if (strlen ($1) >= 3 && strncmp ($1, "0x", 2) == 0) { + $$ = strtoll ($1 + 2, NULL, 16); + } else if ($1[0] == '0') { + $$ = strtoll ($1, NULL, 8); + } else { + $$ = strtoll ($1, NULL, 10); + } + } +| INTEGER { + $$ = $1; + } + +expression: + integer_constant +| expression OR expression { + $$ = $1 || $3; + } +| expression AND expression { + $$ = $1 && $3; + } +| expression '|' expression { + $$ = $1 | $3; + } +| expression '^' expression { + $$ = $1 ^ $3; + } +| expression '&' expression { + $$ = $1 & $3; + } +| expression NOT_EQUAL expression { + $$ = $1 != $3; + } +| expression EQUAL expression { + $$ = $1 == $3; + } +| expression GREATER_OR_EQUAL expression { + $$ = $1 >= $3; + } +| expression LESS_OR_EQUAL expression { + $$ = $1 <= $3; + } +| expression '>' expression { + $$ = $1 > $3; + } +| expression '<' expression { + $$ = $1 < $3; + } +| expression RIGHT_SHIFT expression { + $$ = $1 >> $3; + } +| expression LEFT_SHIFT expression { + $$ = $1 << $3; + } +| expression '-' expression { + $$ = $1 - $3; + } +| expression '+' expression { + $$ = $1 + $3; + } +| expression '%' expression { + $$ = $1 % $3; + } +| expression '/' expression { + $$ = $1 / $3; + } +| expression '*' expression { + $$ = $1 * $3; + } +| '!' expression %prec UNARY { + $$ = ! $2; + } +| '~' expression %prec UNARY { + $$ = ~ $2; + } +| '-' expression %prec UNARY { + $$ = - $2; + } +| '+' expression %prec UNARY { + $$ = + $2; + } +| '(' expression ')' { + $$ = $2; + } +; + +identifier_list: + IDENTIFIER { + $$ = _string_list_create (parser); + _string_list_append_item ($$, $1); + talloc_steal ($$, $1); + } +| identifier_list ',' IDENTIFIER { + $$ = $1; + _string_list_append_item ($$, $3); + talloc_steal ($$, $3); + } +; + +text_line: + NEWLINE { $$ = NULL; } +| pp_tokens NEWLINE +; + +non_directive: + pp_tokens NEWLINE { + yyerror (& @1, parser, "Invalid tokens after #"); + } +; + +replacement_list: + /* empty */ { $$ = NULL; } +| pp_tokens +; + +junk: + /* empty */ +| pp_tokens { + glcpp_warning(&@1, parser, "extra tokens at end of directive"); + } +; + +conditional_token: + /* Handle "defined" operator */ + DEFINED IDENTIFIER { + int v = hash_table_find (parser->defines, $2) ? 1 : 0; + $$ = _token_create_ival (parser, INTEGER, v); + } +| DEFINED '(' IDENTIFIER ')' { + int v = hash_table_find (parser->defines, $3) ? 1 : 0; + $$ = _token_create_ival (parser, INTEGER, v); + } +| preprocessing_token +; + +conditional_tokens: + /* Exactly the same as pp_tokens, but using conditional_token */ + conditional_token { + parser->space_tokens = 1; + $$ = _token_list_create (parser); + _token_list_append ($$, $1); + talloc_unlink (parser, $1); + } +| conditional_tokens conditional_token { + $$ = $1; + _token_list_append ($$, $2); + talloc_unlink (parser, $2); + } +; + +pp_tokens: + preprocessing_token { + parser->space_tokens = 1; + $$ = _token_list_create (parser); + _token_list_append ($$, $1); + talloc_unlink (parser, $1); + } +| pp_tokens preprocessing_token { + $$ = $1; + _token_list_append ($$, $2); + talloc_unlink (parser, $2); + } +; + +preprocessing_token: + IDENTIFIER { + $$ = _token_create_str (parser, IDENTIFIER, $1); + $$->location = yylloc; + } +| INTEGER_STRING { + $$ = _token_create_str (parser, INTEGER_STRING, $1); + $$->location = yylloc; + } +| operator { + $$ = _token_create_ival (parser, $1, $1); + $$->location = yylloc; + } +| OTHER { + $$ = _token_create_str (parser, OTHER, $1); + $$->location = yylloc; + } +| SPACE { + $$ = _token_create_ival (parser, SPACE, SPACE); + $$->location = yylloc; + } +; + +operator: + '[' { $$ = '['; } +| ']' { $$ = ']'; } +| '(' { $$ = '('; } +| ')' { $$ = ')'; } +| '{' { $$ = '{'; } +| '}' { $$ = '}'; } +| '.' { $$ = '.'; } +| '&' { $$ = '&'; } +| '*' { $$ = '*'; } +| '+' { $$ = '+'; } +| '-' { $$ = '-'; } +| '~' { $$ = '~'; } +| '!' { $$ = '!'; } +| '/' { $$ = '/'; } +| '%' { $$ = '%'; } +| LEFT_SHIFT { $$ = LEFT_SHIFT; } +| RIGHT_SHIFT { $$ = RIGHT_SHIFT; } +| '<' { $$ = '<'; } +| '>' { $$ = '>'; } +| LESS_OR_EQUAL { $$ = LESS_OR_EQUAL; } +| GREATER_OR_EQUAL { $$ = GREATER_OR_EQUAL; } +| EQUAL { $$ = EQUAL; } +| NOT_EQUAL { $$ = NOT_EQUAL; } +| '^' { $$ = '^'; } +| '|' { $$ = '|'; } +| AND { $$ = AND; } +| OR { $$ = OR; } +| ';' { $$ = ';'; } +| ',' { $$ = ','; } +| '=' { $$ = '='; } +| PASTE { $$ = PASTE; } +; + +%% + +string_list_t * +_string_list_create (void *ctx) +{ + string_list_t *list; + + list = talloc (ctx, string_list_t); + list->head = NULL; + list->tail = NULL; + + return list; +} + +void +_string_list_append_item (string_list_t *list, const char *str) +{ + string_node_t *node; + + node = talloc (list, string_node_t); + node->str = talloc_strdup (node, str); + + node->next = NULL; + + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; +} + +int +_string_list_contains (string_list_t *list, const char *member, int *index) +{ + string_node_t *node; + int i; + + if (list == NULL) + return 0; + + for (i = 0, node = list->head; node; i++, node = node->next) { + if (strcmp (node->str, member) == 0) { + if (index) + *index = i; + return 1; + } + } + + return 0; +} + +int +_string_list_length (string_list_t *list) +{ + int length = 0; + string_node_t *node; + + if (list == NULL) + return 0; + + for (node = list->head; node; node = node->next) + length++; + + return length; +} + +int +_string_list_equal (string_list_t *a, string_list_t *b) +{ + string_node_t *node_a, *node_b; + + if (a == NULL && b == NULL) + return 1; + + if (a == NULL || b == NULL) + return 0; + + for (node_a = a->head, node_b = b->head; + node_a && node_b; + node_a = node_a->next, node_b = node_b->next) + { + if (strcmp (node_a->str, node_b->str)) + return 0; + } + + /* Catch the case of lists being different lengths, (which + * would cause the loop above to terminate after the shorter + * list). */ + return node_a == node_b; +} + +argument_list_t * +_argument_list_create (void *ctx) +{ + argument_list_t *list; + + list = talloc (ctx, argument_list_t); + list->head = NULL; + list->tail = NULL; + + return list; +} + +void +_argument_list_append (argument_list_t *list, token_list_t *argument) +{ + argument_node_t *node; + + node = talloc (list, argument_node_t); + node->argument = argument; + + node->next = NULL; + + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; +} + +int +_argument_list_length (argument_list_t *list) +{ + int length = 0; + argument_node_t *node; + + if (list == NULL) + return 0; + + for (node = list->head; node; node = node->next) + length++; + + return length; +} + +token_list_t * +_argument_list_member_at (argument_list_t *list, int index) +{ + argument_node_t *node; + int i; + + if (list == NULL) + return NULL; + + node = list->head; + for (i = 0; i < index; i++) { + node = node->next; + if (node == NULL) + break; + } + + if (node) + return node->argument; + + return NULL; +} + +/* Note: This function talloc_steal()s the str pointer. */ +token_t * +_token_create_str (void *ctx, int type, char *str) +{ + token_t *token; + + token = talloc (ctx, token_t); + token->type = type; + token->value.str = talloc_steal (token, str); + + return token; +} + +token_t * +_token_create_ival (void *ctx, int type, int ival) +{ + token_t *token; + + token = talloc (ctx, token_t); + token->type = type; + token->value.ival = ival; + + return token; +} + +token_list_t * +_token_list_create (void *ctx) +{ + token_list_t *list; + + list = talloc (ctx, token_list_t); + list->head = NULL; + list->tail = NULL; + list->non_space_tail = NULL; + + return list; +} + +void +_token_list_append (token_list_t *list, token_t *token) +{ + token_node_t *node; + + node = talloc (list, token_node_t); + node->token = talloc_reference (list, token); + + node->next = NULL; + + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; + if (token->type != SPACE) + list->non_space_tail = node; +} + +void +_token_list_append_list (token_list_t *list, token_list_t *tail) +{ + if (tail == NULL || tail->head == NULL) + return; + + if (list->head == NULL) { + list->head = tail->head; + } else { + list->tail->next = tail->head; + } + + list->tail = tail->tail; + list->non_space_tail = tail->non_space_tail; +} + +static token_list_t * +_token_list_copy (void *ctx, token_list_t *other) +{ + token_list_t *copy; + token_node_t *node; + + if (other == NULL) + return NULL; + + copy = _token_list_create (ctx); + for (node = other->head; node; node = node->next) + _token_list_append (copy, node->token); + + return copy; +} + +static void +_token_list_trim_trailing_space (token_list_t *list) +{ + token_node_t *tail, *next; + + if (list->non_space_tail) { + tail = list->non_space_tail->next; + list->non_space_tail->next = NULL; + list->tail = list->non_space_tail; + + while (tail) { + next = tail->next; + talloc_free (tail); + tail = next; + } + } +} + +int +_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b) +{ + token_node_t *node_a, *node_b; + + node_a = a->head; + node_b = b->head; + + while (1) + { + if (node_a == NULL && node_b == NULL) + break; + + if (node_a == NULL || node_b == NULL) + return 0; + + if (node_a->token->type == SPACE) { + node_a = node_a->next; + continue; + } + + if (node_b->token->type == SPACE) { + node_b = node_b->next; + continue; + } + + if (node_a->token->type != node_b->token->type) + return 0; + + switch (node_a->token->type) { + case INTEGER: + if (node_a->token->value.ival != + node_b->token->value.ival) + { + return 0; + } + break; + case IDENTIFIER: + case INTEGER_STRING: + case OTHER: + if (strcmp (node_a->token->value.str, + node_b->token->value.str)) + { + return 0; + } + break; + } + + node_a = node_a->next; + node_b = node_b->next; + } + + return 1; +} + +static void +_token_print (char **out, token_t *token) +{ + if (token->type < 256) { + glcpp_printf (*out, "%c", token->type); + return; + } + + switch (token->type) { + case INTEGER: + glcpp_printf (*out, "%" PRIiMAX, token->value.ival); + break; + case IDENTIFIER: + case INTEGER_STRING: + case OTHER: + glcpp_print (*out, token->value.str); + break; + case SPACE: + glcpp_print (*out, " "); + break; + case LEFT_SHIFT: + glcpp_print (*out, "<<"); + break; + case RIGHT_SHIFT: + glcpp_print (*out, ">>"); + break; + case LESS_OR_EQUAL: + glcpp_print (*out, "<="); + break; + case GREATER_OR_EQUAL: + glcpp_print (*out, ">="); + break; + case EQUAL: + glcpp_print (*out, "=="); + break; + case NOT_EQUAL: + glcpp_print (*out, "!="); + break; + case AND: + glcpp_print (*out, "&&"); + break; + case OR: + glcpp_print (*out, "||"); + break; + case PASTE: + glcpp_print (*out, "##"); + break; + case COMMA_FINAL: + glcpp_print (*out, ","); + break; + case PLACEHOLDER: + /* Nothing to print. */ + break; + default: + assert(!"Error: Don't know how to print token."); + break; + } +} + +/* Return a new token (talloc()ed off of 'token') formed by pasting + * 'token' and 'other'. Note that this function may return 'token' or + * 'other' directly rather than allocating anything new. + * + * Caution: Only very cursory error-checking is performed to see if + * the final result is a valid single token. */ +static token_t * +_token_paste (glcpp_parser_t *parser, token_t *token, token_t *other) +{ + token_t *combined = NULL; + + /* Pasting a placeholder onto anything makes no change. */ + if (other->type == PLACEHOLDER) + return token; + + /* When 'token' is a placeholder, just return 'other'. */ + if (token->type == PLACEHOLDER) + return other; + + /* A very few single-character punctuators can be combined + * with another to form a multi-character punctuator. */ + switch (token->type) { + case '<': + if (other->type == '<') + combined = _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT); + else if (other->type == '=') + combined = _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL); + break; + case '>': + if (other->type == '>') + combined = _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT); + else if (other->type == '=') + combined = _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL); + break; + case '=': + if (other->type == '=') + combined = _token_create_ival (token, EQUAL, EQUAL); + break; + case '!': + if (other->type == '=') + combined = _token_create_ival (token, NOT_EQUAL, NOT_EQUAL); + break; + case '&': + if (other->type == '&') + combined = _token_create_ival (token, AND, AND); + break; + case '|': + if (other->type == '|') + combined = _token_create_ival (token, OR, OR); + break; + } + + if (combined != NULL) { + /* Inherit the location from the first token */ + combined->location = token->location; + return combined; + } + + /* Two string-valued tokens can usually just be mashed + * together. + * + * XXX: This isn't actually legitimate. Several things here + * should result in a diagnostic since the result cannot be a + * valid, single pre-processing token. For example, pasting + * "123" and "abc" is not legal, but we don't catch that + * here. */ + if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) && + (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING)) + { + char *str; + + str = talloc_asprintf (token, "%s%s", token->value.str, + other->value.str); + combined = _token_create_str (token, token->type, str); + combined->location = token->location; + return combined; + } + + glcpp_error (&token->location, parser, ""); + glcpp_print (parser->info_log, "Pasting \""); + _token_print (&parser->info_log, token); + glcpp_print (parser->info_log, "\" and \""); + _token_print (&parser->info_log, other); + glcpp_print (parser->info_log, "\" does not give a valid preprocessing token.\n"); + + return token; +} + +static void +_token_list_print (glcpp_parser_t *parser, token_list_t *list) +{ + token_node_t *node; + + if (list == NULL) + return; + + for (node = list->head; node; node = node->next) + _token_print (&parser->output, node->token); +} + +void +yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error) +{ + glcpp_error(locp, parser, "%s", error); +} + +static void add_builtin_define(glcpp_parser_t *parser, + const char *name, int value) +{ + token_t *tok; + token_list_t *list; + + tok = _token_create_ival (parser, INTEGER, value); + + list = _token_list_create(parser); + _token_list_append(list, tok); + _define_object_macro(parser, NULL, name, list); + + talloc_unlink(parser, tok); +} + +glcpp_parser_t * +glcpp_parser_create (const struct gl_extensions *extensions) +{ + glcpp_parser_t *parser; + int language_version; + + parser = talloc (NULL, glcpp_parser_t); + + glcpp_lex_init_extra (parser, &parser->scanner); + parser->defines = hash_table_ctor (32, hash_table_string_hash, + hash_table_string_compare); + parser->active = NULL; + parser->lexing_if = 0; + parser->space_tokens = 1; + parser->newline_as_space = 0; + parser->in_control_line = 0; + parser->paren_count = 0; + + parser->skip_stack = NULL; + + parser->lex_from_list = NULL; + parser->lex_from_node = NULL; + + parser->output = talloc_strdup(parser, ""); + parser->info_log = talloc_strdup(parser, ""); + parser->error = 0; + + /* Add pre-defined macros. */ + add_builtin_define(parser, "GL_ARB_draw_buffers", 1); + add_builtin_define(parser, "GL_ARB_texture_rectangle", 1); + + if (extensions != NULL) { + if (extensions->EXT_texture_array) { + add_builtin_define(parser, "GL_EXT_texture_array", 1); + } + + if (extensions->ARB_fragment_coord_conventions) + add_builtin_define(parser, "GL_ARB_fragment_coord_conventions", + 1); + } + + language_version = 110; + add_builtin_define(parser, "__VERSION__", language_version); + + return parser; +} + +int +glcpp_parser_parse (glcpp_parser_t *parser) +{ + return yyparse (parser); +} + +void +glcpp_parser_destroy (glcpp_parser_t *parser) +{ + glcpp_lex_destroy (parser->scanner); + hash_table_dtor (parser->defines); + talloc_free (parser); +} + +typedef enum function_status +{ + FUNCTION_STATUS_SUCCESS, + FUNCTION_NOT_A_FUNCTION, + FUNCTION_UNBALANCED_PARENTHESES +} function_status_t; + +/* Find a set of function-like macro arguments by looking for a + * balanced set of parentheses. + * + * When called, 'node' should be the opening-parenthesis token, (or + * perhaps preceeding SPACE tokens). Upon successful return *last will + * be the last consumed node, (corresponding to the closing right + * parenthesis). + * + * Return values: + * + * FUNCTION_STATUS_SUCCESS: + * + * Successfully parsed a set of function arguments. + * + * FUNCTION_NOT_A_FUNCTION: + * + * Macro name not followed by a '('. This is not an error, but + * simply that the macro name should be treated as a non-macro. + * + * FUNCTION_UNBALANCED_PARENTHESES + * + * Macro name is not followed by a balanced set of parentheses. + */ +static function_status_t +_arguments_parse (argument_list_t *arguments, + token_node_t *node, + token_node_t **last) +{ + token_list_t *argument; + int paren_count; + + node = node->next; + + /* Ignore whitespace before first parenthesis. */ + while (node && node->token->type == SPACE) + node = node->next; + + if (node == NULL || node->token->type != '(') + return FUNCTION_NOT_A_FUNCTION; + + node = node->next; + + argument = _token_list_create (arguments); + _argument_list_append (arguments, argument); + + for (paren_count = 1; node; node = node->next) { + if (node->token->type == '(') + { + paren_count++; + } + else if (node->token->type == ')') + { + paren_count--; + if (paren_count == 0) + break; + } + + if (node->token->type == ',' && + paren_count == 1) + { + _token_list_trim_trailing_space (argument); + argument = _token_list_create (arguments); + _argument_list_append (arguments, argument); + } + else { + if (argument->head == NULL) { + /* Don't treat initial whitespace as + * part of the arguement. */ + if (node->token->type == SPACE) + continue; + } + _token_list_append (argument, node->token); + } + } + + if (paren_count) + return FUNCTION_UNBALANCED_PARENTHESES; + + *last = node; + + return FUNCTION_STATUS_SUCCESS; +} + +static token_list_t * +_token_list_create_with_one_space (void *ctx) +{ + token_list_t *list; + token_t *space; + + list = _token_list_create (ctx); + space = _token_create_ival (list, SPACE, SPACE); + _token_list_append (list, space); + + return list; +} + +static void +_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list) +{ + token_list_t *expanded; + token_t *token; + + expanded = _token_list_create (parser); + token = _token_create_ival (parser, type, type); + _token_list_append (expanded, token); + _glcpp_parser_expand_token_list (parser, list); + _token_list_append_list (expanded, list); + glcpp_parser_lex_from (parser, expanded); +} + +/* This is a helper function that's essentially part of the + * implementation of _glcpp_parser_expand_node. It shouldn't be called + * except for by that function. + * + * Returns NULL if node is a simple token with no expansion, (that is, + * although 'node' corresponds to an identifier defined as a + * function-like macro, it is not followed with a parenthesized + * argument list). + * + * Compute the complete expansion of node (which is a function-like + * macro) and subsequent nodes which are arguments. + * + * Returns the token list that results from the expansion and sets + * *last to the last node in the list that was consumed by the + * expansion. Specifically, *last will be set as follows: as the + * token of the closing right parenthesis. + */ +static token_list_t * +_glcpp_parser_expand_function (glcpp_parser_t *parser, + token_node_t *node, + token_node_t **last) + +{ + macro_t *macro; + const char *identifier; + argument_list_t *arguments; + function_status_t status; + token_list_t *substituted; + int parameter_index; + + identifier = node->token->value.str; + + macro = hash_table_find (parser->defines, identifier); + + assert (macro->is_function); + + arguments = _argument_list_create (parser); + status = _arguments_parse (arguments, node, last); + + switch (status) { + case FUNCTION_STATUS_SUCCESS: + break; + case FUNCTION_NOT_A_FUNCTION: + return NULL; + case FUNCTION_UNBALANCED_PARENTHESES: + glcpp_error (&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier); + return NULL; + } + + /* Replace a macro defined as empty with a SPACE token. */ + if (macro->replacements == NULL) { + talloc_free (arguments); + return _token_list_create_with_one_space (parser); + } + + if (! ((_argument_list_length (arguments) == + _string_list_length (macro->parameters)) || + (_string_list_length (macro->parameters) == 0 && + _argument_list_length (arguments) == 1 && + arguments->head->argument->head == NULL))) + { + glcpp_error (&node->token->location, parser, + "Error: macro %s invoked with %d arguments (expected %d)\n", + identifier, + _argument_list_length (arguments), + _string_list_length (macro->parameters)); + return NULL; + } + + /* Perform argument substitution on the replacement list. */ + substituted = _token_list_create (arguments); + + for (node = macro->replacements->head; node; node = node->next) + { + if (node->token->type == IDENTIFIER && + _string_list_contains (macro->parameters, + node->token->value.str, + ¶meter_index)) + { + token_list_t *argument; + argument = _argument_list_member_at (arguments, + parameter_index); + /* Before substituting, we expand the argument + * tokens, or append a placeholder token for + * an empty argument. */ + if (argument->head) { + token_list_t *expanded_argument; + expanded_argument = _token_list_copy (parser, + argument); + _glcpp_parser_expand_token_list (parser, + expanded_argument); + _token_list_append_list (substituted, + expanded_argument); + } else { + token_t *new_token; + + new_token = _token_create_ival (substituted, + PLACEHOLDER, + PLACEHOLDER); + _token_list_append (substituted, new_token); + } + } else { + _token_list_append (substituted, node->token); + } + } + + /* After argument substitution, and before further expansion + * below, implement token pasting. */ + + _token_list_trim_trailing_space (substituted); + + node = substituted->head; + while (node) + { + token_node_t *next_non_space; + + /* Look ahead for a PASTE token, skipping space. */ + next_non_space = node->next; + while (next_non_space && next_non_space->token->type == SPACE) + next_non_space = next_non_space->next; + + if (next_non_space == NULL) + break; + + if (next_non_space->token->type != PASTE) { + node = next_non_space; + continue; + } + + /* Now find the next non-space token after the PASTE. */ + next_non_space = next_non_space->next; + while (next_non_space && next_non_space->token->type == SPACE) + next_non_space = next_non_space->next; + + if (next_non_space == NULL) { + yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n"); + return NULL; + } + + node->token = _token_paste (parser, node->token, next_non_space->token); + node->next = next_non_space->next; + if (next_non_space == substituted->tail) + substituted->tail = node; + + node = node->next; + } + + substituted->non_space_tail = substituted->tail; + + return substituted; +} + +/* Compute the complete expansion of node, (and subsequent nodes after + * 'node' in the case that 'node' is a function-like macro and + * subsequent nodes are arguments). + * + * Returns NULL if node is a simple token with no expansion. + * + * Otherwise, returns the token list that results from the expansion + * and sets *last to the last node in the list that was consumed by + * the expansion. Specifically, *last will be set as follows: + * + * As 'node' in the case of object-like macro expansion. + * + * As the token of the closing right parenthesis in the case of + * function-like macro expansion. + */ +static token_list_t * +_glcpp_parser_expand_node (glcpp_parser_t *parser, + token_node_t *node, + token_node_t **last) +{ + token_t *token = node->token; + const char *identifier; + macro_t *macro; + + /* We only expand identifiers */ + if (token->type != IDENTIFIER) { + /* We change any COMMA into a COMMA_FINAL to prevent + * it being mistaken for an argument separator + * later. */ + if (token->type == ',') { + token->type = COMMA_FINAL; + token->value.ival = COMMA_FINAL; + } + + return NULL; + } + + /* Look up this identifier in the hash table. */ + identifier = token->value.str; + macro = hash_table_find (parser->defines, identifier); + + /* Not a macro, so no expansion needed. */ + if (macro == NULL) + return NULL; + + /* Finally, don't expand this macro if we're already actively + * expanding it, (to avoid infinite recursion). */ + if (_active_list_contains (parser->active, identifier)) { + /* We change the token type here from IDENTIFIER to + * OTHER to prevent any future expansion of this + * unexpanded token. */ + char *str; + token_list_t *expansion; + token_t *final; + + str = talloc_strdup (parser, token->value.str); + final = _token_create_str (parser, OTHER, str); + expansion = _token_list_create (parser); + _token_list_append (expansion, final); + *last = node; + return expansion; + } + + if (! macro->is_function) + { + *last = node; + + /* Replace a macro defined as empty with a SPACE token. */ + if (macro->replacements == NULL) + return _token_list_create_with_one_space (parser); + + return _token_list_copy (parser, macro->replacements); + } + + return _glcpp_parser_expand_function (parser, node, last); +} + +/* Push a new identifier onto the active list, returning the new list. + * + * Here, 'marker' is the token node that appears in the list after the + * expansion of 'identifier'. That is, when the list iterator begins + * examinging 'marker', then it is time to pop this node from the + * active stack. + */ +active_list_t * +_active_list_push (active_list_t *list, + const char *identifier, + token_node_t *marker) +{ + active_list_t *node; + + node = talloc (list, active_list_t); + node->identifier = talloc_strdup (node, identifier); + node->marker = marker; + node->next = list; + + return node; +} + +active_list_t * +_active_list_pop (active_list_t *list) +{ + active_list_t *node = list; + + if (node == NULL) + return NULL; + + node = list->next; + talloc_free (list); + + return node; +} + +int +_active_list_contains (active_list_t *list, const char *identifier) +{ + active_list_t *node; + + if (list == NULL) + return 0; + + for (node = list; node; node = node->next) + if (strcmp (node->identifier, identifier) == 0) + return 1; + + return 0; +} + +/* Walk over the token list replacing nodes with their expansion. + * Whenever nodes are expanded the walking will walk over the new + * nodes, continuing to expand as necessary. The results are placed in + * 'list' itself; + */ +static void +_glcpp_parser_expand_token_list (glcpp_parser_t *parser, + token_list_t *list) +{ + token_node_t *node_prev; + token_node_t *node, *last = NULL; + token_list_t *expansion; + + if (list == NULL) + return; + + _token_list_trim_trailing_space (list); + + node_prev = NULL; + node = list->head; + + while (node) { + + while (parser->active && parser->active->marker == node) + parser->active = _active_list_pop (parser->active); + + /* Find the expansion for node, which will replace all + * nodes from node to last, inclusive. */ + expansion = _glcpp_parser_expand_node (parser, node, &last); + if (expansion) { + token_node_t *n; + + for (n = node; n != last->next; n = n->next) + while (parser->active && + parser->active->marker == n) + { + parser->active = _active_list_pop (parser->active); + } + + parser->active = _active_list_push (parser->active, + node->token->value.str, + last->next); + + /* Splice expansion into list, supporting a + * simple deletion if the expansion is + * empty. */ + if (expansion->head) { + if (node_prev) + node_prev->next = expansion->head; + else + list->head = expansion->head; + expansion->tail->next = last->next; + if (last == list->tail) + list->tail = expansion->tail; + } else { + if (node_prev) + node_prev->next = last->next; + else + list->head = last->next; + if (last == list->tail) + list->tail = NULL; + } + } else { + node_prev = node; + } + node = node_prev ? node_prev->next : list->head; + } + + while (parser->active) + parser->active = _active_list_pop (parser->active); + + list->non_space_tail = list->tail; +} + +void +_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser, + token_list_t *list) +{ + if (list == NULL) + return; + + _glcpp_parser_expand_token_list (parser, list); + + _token_list_trim_trailing_space (list); + + _token_list_print (parser, list); +} + +static void +_check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc, + const char *identifier) +{ + /* According to the GLSL specification, macro names starting with "__" + * or "GL_" are reserved for future use. So, don't allow them. + */ + if (strncmp(identifier, "__", 2) == 0) { + glcpp_error (loc, parser, "Macro names starting with \"__\" are reserved.\n"); + } + if (strncmp(identifier, "GL_", 3) == 0) { + glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n"); + } +} + +static int +_macro_equal (macro_t *a, macro_t *b) +{ + if (a->is_function != b->is_function) + return 0; + + if (a->is_function) { + if (! _string_list_equal (a->parameters, b->parameters)) + return 0; + } + + return _token_list_equal_ignoring_space (a->replacements, + b->replacements); +} + +void +_define_object_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *identifier, + token_list_t *replacements) +{ + macro_t *macro, *previous; + + if (loc != NULL) + _check_for_reserved_macro_name(parser, loc, identifier); + + macro = talloc (parser, macro_t); + + macro->is_function = 0; + macro->parameters = NULL; + macro->identifier = talloc_strdup (macro, identifier); + macro->replacements = talloc_steal (macro, replacements); + + previous = hash_table_find (parser->defines, identifier); + if (previous) { + if (_macro_equal (macro, previous)) { + talloc_free (macro); + return; + } + glcpp_error (loc, parser, "Redefinition of macro %s\n", + identifier); + } + + hash_table_insert (parser->defines, macro, identifier); +} + +void +_define_function_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *identifier, + string_list_t *parameters, + token_list_t *replacements) +{ + macro_t *macro, *previous; + + _check_for_reserved_macro_name(parser, loc, identifier); + + macro = talloc (parser, macro_t); + + macro->is_function = 1; + macro->parameters = talloc_steal (macro, parameters); + macro->identifier = talloc_strdup (macro, identifier); + macro->replacements = talloc_steal (macro, replacements); + + previous = hash_table_find (parser->defines, identifier); + if (previous) { + if (_macro_equal (macro, previous)) { + talloc_free (macro); + return; + } + glcpp_error (loc, parser, "Redefinition of macro %s\n", + identifier); + } + + hash_table_insert (parser->defines, macro, identifier); +} + +static int +glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser) +{ + token_node_t *node; + int ret; + + if (parser->lex_from_list == NULL) { + ret = glcpp_lex (yylval, yylloc, parser->scanner); + + /* XXX: This ugly block of code exists for the sole + * purpose of converting a NEWLINE token into a SPACE + * token, but only in the case where we have seen a + * function-like macro name, but have not yet seen its + * closing parenthesis. + * + * There's perhaps a more compact way to do this with + * mid-rule actions in the grammar. + * + * I'm definitely not pleased with the complexity of + * this code here. + */ + if (parser->newline_as_space) + { + if (ret == '(') { + parser->paren_count++; + } else if (ret == ')') { + parser->paren_count--; + if (parser->paren_count == 0) + parser->newline_as_space = 0; + } else if (ret == NEWLINE) { + ret = SPACE; + } else if (ret != SPACE) { + if (parser->paren_count == 0) + parser->newline_as_space = 0; + } + } + else if (parser->in_control_line) + { + if (ret == NEWLINE) + parser->in_control_line = 0; + } + else if (ret == HASH_DEFINE_OBJ || ret == HASH_DEFINE_FUNC || + ret == HASH_UNDEF || ret == HASH_IF || + ret == HASH_IFDEF || ret == HASH_IFNDEF || + ret == HASH_ELIF || ret == HASH_ELSE || + ret == HASH_ENDIF || ret == HASH) + { + parser->in_control_line = 1; + } + else if (ret == IDENTIFIER) + { + macro_t *macro; + macro = hash_table_find (parser->defines, + yylval->str); + if (macro && macro->is_function) { + parser->newline_as_space = 1; + parser->paren_count = 0; + } + } + + return ret; + } + + node = parser->lex_from_node; + + if (node == NULL) { + talloc_free (parser->lex_from_list); + parser->lex_from_list = NULL; + return NEWLINE; + } + + *yylval = node->token->value; + ret = node->token->type; + + parser->lex_from_node = node->next; + + return ret; +} + +static void +glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list) +{ + token_node_t *node; + + assert (parser->lex_from_list == NULL); + + /* Copy list, eliminating any space tokens. */ + parser->lex_from_list = _token_list_create (parser); + + for (node = list->head; node; node = node->next) { + if (node->token->type == SPACE) + continue; + _token_list_append (parser->lex_from_list, node->token); + } + + talloc_free (list); + + parser->lex_from_node = parser->lex_from_list->head; + + /* It's possible the list consisted of nothing but whitespace. */ + if (parser->lex_from_node == NULL) { + talloc_free (parser->lex_from_list); + parser->lex_from_list = NULL; + } +} + +static void +_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc, + int condition) +{ + skip_type_t current = SKIP_NO_SKIP; + skip_node_t *node; + + if (parser->skip_stack) + current = parser->skip_stack->type; + + node = talloc (parser, skip_node_t); + node->loc = *loc; + + if (current == SKIP_NO_SKIP) { + if (condition) + node->type = SKIP_NO_SKIP; + else + node->type = SKIP_TO_ELSE; + } else { + node->type = SKIP_TO_ENDIF; + } + + node->next = parser->skip_stack; + parser->skip_stack = node; +} + +static void +_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc, + const char *type, int condition) +{ + if (parser->skip_stack == NULL) { + glcpp_error (loc, parser, "%s without #if\n", type); + return; + } + + if (parser->skip_stack->type == SKIP_TO_ELSE) { + if (condition) + parser->skip_stack->type = SKIP_NO_SKIP; + } else { + parser->skip_stack->type = SKIP_TO_ENDIF; + } +} + +static void +_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc) +{ + skip_node_t *node; + + if (parser->skip_stack == NULL) { + glcpp_error (loc, parser, "#endif without #if\n"); + return; + } + + node = parser->skip_stack; + parser->skip_stack = node->next; + talloc_free (node); +} diff --git a/src/glsl/glcpp/glcpp.c b/src/glsl/glcpp/glcpp.c new file mode 100644 index 0000000000..56714936bb --- /dev/null +++ b/src/glsl/glcpp/glcpp.c @@ -0,0 +1,122 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include "glcpp.h" + +extern int yydebug; + +/* Read from fd until EOF and return a string of everything read. + */ +static char * +load_text_fd (void *ctx, int fd) +{ +#define CHUNK 4096 + char *text = NULL; + ssize_t text_size = 0; + ssize_t total_read = 0; + ssize_t bytes; + + while (1) { + if (total_read + CHUNK + 1 > text_size) { + text_size = text_size ? text_size * 2 : CHUNK + 1; + text = talloc_realloc_size (ctx, text, text_size); + if (text == NULL) { + fprintf (stderr, "Out of memory\n"); + return NULL; + } + } + bytes = read (fd, text + total_read, CHUNK); + if (bytes < 0) { + fprintf (stderr, "Error while reading: %s\n", + strerror (errno)); + talloc_free (text); + return NULL; + } + + if (bytes == 0) { + break; + } + + total_read += bytes; + } + + text[total_read] = '\0'; + + return text; +} + +static char * +load_text_file(void *ctx, const char *filename) +{ + char *text; + int fd; + + if (filename == NULL || strcmp (filename, "-") == 0) + return load_text_fd (ctx, STDIN_FILENO); + + fd = open (filename, O_RDONLY); + if (fd < 0) { + fprintf (stderr, "Failed to open file %s: %s\n", + filename, strerror (errno)); + return NULL; + } + + text = load_text_fd (ctx, fd); + + close(fd); + + return text; +} + +int +main (int argc, char *argv[]) +{ + char *filename = NULL; + void *ctx = talloc(NULL, void*); + char *info_log = talloc_strdup(ctx, ""); + const char *shader; + int ret; + + if (argc) { + filename = argv[1]; + } + + shader = load_text_file (ctx, filename); + if (shader == NULL) + return 1; + + ret = preprocess(ctx, &shader, &info_log, NULL); + + printf("%s", shader); + fprintf(stderr, "%s", info_log); + + talloc_free(ctx); + + return ret; +} diff --git a/src/glsl/glcpp/glcpp.h b/src/glsl/glcpp/glcpp.h new file mode 100644 index 0000000000..0bebdb9ae8 --- /dev/null +++ b/src/glsl/glcpp/glcpp.h @@ -0,0 +1,222 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef GLCPP_H +#define GLCPP_H + +#include <stdint.h> + +#include <talloc.h> + +#include "program/hash_table.h" + +#define yyscan_t void* + +/* Some data types used for parser values. */ + +typedef struct string_node { + const char *str; + struct string_node *next; +} string_node_t; + +typedef struct string_list { + string_node_t *head; + string_node_t *tail; +} string_list_t; + +typedef struct token token_t; +typedef struct token_list token_list_t; + +typedef union YYSTYPE +{ + intmax_t ival; + char *str; + string_list_t *string_list; + token_t *token; + token_list_t *token_list; +} YYSTYPE; + +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 + +typedef struct YYLTYPE { + int first_line; + int first_column; + int last_line; + int last_column; + unsigned source; +} YYLTYPE; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 + +# define YYLLOC_DEFAULT(Current, Rhs, N) \ +do { \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC(Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC(Rhs, 0).last_column; \ + } \ + (Current).source = 0; \ +} while (0) + +struct token { + int type; + YYSTYPE value; + YYLTYPE location; +}; + +typedef struct token_node { + token_t *token; + struct token_node *next; +} token_node_t; + +struct token_list { + token_node_t *head; + token_node_t *tail; + token_node_t *non_space_tail; +}; + +typedef struct argument_node { + token_list_t *argument; + struct argument_node *next; +} argument_node_t; + +typedef struct argument_list { + argument_node_t *head; + argument_node_t *tail; +} argument_list_t; + +typedef struct glcpp_parser glcpp_parser_t; + +typedef enum { + TOKEN_CLASS_IDENTIFIER, + TOKEN_CLASS_IDENTIFIER_FINALIZED, + TOKEN_CLASS_FUNC_MACRO, + TOKEN_CLASS_OBJ_MACRO +} token_class_t; + +token_class_t +glcpp_parser_classify_token (glcpp_parser_t *parser, + const char *identifier, + int *parameter_index); + +typedef struct { + int is_function; + string_list_t *parameters; + const char *identifier; + token_list_t *replacements; +} macro_t; + +typedef struct expansion_node { + macro_t *macro; + token_node_t *replacements; + struct expansion_node *next; +} expansion_node_t; + +typedef enum skip_type { + SKIP_NO_SKIP, + SKIP_TO_ELSE, + SKIP_TO_ENDIF +} skip_type_t; + +typedef struct skip_node { + skip_type_t type; + YYLTYPE loc; /* location of the initial #if/#elif/... */ + struct skip_node *next; +} skip_node_t; + +typedef struct active_list { + const char *identifier; + token_node_t *marker; + struct active_list *next; +} active_list_t; + +struct glcpp_parser { + yyscan_t scanner; + struct hash_table *defines; + active_list_t *active; + int lexing_if; + int space_tokens; + int newline_as_space; + int in_control_line; + int paren_count; + skip_node_t *skip_stack; + token_list_t *lex_from_list; + token_node_t *lex_from_node; + char *output; + char *info_log; + int error; +}; + +struct gl_extensions; + +glcpp_parser_t * +glcpp_parser_create (const struct gl_extensions *extensions); + +int +glcpp_parser_parse (glcpp_parser_t *parser); + +void +glcpp_parser_destroy (glcpp_parser_t *parser); + +int +preprocess(void *talloc_ctx, const char **shader, char **info_log, + const struct gl_extensions *extensions); + +/* Functions for writing to the info log */ + +void +glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...); + +void +glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...); + +/* Generated by glcpp-lex.l to glcpp-lex.c */ + +int +glcpp_lex_init_extra (glcpp_parser_t *parser, yyscan_t* scanner); + +void +glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader); + +int +glcpp_lex (YYSTYPE *lvalp, YYLTYPE *llocp, yyscan_t scanner); + +int +glcpp_lex_destroy (yyscan_t scanner); + +/* Generated by glcpp-parse.y to glcpp-parse.c */ + +int +yyparse (glcpp_parser_t *parser); + +#endif diff --git a/src/glsl/glcpp/pp.c b/src/glsl/glcpp/pp.c new file mode 100644 index 0000000000..a1d00c4193 --- /dev/null +++ b/src/glsl/glcpp/pp.c @@ -0,0 +1,167 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include "glcpp.h" +#include "main/core.h" /* for isblank() on MSVC */ + +void +glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) +{ + va_list ap; + + parser->error = 1; + parser->info_log = talloc_asprintf_append(parser->info_log, + "%u:%u(%u): " + "preprocessor error: ", + locp->source, + locp->first_line, + locp->first_column); + va_start(ap, fmt); + parser->info_log = talloc_vasprintf_append(parser->info_log, fmt, ap); + va_end(ap); + parser->info_log = talloc_strdup_append(parser->info_log, "\n"); +} + +void +glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) +{ + va_list ap; + + parser->info_log = talloc_asprintf_append(parser->info_log, + "%u:%u(%u): " + "preprocessor warning: ", + locp->source, + locp->first_line, + locp->first_column); + va_start(ap, fmt); + parser->info_log = talloc_vasprintf_append(parser->info_log, fmt, ap); + va_end(ap); + parser->info_log = talloc_strdup_append(parser->info_log, "\n"); +} + +/* Searches backwards for '^ *#' from a given starting point. */ +static int +in_directive(const char *shader, const char *ptr) +{ + assert(ptr >= shader); + + /* Search backwards for '#'. If we find a \n first, it doesn't count */ + for (; ptr >= shader && *ptr != '#'; ptr--) { + if (*ptr == '\n') + return 0; + } + if (ptr >= shader) { + /* Found '#'...look for spaces preceded by a newline */ + for (ptr--; ptr >= shader && isblank(*ptr); ptr--); + // FIXME: I don't think the '\n' case can happen + if (ptr < shader || *ptr == '\n') + return 1; + } + return 0; +} + +/* Remove any line continuation characters in preprocessing directives. + * However, ignore any in GLSL code, as "There is no line continuation + * character" (1.30 page 9) in GLSL. + */ +static char * +remove_line_continuations(glcpp_parser_t *ctx, const char *shader) +{ + int in_continued_line = 0; + int extra_newlines = 0; + char *clean = talloc_strdup(ctx, ""); + const char *search_start = shader; + const char *newline; + while ((newline = strchr(search_start, '\n')) != NULL) { + const char *backslash = NULL; + + /* # of characters preceding the newline. */ + int n = newline - shader; + + /* Find the preceding '\', if it exists */ + if (n >= 1 && newline[-1] == '\\') + backslash = newline - 1; + else if (n >= 2 && newline[-1] == '\r' && newline[-2] == '\\') + backslash = newline - 2; + + /* Double backslashes don't count (the backslash is escaped) */ + if (backslash != NULL && backslash[-1] == '\\') { + backslash = NULL; + } + + if (backslash != NULL) { + /* We found a line continuation, but do we care? */ + if (!in_continued_line) { + if (in_directive(shader, backslash)) { + in_continued_line = 1; + extra_newlines = 0; + } + } + if (in_continued_line) { + /* Copy everything before the \ */ + clean = talloc_strndup_append(clean, shader, backslash - shader); + shader = newline + 1; + extra_newlines++; + } + } else if (in_continued_line) { + /* Copy everything up to and including the \n */ + clean = talloc_strndup_append(clean, shader, newline - shader + 1); + shader = newline + 1; + /* Output extra newlines to make line numbers match */ + for (; extra_newlines > 0; extra_newlines--) + clean = talloc_strdup_append(clean, "\n"); + in_continued_line = 0; + } + search_start = newline + 1; + } + clean = talloc_strdup_append(clean, shader); + return clean; +} + +int +preprocess(void *talloc_ctx, const char **shader, char **info_log, + const struct gl_extensions *extensions) +{ + int errors; + glcpp_parser_t *parser = glcpp_parser_create (extensions); + *shader = remove_line_continuations(parser, *shader); + + glcpp_lex_set_source_string (parser, *shader); + + glcpp_parser_parse (parser); + + if (parser->skip_stack) + glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n"); + + *info_log = talloc_strdup_append(*info_log, parser->info_log); + + talloc_steal(talloc_ctx, parser->output); + *shader = parser->output; + + errors = parser->error; + glcpp_parser_destroy (parser); + return errors; +} diff --git a/src/glsl/glcpp/tests/000-content-with-spaces.c b/src/glsl/glcpp/tests/000-content-with-spaces.c new file mode 100644 index 0000000000..696cb3a74f --- /dev/null +++ b/src/glsl/glcpp/tests/000-content-with-spaces.c @@ -0,0 +1 @@ +this is four tokens diff --git a/src/glsl/glcpp/tests/000-content-with-spaces.c.expected b/src/glsl/glcpp/tests/000-content-with-spaces.c.expected new file mode 100644 index 0000000000..83f7834d54 --- /dev/null +++ b/src/glsl/glcpp/tests/000-content-with-spaces.c.expected @@ -0,0 +1,2 @@ +this is four tokens + diff --git a/src/glsl/glcpp/tests/001-define.c b/src/glsl/glcpp/tests/001-define.c new file mode 100644 index 0000000000..cbf2fee0e7 --- /dev/null +++ b/src/glsl/glcpp/tests/001-define.c @@ -0,0 +1,2 @@ +#define foo 1 +foo diff --git a/src/glsl/glcpp/tests/001-define.c.expected b/src/glsl/glcpp/tests/001-define.c.expected new file mode 100644 index 0000000000..878fd15d6f --- /dev/null +++ b/src/glsl/glcpp/tests/001-define.c.expected @@ -0,0 +1,3 @@ + +1 + diff --git a/src/glsl/glcpp/tests/002-define-chain.c b/src/glsl/glcpp/tests/002-define-chain.c new file mode 100644 index 0000000000..87d75c6875 --- /dev/null +++ b/src/glsl/glcpp/tests/002-define-chain.c @@ -0,0 +1,3 @@ +#define foo 1 +#define bar foo +bar diff --git a/src/glsl/glcpp/tests/002-define-chain.c.expected b/src/glsl/glcpp/tests/002-define-chain.c.expected new file mode 100644 index 0000000000..43d484d713 --- /dev/null +++ b/src/glsl/glcpp/tests/002-define-chain.c.expected @@ -0,0 +1,4 @@ + + +1 + diff --git a/src/glsl/glcpp/tests/003-define-chain-reverse.c b/src/glsl/glcpp/tests/003-define-chain-reverse.c new file mode 100644 index 0000000000..a18b724eca --- /dev/null +++ b/src/glsl/glcpp/tests/003-define-chain-reverse.c @@ -0,0 +1,3 @@ +#define bar foo +#define foo 1 +bar diff --git a/src/glsl/glcpp/tests/003-define-chain-reverse.c.expected b/src/glsl/glcpp/tests/003-define-chain-reverse.c.expected new file mode 100644 index 0000000000..43d484d713 --- /dev/null +++ b/src/glsl/glcpp/tests/003-define-chain-reverse.c.expected @@ -0,0 +1,4 @@ + + +1 + diff --git a/src/glsl/glcpp/tests/004-define-recursive.c b/src/glsl/glcpp/tests/004-define-recursive.c new file mode 100644 index 0000000000..2ac56ea3dc --- /dev/null +++ b/src/glsl/glcpp/tests/004-define-recursive.c @@ -0,0 +1,6 @@ +#define foo bar +#define bar baz +#define baz foo +foo +bar +baz diff --git a/src/glsl/glcpp/tests/004-define-recursive.c.expected b/src/glsl/glcpp/tests/004-define-recursive.c.expected new file mode 100644 index 0000000000..4d2698b7a7 --- /dev/null +++ b/src/glsl/glcpp/tests/004-define-recursive.c.expected @@ -0,0 +1,7 @@ + + + +foo +bar +baz + diff --git a/src/glsl/glcpp/tests/005-define-composite-chain.c b/src/glsl/glcpp/tests/005-define-composite-chain.c new file mode 100644 index 0000000000..f5521df968 --- /dev/null +++ b/src/glsl/glcpp/tests/005-define-composite-chain.c @@ -0,0 +1,3 @@ +#define foo 1 +#define bar a foo +bar diff --git a/src/glsl/glcpp/tests/005-define-composite-chain.c.expected b/src/glsl/glcpp/tests/005-define-composite-chain.c.expected new file mode 100644 index 0000000000..c67358f4f6 --- /dev/null +++ b/src/glsl/glcpp/tests/005-define-composite-chain.c.expected @@ -0,0 +1,4 @@ + + +a 1 + diff --git a/src/glsl/glcpp/tests/006-define-composite-chain-reverse.c b/src/glsl/glcpp/tests/006-define-composite-chain-reverse.c new file mode 100644 index 0000000000..4bb91a1221 --- /dev/null +++ b/src/glsl/glcpp/tests/006-define-composite-chain-reverse.c @@ -0,0 +1,3 @@ +#define bar a foo +#define foo 1 +bar diff --git a/src/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected b/src/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected new file mode 100644 index 0000000000..c67358f4f6 --- /dev/null +++ b/src/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected @@ -0,0 +1,4 @@ + + +a 1 + diff --git a/src/glsl/glcpp/tests/007-define-composite-recursive.c b/src/glsl/glcpp/tests/007-define-composite-recursive.c new file mode 100644 index 0000000000..5784565bdf --- /dev/null +++ b/src/glsl/glcpp/tests/007-define-composite-recursive.c @@ -0,0 +1,6 @@ +#define foo a bar +#define bar b baz +#define baz c foo +foo +bar +baz diff --git a/src/glsl/glcpp/tests/007-define-composite-recursive.c.expected b/src/glsl/glcpp/tests/007-define-composite-recursive.c.expected new file mode 100644 index 0000000000..30fe4dc1f6 --- /dev/null +++ b/src/glsl/glcpp/tests/007-define-composite-recursive.c.expected @@ -0,0 +1,7 @@ + + + +a b c foo +b c a bar +c a b baz + diff --git a/src/glsl/glcpp/tests/008-define-empty.c b/src/glsl/glcpp/tests/008-define-empty.c new file mode 100644 index 0000000000..b1bd17ec21 --- /dev/null +++ b/src/glsl/glcpp/tests/008-define-empty.c @@ -0,0 +1,2 @@ +#define foo +foo diff --git a/src/glsl/glcpp/tests/008-define-empty.c.expected b/src/glsl/glcpp/tests/008-define-empty.c.expected new file mode 100644 index 0000000000..c0f53d75c7 --- /dev/null +++ b/src/glsl/glcpp/tests/008-define-empty.c.expected @@ -0,0 +1,3 @@ + + + diff --git a/src/glsl/glcpp/tests/009-undef.c b/src/glsl/glcpp/tests/009-undef.c new file mode 100644 index 0000000000..3fc1fb4424 --- /dev/null +++ b/src/glsl/glcpp/tests/009-undef.c @@ -0,0 +1,4 @@ +#define foo 1 +foo +#undef foo +foo diff --git a/src/glsl/glcpp/tests/009-undef.c.expected b/src/glsl/glcpp/tests/009-undef.c.expected new file mode 100644 index 0000000000..03a7061af0 --- /dev/null +++ b/src/glsl/glcpp/tests/009-undef.c.expected @@ -0,0 +1,5 @@ + +1 + +foo + diff --git a/src/glsl/glcpp/tests/010-undef-re-define.c b/src/glsl/glcpp/tests/010-undef-re-define.c new file mode 100644 index 0000000000..32ff73798b --- /dev/null +++ b/src/glsl/glcpp/tests/010-undef-re-define.c @@ -0,0 +1,6 @@ +#define foo 1 +foo +#undef foo +foo +#define foo 2 +foo diff --git a/src/glsl/glcpp/tests/010-undef-re-define.c.expected b/src/glsl/glcpp/tests/010-undef-re-define.c.expected new file mode 100644 index 0000000000..f4f7efdc2b --- /dev/null +++ b/src/glsl/glcpp/tests/010-undef-re-define.c.expected @@ -0,0 +1,7 @@ + +1 + +foo + +2 + diff --git a/src/glsl/glcpp/tests/011-define-func-empty.c b/src/glsl/glcpp/tests/011-define-func-empty.c new file mode 100644 index 0000000000..d9ce13c228 --- /dev/null +++ b/src/glsl/glcpp/tests/011-define-func-empty.c @@ -0,0 +1,2 @@ +#define foo() +foo() diff --git a/src/glsl/glcpp/tests/011-define-func-empty.c.expected b/src/glsl/glcpp/tests/011-define-func-empty.c.expected new file mode 100644 index 0000000000..c0f53d75c7 --- /dev/null +++ b/src/glsl/glcpp/tests/011-define-func-empty.c.expected @@ -0,0 +1,3 @@ + + + diff --git a/src/glsl/glcpp/tests/012-define-func-no-args.c b/src/glsl/glcpp/tests/012-define-func-no-args.c new file mode 100644 index 0000000000..c2bb730b11 --- /dev/null +++ b/src/glsl/glcpp/tests/012-define-func-no-args.c @@ -0,0 +1,2 @@ +#define foo() bar +foo() diff --git a/src/glsl/glcpp/tests/012-define-func-no-args.c.expected b/src/glsl/glcpp/tests/012-define-func-no-args.c.expected new file mode 100644 index 0000000000..0353767297 --- /dev/null +++ b/src/glsl/glcpp/tests/012-define-func-no-args.c.expected @@ -0,0 +1,3 @@ + +bar + diff --git a/src/glsl/glcpp/tests/013-define-func-1-arg-unused.c b/src/glsl/glcpp/tests/013-define-func-1-arg-unused.c new file mode 100644 index 0000000000..f78fb8b118 --- /dev/null +++ b/src/glsl/glcpp/tests/013-define-func-1-arg-unused.c @@ -0,0 +1,2 @@ +#define foo(x) 1 +foo(bar) diff --git a/src/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected b/src/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected new file mode 100644 index 0000000000..878fd15d6f --- /dev/null +++ b/src/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected @@ -0,0 +1,3 @@ + +1 + diff --git a/src/glsl/glcpp/tests/014-define-func-2-arg-unused.c b/src/glsl/glcpp/tests/014-define-func-2-arg-unused.c new file mode 100644 index 0000000000..11feb2624b --- /dev/null +++ b/src/glsl/glcpp/tests/014-define-func-2-arg-unused.c @@ -0,0 +1,2 @@ +#define foo(x,y) 1 +foo(bar,baz) diff --git a/src/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected b/src/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected new file mode 100644 index 0000000000..878fd15d6f --- /dev/null +++ b/src/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected @@ -0,0 +1,3 @@ + +1 + diff --git a/src/glsl/glcpp/tests/015-define-object-with-parens.c b/src/glsl/glcpp/tests/015-define-object-with-parens.c new file mode 100644 index 0000000000..558da9c617 --- /dev/null +++ b/src/glsl/glcpp/tests/015-define-object-with-parens.c @@ -0,0 +1,4 @@ +#define foo ()1 +foo() +#define bar ()2 +bar() diff --git a/src/glsl/glcpp/tests/015-define-object-with-parens.c.expected b/src/glsl/glcpp/tests/015-define-object-with-parens.c.expected new file mode 100644 index 0000000000..d6f8cb9dc6 --- /dev/null +++ b/src/glsl/glcpp/tests/015-define-object-with-parens.c.expected @@ -0,0 +1,5 @@ + +()1() + +()2() + diff --git a/src/glsl/glcpp/tests/016-define-func-1-arg.c b/src/glsl/glcpp/tests/016-define-func-1-arg.c new file mode 100644 index 0000000000..a2e2404c7c --- /dev/null +++ b/src/glsl/glcpp/tests/016-define-func-1-arg.c @@ -0,0 +1,2 @@ +#define foo(x) ((x)+1) +foo(bar) diff --git a/src/glsl/glcpp/tests/016-define-func-1-arg.c.expected b/src/glsl/glcpp/tests/016-define-func-1-arg.c.expected new file mode 100644 index 0000000000..7f1828a3c6 --- /dev/null +++ b/src/glsl/glcpp/tests/016-define-func-1-arg.c.expected @@ -0,0 +1,3 @@ + +((bar)+1) + diff --git a/src/glsl/glcpp/tests/017-define-func-2-args.c b/src/glsl/glcpp/tests/017-define-func-2-args.c new file mode 100644 index 0000000000..c725383527 --- /dev/null +++ b/src/glsl/glcpp/tests/017-define-func-2-args.c @@ -0,0 +1,2 @@ +#define foo(x,y) ((x)*(y)) +foo(bar,baz) diff --git a/src/glsl/glcpp/tests/017-define-func-2-args.c.expected b/src/glsl/glcpp/tests/017-define-func-2-args.c.expected new file mode 100644 index 0000000000..9f341dac00 --- /dev/null +++ b/src/glsl/glcpp/tests/017-define-func-2-args.c.expected @@ -0,0 +1,3 @@ + +((bar)*(baz)) + diff --git a/src/glsl/glcpp/tests/018-define-func-macro-as-parameter.c b/src/glsl/glcpp/tests/018-define-func-macro-as-parameter.c new file mode 100644 index 0000000000..668130b8f9 --- /dev/null +++ b/src/glsl/glcpp/tests/018-define-func-macro-as-parameter.c @@ -0,0 +1,3 @@ +#define x 0 +#define foo(x) x +foo(1) diff --git a/src/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected b/src/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected new file mode 100644 index 0000000000..43d484d713 --- /dev/null +++ b/src/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected @@ -0,0 +1,4 @@ + + +1 + diff --git a/src/glsl/glcpp/tests/019-define-func-1-arg-multi.c b/src/glsl/glcpp/tests/019-define-func-1-arg-multi.c new file mode 100644 index 0000000000..c4e62b2550 --- /dev/null +++ b/src/glsl/glcpp/tests/019-define-func-1-arg-multi.c @@ -0,0 +1,2 @@ +#define foo(x) (x) +foo(this is more than one word) diff --git a/src/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected b/src/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected new file mode 100644 index 0000000000..4314fc88d8 --- /dev/null +++ b/src/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected @@ -0,0 +1,3 @@ + +(this is more than one word) + diff --git a/src/glsl/glcpp/tests/020-define-func-2-arg-multi.c b/src/glsl/glcpp/tests/020-define-func-2-arg-multi.c new file mode 100644 index 0000000000..3049ad1546 --- /dev/null +++ b/src/glsl/glcpp/tests/020-define-func-2-arg-multi.c @@ -0,0 +1,2 @@ +#define foo(x,y) x,two fish,red fish,y +foo(one fish, blue fish) diff --git a/src/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected b/src/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected new file mode 100644 index 0000000000..5648e4fb9d --- /dev/null +++ b/src/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected @@ -0,0 +1,3 @@ + +one fish,two fish,red fish,blue fish + diff --git a/src/glsl/glcpp/tests/021-define-func-compose.c b/src/glsl/glcpp/tests/021-define-func-compose.c new file mode 100644 index 0000000000..21ddd0e65f --- /dev/null +++ b/src/glsl/glcpp/tests/021-define-func-compose.c @@ -0,0 +1,3 @@ +#define bar(x) (1+(x)) +#define foo(y) (2*(y)) +foo(bar(3)) diff --git a/src/glsl/glcpp/tests/021-define-func-compose.c.expected b/src/glsl/glcpp/tests/021-define-func-compose.c.expected new file mode 100644 index 0000000000..1d62105de4 --- /dev/null +++ b/src/glsl/glcpp/tests/021-define-func-compose.c.expected @@ -0,0 +1,4 @@ + + +(2*((1+(3)))) + diff --git a/src/glsl/glcpp/tests/022-define-func-arg-with-parens.c b/src/glsl/glcpp/tests/022-define-func-arg-with-parens.c new file mode 100644 index 0000000000..c20d73a4a2 --- /dev/null +++ b/src/glsl/glcpp/tests/022-define-func-arg-with-parens.c @@ -0,0 +1,2 @@ +#define foo(x) (x) +foo(argument(including parens)for the win) diff --git a/src/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected b/src/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected new file mode 100644 index 0000000000..66c1658175 --- /dev/null +++ b/src/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected @@ -0,0 +1,3 @@ + +(argument(including parens)for the win) + diff --git a/src/glsl/glcpp/tests/023-define-extra-whitespace.c b/src/glsl/glcpp/tests/023-define-extra-whitespace.c new file mode 100644 index 0000000000..7ebfed6516 --- /dev/null +++ b/src/glsl/glcpp/tests/023-define-extra-whitespace.c @@ -0,0 +1,8 @@ +#define noargs() 1 +# define onearg(foo) foo + # define twoargs( x , y ) x y + # define threeargs( a , b , c ) a b c +noargs ( ) +onearg ( 2 ) +twoargs ( 3 , 4 ) +threeargs ( 5 , 6 , 7 ) diff --git a/src/glsl/glcpp/tests/023-define-extra-whitespace.c.expected b/src/glsl/glcpp/tests/023-define-extra-whitespace.c.expected new file mode 100644 index 0000000000..573829c2d6 --- /dev/null +++ b/src/glsl/glcpp/tests/023-define-extra-whitespace.c.expected @@ -0,0 +1,9 @@ + + + + +1 +2 +3 4 +5 6 7 + diff --git a/src/glsl/glcpp/tests/024-define-chain-to-self-recursion.c b/src/glsl/glcpp/tests/024-define-chain-to-self-recursion.c new file mode 100644 index 0000000000..e788adce30 --- /dev/null +++ b/src/glsl/glcpp/tests/024-define-chain-to-self-recursion.c @@ -0,0 +1,3 @@ +#define foo foo +#define bar foo +bar diff --git a/src/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected b/src/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected new file mode 100644 index 0000000000..ad955fce6e --- /dev/null +++ b/src/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected @@ -0,0 +1,4 @@ + + +foo + diff --git a/src/glsl/glcpp/tests/025-func-macro-as-non-macro.c b/src/glsl/glcpp/tests/025-func-macro-as-non-macro.c new file mode 100644 index 0000000000..b433671d1b --- /dev/null +++ b/src/glsl/glcpp/tests/025-func-macro-as-non-macro.c @@ -0,0 +1,2 @@ +#define foo(bar) bar +foo bar diff --git a/src/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected b/src/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected new file mode 100644 index 0000000000..960f44511a --- /dev/null +++ b/src/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected @@ -0,0 +1,3 @@ + +foo bar + diff --git a/src/glsl/glcpp/tests/026-define-func-extra-newlines.c b/src/glsl/glcpp/tests/026-define-func-extra-newlines.c new file mode 100644 index 0000000000..0d83740530 --- /dev/null +++ b/src/glsl/glcpp/tests/026-define-func-extra-newlines.c @@ -0,0 +1,6 @@ +#define foo(a) bar + +foo +( +1 +) diff --git a/src/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected b/src/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected new file mode 100644 index 0000000000..f0888f21b9 --- /dev/null +++ b/src/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected @@ -0,0 +1,4 @@ + + +bar + diff --git a/src/glsl/glcpp/tests/027-define-chain-obj-to-func.c b/src/glsl/glcpp/tests/027-define-chain-obj-to-func.c new file mode 100644 index 0000000000..5ccb52caba --- /dev/null +++ b/src/glsl/glcpp/tests/027-define-chain-obj-to-func.c @@ -0,0 +1,3 @@ +#define failure() success +#define foo failure() +foo diff --git a/src/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected b/src/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected new file mode 100644 index 0000000000..aef762e1e6 --- /dev/null +++ b/src/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected @@ -0,0 +1,4 @@ + + +success + diff --git a/src/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c b/src/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c new file mode 100644 index 0000000000..44962a7187 --- /dev/null +++ b/src/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c @@ -0,0 +1,3 @@ +#define success() failure +#define foo success +foo diff --git a/src/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected b/src/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected new file mode 100644 index 0000000000..aef762e1e6 --- /dev/null +++ b/src/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected @@ -0,0 +1,4 @@ + + +success + diff --git a/src/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c b/src/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c new file mode 100644 index 0000000000..261f7d28fc --- /dev/null +++ b/src/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c @@ -0,0 +1,3 @@ +#define bar(failure) failure +#define foo bar(success) +foo diff --git a/src/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected b/src/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected new file mode 100644 index 0000000000..aef762e1e6 --- /dev/null +++ b/src/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected @@ -0,0 +1,4 @@ + + +success + diff --git a/src/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c b/src/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c new file mode 100644 index 0000000000..e56fbefd62 --- /dev/null +++ b/src/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c @@ -0,0 +1,4 @@ +#define baz(failure) failure +#define bar(failure) failure +#define foo bar(baz(success)) +foo diff --git a/src/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected b/src/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected new file mode 100644 index 0000000000..729bdd15f8 --- /dev/null +++ b/src/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected @@ -0,0 +1,5 @@ + + + +success + diff --git a/src/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c b/src/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c new file mode 100644 index 0000000000..3f4c8744df --- /dev/null +++ b/src/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c @@ -0,0 +1,4 @@ +#define baz(failure) failure +#define bar(failure) failure +#define foo() bar(baz(success)) +foo() diff --git a/src/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected b/src/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected new file mode 100644 index 0000000000..729bdd15f8 --- /dev/null +++ b/src/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected @@ -0,0 +1,5 @@ + + + +success + diff --git a/src/glsl/glcpp/tests/032-define-func-self-recurse.c b/src/glsl/glcpp/tests/032-define-func-self-recurse.c new file mode 100644 index 0000000000..b3ac70f499 --- /dev/null +++ b/src/glsl/glcpp/tests/032-define-func-self-recurse.c @@ -0,0 +1,2 @@ +#define foo(a) foo(2*(a)) +foo(3) diff --git a/src/glsl/glcpp/tests/032-define-func-self-recurse.c.expected b/src/glsl/glcpp/tests/032-define-func-self-recurse.c.expected new file mode 100644 index 0000000000..541d44db7a --- /dev/null +++ b/src/glsl/glcpp/tests/032-define-func-self-recurse.c.expected @@ -0,0 +1,3 @@ + +foo(2*(3)) + diff --git a/src/glsl/glcpp/tests/033-define-func-self-compose.c b/src/glsl/glcpp/tests/033-define-func-self-compose.c new file mode 100644 index 0000000000..f65e48286c --- /dev/null +++ b/src/glsl/glcpp/tests/033-define-func-self-compose.c @@ -0,0 +1,2 @@ +#define foo(a) foo(2*(a)) +foo(foo(3)) diff --git a/src/glsl/glcpp/tests/033-define-func-self-compose.c.expected b/src/glsl/glcpp/tests/033-define-func-self-compose.c.expected new file mode 100644 index 0000000000..6ea6905d80 --- /dev/null +++ b/src/glsl/glcpp/tests/033-define-func-self-compose.c.expected @@ -0,0 +1,3 @@ + +foo(2*(foo(2*(3)))) + diff --git a/src/glsl/glcpp/tests/034-define-func-self-compose-non-func.c b/src/glsl/glcpp/tests/034-define-func-self-compose-non-func.c new file mode 100644 index 0000000000..209a5f7e07 --- /dev/null +++ b/src/glsl/glcpp/tests/034-define-func-self-compose-non-func.c @@ -0,0 +1,2 @@ +#define foo(bar) bar +foo(foo) diff --git a/src/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected b/src/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected new file mode 100644 index 0000000000..24823b1b67 --- /dev/null +++ b/src/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected @@ -0,0 +1,3 @@ + +foo + diff --git a/src/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c b/src/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c new file mode 100644 index 0000000000..c307fbe830 --- /dev/null +++ b/src/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c @@ -0,0 +1,2 @@ +#define foo(bar) bar +foo(1+foo) diff --git a/src/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected b/src/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected new file mode 100644 index 0000000000..137a9ea2db --- /dev/null +++ b/src/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected @@ -0,0 +1,3 @@ + +1+foo + diff --git a/src/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c b/src/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c new file mode 100644 index 0000000000..b21ff33673 --- /dev/null +++ b/src/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c @@ -0,0 +1,3 @@ +#define bar success +#define foo(x) x +foo(more bar) diff --git a/src/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected b/src/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected new file mode 100644 index 0000000000..ff6360bfe4 --- /dev/null +++ b/src/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected @@ -0,0 +1,4 @@ + + +more success + diff --git a/src/glsl/glcpp/tests/037-finalize-unexpanded-macro.c b/src/glsl/glcpp/tests/037-finalize-unexpanded-macro.c new file mode 100644 index 0000000000..b3a2f37f1b --- /dev/null +++ b/src/glsl/glcpp/tests/037-finalize-unexpanded-macro.c @@ -0,0 +1,3 @@ +#define expand(x) expand(x once) +#define foo(x) x +foo(expand(just)) diff --git a/src/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected b/src/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected new file mode 100644 index 0000000000..cbadee848a --- /dev/null +++ b/src/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected @@ -0,0 +1,4 @@ + + +expand(just once) + diff --git a/src/glsl/glcpp/tests/038-func-arg-with-commas.c b/src/glsl/glcpp/tests/038-func-arg-with-commas.c new file mode 100644 index 0000000000..1407c7d6e3 --- /dev/null +++ b/src/glsl/glcpp/tests/038-func-arg-with-commas.c @@ -0,0 +1,2 @@ +#define foo(x) success +foo(argument (with,embedded , commas) -- tricky) diff --git a/src/glsl/glcpp/tests/038-func-arg-with-commas.c.expected b/src/glsl/glcpp/tests/038-func-arg-with-commas.c.expected new file mode 100644 index 0000000000..5a28fb3b66 --- /dev/null +++ b/src/glsl/glcpp/tests/038-func-arg-with-commas.c.expected @@ -0,0 +1,3 @@ + +success + diff --git a/src/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c b/src/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c new file mode 100644 index 0000000000..0f7fe632b5 --- /dev/null +++ b/src/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c @@ -0,0 +1,3 @@ +#define foo(a) (a) +#define bar two,words +foo(bar) diff --git a/src/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected b/src/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected new file mode 100644 index 0000000000..b73869d023 --- /dev/null +++ b/src/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected @@ -0,0 +1,4 @@ + + +(two,words) + diff --git a/src/glsl/glcpp/tests/040-token-pasting.c b/src/glsl/glcpp/tests/040-token-pasting.c new file mode 100644 index 0000000000..caab3ba736 --- /dev/null +++ b/src/glsl/glcpp/tests/040-token-pasting.c @@ -0,0 +1,2 @@ +#define paste(a,b) a ## b +paste(one , token) diff --git a/src/glsl/glcpp/tests/040-token-pasting.c.expected b/src/glsl/glcpp/tests/040-token-pasting.c.expected new file mode 100644 index 0000000000..36f6699253 --- /dev/null +++ b/src/glsl/glcpp/tests/040-token-pasting.c.expected @@ -0,0 +1,3 @@ + +onetoken + diff --git a/src/glsl/glcpp/tests/041-if-0.c b/src/glsl/glcpp/tests/041-if-0.c new file mode 100644 index 0000000000..2cab677d3e --- /dev/null +++ b/src/glsl/glcpp/tests/041-if-0.c @@ -0,0 +1,5 @@ +success_1 +#if 0 +failure +#endif +success_2 diff --git a/src/glsl/glcpp/tests/041-if-0.c.expected b/src/glsl/glcpp/tests/041-if-0.c.expected new file mode 100644 index 0000000000..3800024c6f --- /dev/null +++ b/src/glsl/glcpp/tests/041-if-0.c.expected @@ -0,0 +1,6 @@ +success_1 + + + +success_2 + diff --git a/src/glsl/glcpp/tests/042-if-1.c b/src/glsl/glcpp/tests/042-if-1.c new file mode 100644 index 0000000000..874a25cf41 --- /dev/null +++ b/src/glsl/glcpp/tests/042-if-1.c @@ -0,0 +1,5 @@ +success_1 +#if 1 +success_2 +#endif +success_3 diff --git a/src/glsl/glcpp/tests/042-if-1.c.expected b/src/glsl/glcpp/tests/042-if-1.c.expected new file mode 100644 index 0000000000..e591044adb --- /dev/null +++ b/src/glsl/glcpp/tests/042-if-1.c.expected @@ -0,0 +1,6 @@ +success_1 + +success_2 + +success_3 + diff --git a/src/glsl/glcpp/tests/043-if-0-else.c b/src/glsl/glcpp/tests/043-if-0-else.c new file mode 100644 index 0000000000..323351f9db --- /dev/null +++ b/src/glsl/glcpp/tests/043-if-0-else.c @@ -0,0 +1,7 @@ +success_1 +#if 0 +failure +#else +success_2 +#endif +success_3 diff --git a/src/glsl/glcpp/tests/043-if-0-else.c.expected b/src/glsl/glcpp/tests/043-if-0-else.c.expected new file mode 100644 index 0000000000..ee9e677096 --- /dev/null +++ b/src/glsl/glcpp/tests/043-if-0-else.c.expected @@ -0,0 +1,8 @@ +success_1 + + + +success_2 + +success_3 + diff --git a/src/glsl/glcpp/tests/044-if-1-else.c b/src/glsl/glcpp/tests/044-if-1-else.c new file mode 100644 index 0000000000..28dfc25c6f --- /dev/null +++ b/src/glsl/glcpp/tests/044-if-1-else.c @@ -0,0 +1,7 @@ +success_1 +#if 1 +success_2 +#else +failure +#endif +success_3 diff --git a/src/glsl/glcpp/tests/044-if-1-else.c.expected b/src/glsl/glcpp/tests/044-if-1-else.c.expected new file mode 100644 index 0000000000..129f5c8542 --- /dev/null +++ b/src/glsl/glcpp/tests/044-if-1-else.c.expected @@ -0,0 +1,8 @@ +success_1 + +success_2 + + + +success_3 + diff --git a/src/glsl/glcpp/tests/045-if-0-elif.c b/src/glsl/glcpp/tests/045-if-0-elif.c new file mode 100644 index 0000000000..e50f686d46 --- /dev/null +++ b/src/glsl/glcpp/tests/045-if-0-elif.c @@ -0,0 +1,11 @@ +success_1 +#if 0 +failure_1 +#elif 0 +failure_2 +#elif 1 +success_3 +#elif 1 +failure_3 +#endif +success_4 diff --git a/src/glsl/glcpp/tests/045-if-0-elif.c.expected b/src/glsl/glcpp/tests/045-if-0-elif.c.expected new file mode 100644 index 0000000000..97a11b4472 --- /dev/null +++ b/src/glsl/glcpp/tests/045-if-0-elif.c.expected @@ -0,0 +1,12 @@ +success_1 + + + + + +success_3 + + + +success_4 + diff --git a/src/glsl/glcpp/tests/046-if-1-elsif.c b/src/glsl/glcpp/tests/046-if-1-elsif.c new file mode 100644 index 0000000000..130515a01e --- /dev/null +++ b/src/glsl/glcpp/tests/046-if-1-elsif.c @@ -0,0 +1,11 @@ +success_1 +#if 1 +success_2 +#elif 0 +failure_1 +#elif 1 +failure_2 +#elif 0 +failure_3 +#endif +success_3 diff --git a/src/glsl/glcpp/tests/046-if-1-elsif.c.expected b/src/glsl/glcpp/tests/046-if-1-elsif.c.expected new file mode 100644 index 0000000000..b928b917e3 --- /dev/null +++ b/src/glsl/glcpp/tests/046-if-1-elsif.c.expected @@ -0,0 +1,12 @@ +success_1 + +success_2 + + + + + + + +success_3 + diff --git a/src/glsl/glcpp/tests/047-if-elif-else.c b/src/glsl/glcpp/tests/047-if-elif-else.c new file mode 100644 index 0000000000..e8f0838a9e --- /dev/null +++ b/src/glsl/glcpp/tests/047-if-elif-else.c @@ -0,0 +1,11 @@ +success_1 +#if 0 +failure_1 +#elif 0 +failure_2 +#elif 0 +failure_3 +#else +success_2 +#endif +success_3 diff --git a/src/glsl/glcpp/tests/047-if-elif-else.c.expected b/src/glsl/glcpp/tests/047-if-elif-else.c.expected new file mode 100644 index 0000000000..e5b53a3fa5 --- /dev/null +++ b/src/glsl/glcpp/tests/047-if-elif-else.c.expected @@ -0,0 +1,12 @@ +success_1 + + + + + + + +success_2 + +success_3 + diff --git a/src/glsl/glcpp/tests/048-if-nested.c b/src/glsl/glcpp/tests/048-if-nested.c new file mode 100644 index 0000000000..fc4679c3be --- /dev/null +++ b/src/glsl/glcpp/tests/048-if-nested.c @@ -0,0 +1,11 @@ +success_1 +#if 0 +failure_1 +#if 1 +failure_2 +#else +failure_3 +#endif +failure_4 +#endif +success_2 diff --git a/src/glsl/glcpp/tests/048-if-nested.c.expected b/src/glsl/glcpp/tests/048-if-nested.c.expected new file mode 100644 index 0000000000..c61fd0b315 --- /dev/null +++ b/src/glsl/glcpp/tests/048-if-nested.c.expected @@ -0,0 +1,12 @@ +success_1 + + + + + + + + + +success_2 + diff --git a/src/glsl/glcpp/tests/049-if-expression-precedence.c b/src/glsl/glcpp/tests/049-if-expression-precedence.c new file mode 100644 index 0000000000..833ea03882 --- /dev/null +++ b/src/glsl/glcpp/tests/049-if-expression-precedence.c @@ -0,0 +1,5 @@ +#if 1 + 2 * 3 + - (25 % 17 - + 1) +failure with operator precedence +#else +success +#endif diff --git a/src/glsl/glcpp/tests/049-if-expression-precedence.c.expected b/src/glsl/glcpp/tests/049-if-expression-precedence.c.expected new file mode 100644 index 0000000000..569debb0bb --- /dev/null +++ b/src/glsl/glcpp/tests/049-if-expression-precedence.c.expected @@ -0,0 +1,6 @@ + + + +success + + diff --git a/src/glsl/glcpp/tests/050-if-defined.c b/src/glsl/glcpp/tests/050-if-defined.c new file mode 100644 index 0000000000..34f0f95140 --- /dev/null +++ b/src/glsl/glcpp/tests/050-if-defined.c @@ -0,0 +1,17 @@ +#if defined foo +failure_1 +#else +success_1 +#endif +#define foo +#if defined foo +success_2 +#else +failure_2 +#endif +#undef foo +#if defined foo +failure_3 +#else +success_3 +#endif diff --git a/src/glsl/glcpp/tests/050-if-defined.c.expected b/src/glsl/glcpp/tests/050-if-defined.c.expected new file mode 100644 index 0000000000..3f01955ee4 --- /dev/null +++ b/src/glsl/glcpp/tests/050-if-defined.c.expected @@ -0,0 +1,18 @@ + + + +success_1 + + + +success_2 + + + + + + + +success_3 + + diff --git a/src/glsl/glcpp/tests/051-if-relational.c b/src/glsl/glcpp/tests/051-if-relational.c new file mode 100644 index 0000000000..c3db488e0d --- /dev/null +++ b/src/glsl/glcpp/tests/051-if-relational.c @@ -0,0 +1,35 @@ +#if 3 < 2 +failure_1 +#else +success_1 +#endif + +#if 3 >= 2 +success_2 +#else +failure_2 +#endif + +#if 2 + 3 <= 5 +success_3 +#else +failure_3 +#endif + +#if 3 - 2 == 1 +success_3 +#else +failure_3 +#endif + +#if 1 > 3 +failure_4 +#else +success_4 +#endif + +#if 1 != 5 +success_5 +#else +failure_5 +#endif diff --git a/src/glsl/glcpp/tests/051-if-relational.c.expected b/src/glsl/glcpp/tests/051-if-relational.c.expected new file mode 100644 index 0000000000..d2b76f1457 --- /dev/null +++ b/src/glsl/glcpp/tests/051-if-relational.c.expected @@ -0,0 +1,36 @@ + + + +success_1 + + + +success_2 + + + + + +success_3 + + + + + +success_3 + + + + + + + +success_4 + + + +success_5 + + + + diff --git a/src/glsl/glcpp/tests/052-if-bitwise.c b/src/glsl/glcpp/tests/052-if-bitwise.c new file mode 100644 index 0000000000..2d8e45eb61 --- /dev/null +++ b/src/glsl/glcpp/tests/052-if-bitwise.c @@ -0,0 +1,20 @@ +#if (0xaaaaaaaa | 0x55555555) != 4294967295 +failure_1 +#else +success_1 +#endif +#if (0x12345678 ^ 0xfdecba98) == 4023971040 +success_2 +#else +failure_2 +#endif +#if (~ 0xdeadbeef) != -3735928560 +failure_3 +#else +success_3 +#endif +#if (0667 & 0733) == 403 +success_4 +#else +failure_4 +#endif diff --git a/src/glsl/glcpp/tests/052-if-bitwise.c.expected b/src/glsl/glcpp/tests/052-if-bitwise.c.expected new file mode 100644 index 0000000000..bb5d92e8d9 --- /dev/null +++ b/src/glsl/glcpp/tests/052-if-bitwise.c.expected @@ -0,0 +1,21 @@ + + + +success_1 + + +success_2 + + + + + + +success_3 + + +success_4 + + + + diff --git a/src/glsl/glcpp/tests/053-if-divide-and-shift.c b/src/glsl/glcpp/tests/053-if-divide-and-shift.c new file mode 100644 index 0000000000..d24c54a88d --- /dev/null +++ b/src/glsl/glcpp/tests/053-if-divide-and-shift.c @@ -0,0 +1,15 @@ +#if (15 / 2) != 7 +failure_1 +#else +success_1 +#endif +#if (1 << 12) == 4096 +success_2 +#else +failure_2 +#endif +#if (31762 >> 8) != 124 +failure_3 +#else +success_3 +#endif diff --git a/src/glsl/glcpp/tests/053-if-divide-and-shift.c.expected b/src/glsl/glcpp/tests/053-if-divide-and-shift.c.expected new file mode 100644 index 0000000000..f97e93673c --- /dev/null +++ b/src/glsl/glcpp/tests/053-if-divide-and-shift.c.expected @@ -0,0 +1,16 @@ + + + +success_1 + + +success_2 + + + + + + +success_3 + + diff --git a/src/glsl/glcpp/tests/054-if-with-macros.c b/src/glsl/glcpp/tests/054-if-with-macros.c new file mode 100644 index 0000000000..3da79a0d96 --- /dev/null +++ b/src/glsl/glcpp/tests/054-if-with-macros.c @@ -0,0 +1,34 @@ +#define one 1 +#define two 2 +#define three 3 +#define five 5 +#if five < two +failure_1 +#else +success_1 +#endif +#if three >= two +success_2 +#else +failure_2 +#endif +#if two + three <= five +success_3 +#else +failure_3 +#endif +#if five - two == three +success_4 +#else +failure_4 +#endif +#if one > three +failure_5 +#else +success_5 +#endif +#if one != five +success_6 +#else +failure_6 +#endif diff --git a/src/glsl/glcpp/tests/054-if-with-macros.c.expected b/src/glsl/glcpp/tests/054-if-with-macros.c.expected new file mode 100644 index 0000000000..27ea496962 --- /dev/null +++ b/src/glsl/glcpp/tests/054-if-with-macros.c.expected @@ -0,0 +1,35 @@ + + + + + + + +success_1 + + +success_2 + + + + +success_3 + + + + +success_4 + + + + + + +success_5 + + +success_6 + + + + diff --git a/src/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c b/src/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c new file mode 100644 index 0000000000..00f2c2346d --- /dev/null +++ b/src/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c @@ -0,0 +1,3 @@ +#define failure() success +#define foo failure +foo() diff --git a/src/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected b/src/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected new file mode 100644 index 0000000000..aef762e1e6 --- /dev/null +++ b/src/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected @@ -0,0 +1,4 @@ + + +success + diff --git a/src/glsl/glcpp/tests/056-macro-argument-with-comma.c b/src/glsl/glcpp/tests/056-macro-argument-with-comma.c new file mode 100644 index 0000000000..58701d1f25 --- /dev/null +++ b/src/glsl/glcpp/tests/056-macro-argument-with-comma.c @@ -0,0 +1,4 @@ +#define bar with,embedded,commas +#define function(x) success +#define foo function +foo(bar) diff --git a/src/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected b/src/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected new file mode 100644 index 0000000000..729bdd15f8 --- /dev/null +++ b/src/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected @@ -0,0 +1,5 @@ + + + +success + diff --git a/src/glsl/glcpp/tests/057-empty-arguments.c b/src/glsl/glcpp/tests/057-empty-arguments.c new file mode 100644 index 0000000000..6140232865 --- /dev/null +++ b/src/glsl/glcpp/tests/057-empty-arguments.c @@ -0,0 +1,6 @@ +#define zero() success +zero() +#define one(x) success +one() +#define two(x,y) success +two(,) diff --git a/src/glsl/glcpp/tests/057-empty-arguments.c.expected b/src/glsl/glcpp/tests/057-empty-arguments.c.expected new file mode 100644 index 0000000000..4e3aad5217 --- /dev/null +++ b/src/glsl/glcpp/tests/057-empty-arguments.c.expected @@ -0,0 +1,7 @@ + +success + +success + +success + diff --git a/src/glsl/glcpp/tests/058-token-pasting-empty-arguments.c b/src/glsl/glcpp/tests/058-token-pasting-empty-arguments.c new file mode 100644 index 0000000000..8ac260c76b --- /dev/null +++ b/src/glsl/glcpp/tests/058-token-pasting-empty-arguments.c @@ -0,0 +1,5 @@ +#define paste(x,y) x ## y +paste(a,b) +paste(a,) +paste(,b) +paste(,) diff --git a/src/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected b/src/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected new file mode 100644 index 0000000000..a1c34e5c1f --- /dev/null +++ b/src/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected @@ -0,0 +1,6 @@ + +ab +a +b + + diff --git a/src/glsl/glcpp/tests/059-token-pasting-integer.c b/src/glsl/glcpp/tests/059-token-pasting-integer.c new file mode 100644 index 0000000000..37b895a423 --- /dev/null +++ b/src/glsl/glcpp/tests/059-token-pasting-integer.c @@ -0,0 +1,4 @@ +#define paste(x,y) x ## y +paste(1,2) +paste(1,000) +paste(identifier,2) diff --git a/src/glsl/glcpp/tests/059-token-pasting-integer.c.expected b/src/glsl/glcpp/tests/059-token-pasting-integer.c.expected new file mode 100644 index 0000000000..f1a2cd21c1 --- /dev/null +++ b/src/glsl/glcpp/tests/059-token-pasting-integer.c.expected @@ -0,0 +1,5 @@ + +12 +1000 +identifier2 + diff --git a/src/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c b/src/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c new file mode 100644 index 0000000000..ed80ea879c --- /dev/null +++ b/src/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c @@ -0,0 +1,3 @@ +#define double(a) a*2 +#define foo double( +foo 5) diff --git a/src/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected b/src/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected new file mode 100644 index 0000000000..c1f0d24a14 --- /dev/null +++ b/src/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected @@ -0,0 +1,4 @@ + + +5*2 + diff --git a/src/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c b/src/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c new file mode 100644 index 0000000000..6dbfd1f62d --- /dev/null +++ b/src/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c @@ -0,0 +1,5 @@ +#define foo(x) success +#define bar foo +#define baz bar +#define joe baz +joe (failure) diff --git a/src/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected b/src/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected new file mode 100644 index 0000000000..111f7d1063 --- /dev/null +++ b/src/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected @@ -0,0 +1,6 @@ + + + + +success + diff --git a/src/glsl/glcpp/tests/062-if-0-skips-garbage.c b/src/glsl/glcpp/tests/062-if-0-skips-garbage.c new file mode 100644 index 0000000000..d9e439bb89 --- /dev/null +++ b/src/glsl/glcpp/tests/062-if-0-skips-garbage.c @@ -0,0 +1,5 @@ +#define foo(a,b) +#if 0 +foo(bar) +foo( +#endif diff --git a/src/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected b/src/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected new file mode 100644 index 0000000000..6fb66a5e2f --- /dev/null +++ b/src/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/glsl/glcpp/tests/063-comments.c b/src/glsl/glcpp/tests/063-comments.c new file mode 100644 index 0000000000..e641d2f0f9 --- /dev/null +++ b/src/glsl/glcpp/tests/063-comments.c @@ -0,0 +1,20 @@ +/* this is a comment */ +// so is this +// */ +f = g/**//h; +/*//*/l(); +m = n//**/o ++ p; +/* this +comment spans +multiple lines and +contains *** stars +and slashes / *** / +and other stuff. +****/ +more code here +/* Test that /* nested + comments */ +are not treated like comments. +/*/ this is a comment */ +/*/*/ diff --git a/src/glsl/glcpp/tests/063-comments.c.expected b/src/glsl/glcpp/tests/063-comments.c.expected new file mode 100644 index 0000000000..ed4feedd45 --- /dev/null +++ b/src/glsl/glcpp/tests/063-comments.c.expected @@ -0,0 +1,14 @@ + + + +f = g /h; + l(); +m = n ++ p; + +more code here + +are not treated like comments. + + + diff --git a/src/glsl/glcpp/tests/064-version.c b/src/glsl/glcpp/tests/064-version.c new file mode 100644 index 0000000000..21326481b8 --- /dev/null +++ b/src/glsl/glcpp/tests/064-version.c @@ -0,0 +1,2 @@ +#version 130 +#define FOO diff --git a/src/glsl/glcpp/tests/064-version.c.expected b/src/glsl/glcpp/tests/064-version.c.expected new file mode 100644 index 0000000000..3af71113c8 --- /dev/null +++ b/src/glsl/glcpp/tests/064-version.c.expected @@ -0,0 +1,3 @@ +#version 130 + + diff --git a/src/glsl/glcpp/tests/065-if-defined-parens.c b/src/glsl/glcpp/tests/065-if-defined-parens.c new file mode 100644 index 0000000000..48aa0f8c3e --- /dev/null +++ b/src/glsl/glcpp/tests/065-if-defined-parens.c @@ -0,0 +1,17 @@ +#if defined(foo) +failure_1 +#else +success_1 +#endif +#define foo +#if defined ( foo ) +success_2 +#else +failure_2 +#endif +#undef foo +#if defined (foo) +failure_3 +#else +success_3 +#endif diff --git a/src/glsl/glcpp/tests/065-if-defined-parens.c.expected b/src/glsl/glcpp/tests/065-if-defined-parens.c.expected new file mode 100644 index 0000000000..3f01955ee4 --- /dev/null +++ b/src/glsl/glcpp/tests/065-if-defined-parens.c.expected @@ -0,0 +1,18 @@ + + + +success_1 + + + +success_2 + + + + + + + +success_3 + + diff --git a/src/glsl/glcpp/tests/066-if-nospace-expression.c b/src/glsl/glcpp/tests/066-if-nospace-expression.c new file mode 100644 index 0000000000..3b0b47349d --- /dev/null +++ b/src/glsl/glcpp/tests/066-if-nospace-expression.c @@ -0,0 +1,3 @@ +#if(1) +success +#endif diff --git a/src/glsl/glcpp/tests/066-if-nospace-expression.c.expected b/src/glsl/glcpp/tests/066-if-nospace-expression.c.expected new file mode 100644 index 0000000000..0e84a7cda3 --- /dev/null +++ b/src/glsl/glcpp/tests/066-if-nospace-expression.c.expected @@ -0,0 +1,4 @@ + +success + + diff --git a/src/glsl/glcpp/tests/067-nested-ifdef-ifndef.c b/src/glsl/glcpp/tests/067-nested-ifdef-ifndef.c new file mode 100644 index 0000000000..f46cce4e60 --- /dev/null +++ b/src/glsl/glcpp/tests/067-nested-ifdef-ifndef.c @@ -0,0 +1,40 @@ +#define D1 +#define D2 + +#define result success + +#ifdef U1 +#ifdef U2 +#undef result +#define result failure +#endif +#endif +result + +#ifndef D1 +#ifndef D2 +#undef result +#define result failure +#endif +#endif +result + +#undef result +#define result failure +#ifdef D1 +#ifdef D2 +#undef result +#define result success +#endif +#endif +result + +#undef result +#define result failure +#ifndef U1 +#ifndef U2 +#undef result +#define result success +#endif +#endif +result diff --git a/src/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected b/src/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected new file mode 100644 index 0000000000..3340daaa1f --- /dev/null +++ b/src/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected @@ -0,0 +1,41 @@ + + + + + + + + + + + +success + + + + + + + +success + + + + + + + + + +success + + + + + + + + + +success + diff --git a/src/glsl/glcpp/tests/068-accidental-pasting.c b/src/glsl/glcpp/tests/068-accidental-pasting.c new file mode 100644 index 0000000000..699ac5144e --- /dev/null +++ b/src/glsl/glcpp/tests/068-accidental-pasting.c @@ -0,0 +1,11 @@ +#define empty +<empty< +<empty= +>empty> +>empty= +=empty= +!empty= +&empty& +|empty| ++empty+ +-empty- diff --git a/src/glsl/glcpp/tests/068-accidental-pasting.c.expected b/src/glsl/glcpp/tests/068-accidental-pasting.c.expected new file mode 100644 index 0000000000..ce41cd6e52 --- /dev/null +++ b/src/glsl/glcpp/tests/068-accidental-pasting.c.expected @@ -0,0 +1,12 @@ + +< < +< = +> > +> = += = +! = +& & +| | ++ + +- - + diff --git a/src/glsl/glcpp/tests/069-repeated-argument.c b/src/glsl/glcpp/tests/069-repeated-argument.c new file mode 100644 index 0000000000..2b46ead294 --- /dev/null +++ b/src/glsl/glcpp/tests/069-repeated-argument.c @@ -0,0 +1,2 @@ +#define double(x) x x +double(1) diff --git a/src/glsl/glcpp/tests/069-repeated-argument.c.expected b/src/glsl/glcpp/tests/069-repeated-argument.c.expected new file mode 100644 index 0000000000..755c4d4b56 --- /dev/null +++ b/src/glsl/glcpp/tests/069-repeated-argument.c.expected @@ -0,0 +1,3 @@ + +1 1 + diff --git a/src/glsl/glcpp/tests/070-undefined-macro-in-expression.c b/src/glsl/glcpp/tests/070-undefined-macro-in-expression.c new file mode 100644 index 0000000000..b6dc2ba075 --- /dev/null +++ b/src/glsl/glcpp/tests/070-undefined-macro-in-expression.c @@ -0,0 +1,2 @@ +#if UNDEFINED_MACRO +#endif diff --git a/src/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected b/src/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected new file mode 100644 index 0000000000..2bb38a1411 --- /dev/null +++ b/src/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected @@ -0,0 +1,2 @@ +0:1(21): preprocessor error: syntax error, unexpected IDENTIFIER + diff --git a/src/glsl/glcpp/tests/071-punctuator.c b/src/glsl/glcpp/tests/071-punctuator.c new file mode 100644 index 0000000000..959d682598 --- /dev/null +++ b/src/glsl/glcpp/tests/071-punctuator.c @@ -0,0 +1 @@ +a = b diff --git a/src/glsl/glcpp/tests/071-punctuator.c.expected b/src/glsl/glcpp/tests/071-punctuator.c.expected new file mode 100644 index 0000000000..fee253b745 --- /dev/null +++ b/src/glsl/glcpp/tests/071-punctuator.c.expected @@ -0,0 +1,2 @@ +a = b + diff --git a/src/glsl/glcpp/tests/072-token-pasting-same-line.c b/src/glsl/glcpp/tests/072-token-pasting-same-line.c new file mode 100644 index 0000000000..e421e9d5e2 --- /dev/null +++ b/src/glsl/glcpp/tests/072-token-pasting-same-line.c @@ -0,0 +1,2 @@ +#define paste(x) success_ ## x +paste(1) paste(2) paste(3) diff --git a/src/glsl/glcpp/tests/072-token-pasting-same-line.c.expected b/src/glsl/glcpp/tests/072-token-pasting-same-line.c.expected new file mode 100644 index 0000000000..c780b43d70 --- /dev/null +++ b/src/glsl/glcpp/tests/072-token-pasting-same-line.c.expected @@ -0,0 +1,3 @@ + +success_1 success_2 success_3 + diff --git a/src/glsl/glcpp/tests/073-if-in-ifdef.c b/src/glsl/glcpp/tests/073-if-in-ifdef.c new file mode 100644 index 0000000000..61a48097ca --- /dev/null +++ b/src/glsl/glcpp/tests/073-if-in-ifdef.c @@ -0,0 +1,4 @@ +#ifdef UNDEF +#if UNDEF > 1 +#endif +#endif diff --git a/src/glsl/glcpp/tests/073-if-in-ifdef.c.expected b/src/glsl/glcpp/tests/073-if-in-ifdef.c.expected new file mode 100644 index 0000000000..3f2ff2d6cc --- /dev/null +++ b/src/glsl/glcpp/tests/073-if-in-ifdef.c.expected @@ -0,0 +1,5 @@ + + + + + diff --git a/src/glsl/glcpp/tests/074-elif-undef.c b/src/glsl/glcpp/tests/074-elif-undef.c new file mode 100644 index 0000000000..67aac8977e --- /dev/null +++ b/src/glsl/glcpp/tests/074-elif-undef.c @@ -0,0 +1,3 @@ +#ifndef UNDEF +#elif UNDEF < 0 +#endif diff --git a/src/glsl/glcpp/tests/074-elif-undef.c.expected b/src/glsl/glcpp/tests/074-elif-undef.c.expected new file mode 100644 index 0000000000..fd40910d9e --- /dev/null +++ b/src/glsl/glcpp/tests/074-elif-undef.c.expected @@ -0,0 +1,4 @@ + + + + diff --git a/src/glsl/glcpp/tests/075-elif-elif-undef.c b/src/glsl/glcpp/tests/075-elif-elif-undef.c new file mode 100644 index 0000000000..264bc4f10e --- /dev/null +++ b/src/glsl/glcpp/tests/075-elif-elif-undef.c @@ -0,0 +1,4 @@ +#ifndef UNDEF +#elif UNDEF < 0 +#elif UNDEF == 3 +#endif diff --git a/src/glsl/glcpp/tests/075-elif-elif-undef.c.expected b/src/glsl/glcpp/tests/075-elif-elif-undef.c.expected new file mode 100644 index 0000000000..3f2ff2d6cc --- /dev/null +++ b/src/glsl/glcpp/tests/075-elif-elif-undef.c.expected @@ -0,0 +1,5 @@ + + + + + diff --git a/src/glsl/glcpp/tests/076-elif-undef-nested.c b/src/glsl/glcpp/tests/076-elif-undef-nested.c new file mode 100644 index 0000000000..ebd550ed00 --- /dev/null +++ b/src/glsl/glcpp/tests/076-elif-undef-nested.c @@ -0,0 +1,5 @@ +#ifdef UNDEF +#if UNDEF == 4 +#elif UNDEF == 5 +#endif +#endif diff --git a/src/glsl/glcpp/tests/076-elif-undef-nested.c.expected b/src/glsl/glcpp/tests/076-elif-undef-nested.c.expected new file mode 100644 index 0000000000..6fb66a5e2f --- /dev/null +++ b/src/glsl/glcpp/tests/076-elif-undef-nested.c.expected @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/glsl/glcpp/tests/077-else-without-if.c b/src/glsl/glcpp/tests/077-else-without-if.c new file mode 100644 index 0000000000..81f00bfe27 --- /dev/null +++ b/src/glsl/glcpp/tests/077-else-without-if.c @@ -0,0 +1 @@ +#else diff --git a/src/glsl/glcpp/tests/077-else-without-if.c.expected b/src/glsl/glcpp/tests/077-else-without-if.c.expected new file mode 100644 index 0000000000..d289b36356 --- /dev/null +++ b/src/glsl/glcpp/tests/077-else-without-if.c.expected @@ -0,0 +1,4 @@ +0:1(2): preprocessor error: else without #if + + + diff --git a/src/glsl/glcpp/tests/078-elif-without-if.c b/src/glsl/glcpp/tests/078-elif-without-if.c new file mode 100644 index 0000000000..60466b3890 --- /dev/null +++ b/src/glsl/glcpp/tests/078-elif-without-if.c @@ -0,0 +1 @@ +#elif defined FOO diff --git a/src/glsl/glcpp/tests/078-elif-without-if.c.expected b/src/glsl/glcpp/tests/078-elif-without-if.c.expected new file mode 100644 index 0000000000..7d41f0ac79 --- /dev/null +++ b/src/glsl/glcpp/tests/078-elif-without-if.c.expected @@ -0,0 +1,4 @@ +0:1(2): preprocessor error: elif without #if + + + diff --git a/src/glsl/glcpp/tests/079-endif-without-if.c b/src/glsl/glcpp/tests/079-endif-without-if.c new file mode 100644 index 0000000000..69331c3ca9 --- /dev/null +++ b/src/glsl/glcpp/tests/079-endif-without-if.c @@ -0,0 +1 @@ +#endif diff --git a/src/glsl/glcpp/tests/079-endif-without-if.c.expected b/src/glsl/glcpp/tests/079-endif-without-if.c.expected new file mode 100644 index 0000000000..08dd33546f --- /dev/null +++ b/src/glsl/glcpp/tests/079-endif-without-if.c.expected @@ -0,0 +1,4 @@ +0:1(2): preprocessor error: #endif without #if + + + diff --git a/src/glsl/glcpp/tests/080-if-without-expression.c b/src/glsl/glcpp/tests/080-if-without-expression.c new file mode 100644 index 0000000000..a27ba36a36 --- /dev/null +++ b/src/glsl/glcpp/tests/080-if-without-expression.c @@ -0,0 +1,4 @@ +/* Error message for unskipped #if with no expression. */ +#if +#endif + diff --git a/src/glsl/glcpp/tests/080-if-without-expression.c.expected b/src/glsl/glcpp/tests/080-if-without-expression.c.expected new file mode 100644 index 0000000000..768ba0f473 --- /dev/null +++ b/src/glsl/glcpp/tests/080-if-without-expression.c.expected @@ -0,0 +1,6 @@ +0:2(1): preprocessor error: #if with no expression + + + + + diff --git a/src/glsl/glcpp/tests/081-elif-without-expression.c b/src/glsl/glcpp/tests/081-elif-without-expression.c new file mode 100644 index 0000000000..79c78663dd --- /dev/null +++ b/src/glsl/glcpp/tests/081-elif-without-expression.c @@ -0,0 +1,3 @@ +#if 0 +#elif +#endif diff --git a/src/glsl/glcpp/tests/081-elif-without-expression.c.expected b/src/glsl/glcpp/tests/081-elif-without-expression.c.expected new file mode 100644 index 0000000000..974f0f550e --- /dev/null +++ b/src/glsl/glcpp/tests/081-elif-without-expression.c.expected @@ -0,0 +1,5 @@ +0:2(1): preprocessor error: #elif with no expression + + + + diff --git a/src/glsl/glcpp/tests/082-invalid-paste.c b/src/glsl/glcpp/tests/082-invalid-paste.c new file mode 100644 index 0000000000..40bf64411c --- /dev/null +++ b/src/glsl/glcpp/tests/082-invalid-paste.c @@ -0,0 +1,2 @@ +#define PASTE(x,y) x ## y +PASTE(<,>) diff --git a/src/glsl/glcpp/tests/082-invalid-paste.c.expected b/src/glsl/glcpp/tests/082-invalid-paste.c.expected new file mode 100644 index 0000000000..2c924406b5 --- /dev/null +++ b/src/glsl/glcpp/tests/082-invalid-paste.c.expected @@ -0,0 +1,5 @@ +0:2(7): preprocessor error: +Pasting "<" and ">" does not give a valid preprocessing token. + +< + diff --git a/src/glsl/glcpp/tests/083-unterminated-if.c b/src/glsl/glcpp/tests/083-unterminated-if.c new file mode 100644 index 0000000000..9180635092 --- /dev/null +++ b/src/glsl/glcpp/tests/083-unterminated-if.c @@ -0,0 +1,2 @@ +#if 1 + diff --git a/src/glsl/glcpp/tests/083-unterminated-if.c.expected b/src/glsl/glcpp/tests/083-unterminated-if.c.expected new file mode 100644 index 0000000000..a69f8bab58 --- /dev/null +++ b/src/glsl/glcpp/tests/083-unterminated-if.c.expected @@ -0,0 +1,5 @@ +0:1(7): preprocessor error: Unterminated #if + + + + diff --git a/src/glsl/glcpp/tests/084-unbalanced-parentheses.c b/src/glsl/glcpp/tests/084-unbalanced-parentheses.c new file mode 100644 index 0000000000..0789ba5e52 --- /dev/null +++ b/src/glsl/glcpp/tests/084-unbalanced-parentheses.c @@ -0,0 +1,2 @@ +#define FUNC(x) (2*(x)) +FUNC(23 diff --git a/src/glsl/glcpp/tests/085-incorrect-argument-count.c b/src/glsl/glcpp/tests/085-incorrect-argument-count.c new file mode 100644 index 0000000000..91bea60061 --- /dev/null +++ b/src/glsl/glcpp/tests/085-incorrect-argument-count.c @@ -0,0 +1,5 @@ +#define MULT(x,y) ((x)*(y)) +MULT() +MULT(1) +MULT(1,2,3) + diff --git a/src/glsl/glcpp/tests/085-incorrect-argument-count.c.expected b/src/glsl/glcpp/tests/085-incorrect-argument-count.c.expected new file mode 100644 index 0000000000..1df30cbb56 --- /dev/null +++ b/src/glsl/glcpp/tests/085-incorrect-argument-count.c.expected @@ -0,0 +1,12 @@ +0:2(1): preprocessor error: Error: macro MULT invoked with 1 arguments (expected 2) + +0:3(1): preprocessor error: Error: macro MULT invoked with 1 arguments (expected 2) + +0:4(1): preprocessor error: Error: macro MULT invoked with 3 arguments (expected 2) + + +MULT() +MULT(1) +MULT(1,2,3) + + diff --git a/src/glsl/glcpp/tests/086-reserved-macro-names.c b/src/glsl/glcpp/tests/086-reserved-macro-names.c new file mode 100644 index 0000000000..fd0c29f0c4 --- /dev/null +++ b/src/glsl/glcpp/tests/086-reserved-macro-names.c @@ -0,0 +1,2 @@ +#define __BAD reserved +#define GL_ALSO_BAD() also reserved diff --git a/src/glsl/glcpp/tests/086-reserved-macro-names.c.expected b/src/glsl/glcpp/tests/086-reserved-macro-names.c.expected new file mode 100644 index 0000000000..6a9df68268 --- /dev/null +++ b/src/glsl/glcpp/tests/086-reserved-macro-names.c.expected @@ -0,0 +1,7 @@ +0:1(10): preprocessor error: Macro names starting with "__" are reserved. + +0:2(9): preprocessor error: Macro names starting with "GL_" are reserved. + + + + diff --git a/src/glsl/glcpp/tests/087-if-comments.c b/src/glsl/glcpp/tests/087-if-comments.c new file mode 100644 index 0000000000..ce8dc43057 --- /dev/null +++ b/src/glsl/glcpp/tests/087-if-comments.c @@ -0,0 +1,5 @@ +#if (1 == 0) // dangerous comment +fail +#else +win +#endif diff --git a/src/glsl/glcpp/tests/087-if-comments.c.expected b/src/glsl/glcpp/tests/087-if-comments.c.expected new file mode 100644 index 0000000000..827e548fe5 --- /dev/null +++ b/src/glsl/glcpp/tests/087-if-comments.c.expected @@ -0,0 +1,6 @@ + + + +win + + diff --git a/src/glsl/glcpp/tests/088-redefine-macro-legitimate.c b/src/glsl/glcpp/tests/088-redefine-macro-legitimate.c new file mode 100644 index 0000000000..0e0666b8b3 --- /dev/null +++ b/src/glsl/glcpp/tests/088-redefine-macro-legitimate.c @@ -0,0 +1,5 @@ +#define abc 123 +#define abc 123 + +#define foo(x) (x)+23 +#define foo(x) ( x ) + 23 diff --git a/src/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected b/src/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected new file mode 100644 index 0000000000..6fb66a5e2f --- /dev/null +++ b/src/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/glsl/glcpp/tests/089-redefine-macro-error.c b/src/glsl/glcpp/tests/089-redefine-macro-error.c new file mode 100644 index 0000000000..b3d1391e16 --- /dev/null +++ b/src/glsl/glcpp/tests/089-redefine-macro-error.c @@ -0,0 +1,17 @@ +#define x y +#define x z + +#define abc 123 +#define abc() 123 + +#define foo() bar +#define foo(x) bar + +#define bar() baz +#define bar baz + +#define biff(a,b) a+b +#define biff(a,b,c) a+b + +#define oper(a,b) a+b +#define oper(a,b) a*b diff --git a/src/glsl/glcpp/tests/089-redefine-macro-error.c.expected b/src/glsl/glcpp/tests/089-redefine-macro-error.c.expected new file mode 100644 index 0000000000..6209ead559 --- /dev/null +++ b/src/glsl/glcpp/tests/089-redefine-macro-error.c.expected @@ -0,0 +1,30 @@ +0:2(9): preprocessor error: Redefinition of macro x + +0:5(9): preprocessor error: Redefinition of macro abc + +0:8(9): preprocessor error: Redefinition of macro foo + +0:11(9): preprocessor error: Redefinition of macro bar + +0:14(9): preprocessor error: Redefinition of macro biff + +0:17(9): preprocessor error: Redefinition of macro oper + + + + + + + + + + + + + + + + + + + diff --git a/src/glsl/glcpp/tests/090-hash-error.c b/src/glsl/glcpp/tests/090-hash-error.c new file mode 100644 index 0000000000..d19bb7faed --- /dev/null +++ b/src/glsl/glcpp/tests/090-hash-error.c @@ -0,0 +1 @@ +#error human error diff --git a/src/glsl/glcpp/tests/090-hash-error.c.expected b/src/glsl/glcpp/tests/090-hash-error.c.expected new file mode 100644 index 0000000000..f2f1fbeaf8 --- /dev/null +++ b/src/glsl/glcpp/tests/090-hash-error.c.expected @@ -0,0 +1,3 @@ +0:1(2): preprocessor error: #error human error + + diff --git a/src/glsl/glcpp/tests/091-hash-line.c b/src/glsl/glcpp/tests/091-hash-line.c new file mode 100644 index 0000000000..fea35d37b0 --- /dev/null +++ b/src/glsl/glcpp/tests/091-hash-line.c @@ -0,0 +1,8 @@ +#line 0 +#error line 0 error +#line 25 +#error line 25 error +#line 0 1 +#error source 1, line 0 error +#line 30 2 +#error source 2, line 30 error diff --git a/src/glsl/glcpp/tests/091-hash-line.c.expected b/src/glsl/glcpp/tests/091-hash-line.c.expected new file mode 100644 index 0000000000..e663398c16 --- /dev/null +++ b/src/glsl/glcpp/tests/091-hash-line.c.expected @@ -0,0 +1,13 @@ +0:0(1): preprocessor error: #error line 0 error +0:25(1): preprocessor error: #error line 25 error +1:0(1): preprocessor error: #error source 1, line 0 error +2:30(1): preprocessor error: #error source 2, line 30 error + + + + + + + + + diff --git a/src/glsl/glcpp/tests/099-c99-example.c b/src/glsl/glcpp/tests/099-c99-example.c new file mode 100644 index 0000000000..d1976b1f26 --- /dev/null +++ b/src/glsl/glcpp/tests/099-c99-example.c @@ -0,0 +1,17 @@ +#define x 3 +#define f(a) f(x * (a)) +#undef x +#define x 2 +#define g f +#define z z[0] +#define h g(~ +#define m(a) a(w) +#define w 0,1 +#define t(a) a +#define p() int +#define q(x) x +#define r(x,y) x ## y +f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); +g(x +(3,4)-w) | h 5) & m + (f)^m(m); +p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,)}; diff --git a/src/glsl/glcpp/tests/099-c99-example.c.expected b/src/glsl/glcpp/tests/099-c99-example.c.expected new file mode 100644 index 0000000000..19be750555 --- /dev/null +++ b/src/glsl/glcpp/tests/099-c99-example.c.expected @@ -0,0 +1,17 @@ + + + + + + + + + + + + + +f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); +f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); +int i[] = { 1, 23, 4, 5, }; + diff --git a/src/glsl/glcpp/tests/glcpp-test b/src/glsl/glcpp/tests/glcpp-test new file mode 100755 index 0000000000..5dc08ea6ac --- /dev/null +++ b/src/glsl/glcpp/tests/glcpp-test @@ -0,0 +1,50 @@ +#!/bin/sh + +trap 'rm $test.valgrind-errors; exit 1' INT QUIT + +total=0 +pass=0 +clean=0 + +echo "====== Testing for correctness ======" +for test in *.c; do + echo -n "Testing $test..." + ../glcpp < $test > $test.out 2>&1 + total=$((total+1)) + if cmp $test.expected $test.out >/dev/null 2>&1; then + echo "PASS" + pass=$((pass+1)) + else + echo "FAIL" + diff -u $test.expected $test.out + fi +done + +echo "" +echo "$pass/$total tests returned correct results" +echo "" + +echo "====== Testing for valgrind cleanliness ======" +for test in *.c; do + echo -n "Testing $test with valgrind..." + valgrind --error-exitcode=31 --log-file=$test.valgrind-errors ../glcpp < $test >/dev/null 2>&1 + if [ "$?" = "31" ]; then + echo "ERRORS" + cat $test.valgrind-errors + else + echo "CLEAN" + clean=$((clean+1)) + rm $test.valgrind-errors + fi +done + +echo "" +echo "$pass/$total tests returned correct results" +echo "$clean/$total tests are valgrind-clean" + +if [ "$pass" = "$total" ] && [ "$clean" = "$total" ]; then + exit 0 +else + exit 1 +fi + diff --git a/src/glsl/glsl_lexer.cpp b/src/glsl/glsl_lexer.cpp new file mode 100644 index 0000000000..873df609d3 --- /dev/null +++ b/src/glsl/glsl_lexer.cpp @@ -0,0 +1,3492 @@ +#line 2 "glsl_lexer.cpp" + +#line 4 "glsl_lexer.cpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE _mesa_glsl_restart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via _mesa_glsl_restart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void _mesa_glsl_restart (FILE *input_file ,yyscan_t yyscanner ); +void _mesa_glsl__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE _mesa_glsl__create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void _mesa_glsl__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void _mesa_glsl__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void _mesa_glsl_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void _mesa_glsl_pop_buffer_state (yyscan_t yyscanner ); + +static void _mesa_glsl_ensure_buffer_stack (yyscan_t yyscanner ); +static void _mesa_glsl__load_buffer_state (yyscan_t yyscanner ); +static void _mesa_glsl__init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER _mesa_glsl__flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE _mesa_glsl__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE _mesa_glsl__scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE _mesa_glsl__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *_mesa_glsl_alloc (yy_size_t ,yyscan_t yyscanner ); +void *_mesa_glsl_realloc (void *,yy_size_t ,yyscan_t yyscanner ); +void _mesa_glsl_free (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer _mesa_glsl__create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + _mesa_glsl_ensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + _mesa_glsl__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + _mesa_glsl_ensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + _mesa_glsl__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define _mesa_glsl_wrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 183 +#define YY_END_OF_BUFFER 184 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[708] = + { 0, + 0, 0, 15, 15, 0, 0, 184, 182, 1, 20, + 182, 182, 182, 182, 182, 182, 182, 182, 96, 94, + 182, 182, 182, 181, 182, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 182, 1, 182, 91, 183, + 15, 19, 183, 18, 16, 17, 13, 12, 1, 80, + 87, 81, 90, 84, 75, 86, 76, 93, 98, 85, + 99, 96, 0, 0, 101, 0, 94, 0, 77, 79, + 78, 0, 181, 83, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 28, 181, 181, 181, + + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 32, 181, 181, 56, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 92, 82, 1, 0, 0, + 2, 0, 0, 0, 0, 15, 14, 18, 17, 0, + 98, 97, 0, 99, 0, 100, 95, 88, 89, 181, + 104, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 31, 181, 181, 181, 181, 181, 181, 181, + + 181, 181, 181, 25, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 57, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 0, 0, 0, 0, 14, 0, 98, 0, + 97, 0, 99, 100, 181, 181, 23, 181, 181, 144, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 30, + 107, 181, 181, 181, 181, 63, 181, 181, 112, 126, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 123, 147, 44, 45, 46, 181, 181, 181, 181, + + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 110, 102, 181, 181, + 181, 181, 181, 181, 181, 41, 42, 43, 73, 181, + 181, 0, 0, 0, 0, 0, 97, 181, 181, 26, + 35, 36, 37, 181, 105, 181, 22, 181, 181, 181, + 181, 134, 135, 136, 181, 103, 181, 127, 24, 137, + 138, 139, 149, 131, 132, 133, 181, 181, 181, 58, + 129, 181, 181, 38, 39, 40, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 124, 181, 181, 181, 181, 181, 181, 181, + + 181, 181, 181, 106, 181, 146, 181, 181, 29, 0, + 0, 0, 0, 153, 181, 181, 151, 181, 181, 181, + 125, 120, 156, 181, 181, 181, 181, 181, 181, 115, + 181, 181, 74, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 181, 181, 181, 181, 130, 111, 181, 181, + 118, 34, 181, 181, 143, 64, 119, 72, 154, 113, + 181, 181, 181, 181, 181, 181, 181, 0, 0, 0, + 0, 181, 181, 181, 114, 33, 181, 181, 181, 181, + 181, 181, 157, 158, 159, 181, 181, 181, 181, 148, + 181, 181, 181, 181, 181, 181, 181, 181, 108, 181, + + 181, 181, 181, 181, 59, 181, 60, 181, 0, 0, + 0, 0, 0, 181, 61, 27, 121, 161, 162, 163, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 116, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 109, 165, 166, 167, 181, 181, 128, 117, 0, + 0, 6, 0, 0, 0, 11, 3, 21, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 160, 122, 62, + 145, 181, 152, 150, 180, 66, 67, 68, 181, 181, + 181, 181, 181, 181, 0, 0, 0, 0, 0, 0, + 181, 181, 181, 164, 181, 181, 181, 181, 181, 181, + + 181, 181, 181, 181, 181, 181, 181, 181, 181, 168, + 4, 0, 5, 0, 0, 0, 0, 0, 181, 181, + 181, 181, 181, 181, 181, 177, 181, 181, 181, 181, + 181, 181, 69, 181, 181, 181, 0, 0, 0, 181, + 181, 178, 169, 181, 170, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 179, 0, 0, 171, 172, 175, + 176, 65, 181, 140, 181, 141, 155, 173, 174, 0, + 0, 181, 181, 181, 0, 0, 0, 70, 181, 71, + 0, 0, 0, 181, 0, 0, 0, 181, 0, 0, + 7, 0, 0, 181, 0, 8, 0, 0, 142, 0, + + 0, 0, 0, 9, 0, 10, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 5, 1, 6, 1, 7, 8, 1, 9, + 10, 11, 12, 1, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 21, 21, 22, 22, 23, 1, 24, + 25, 26, 1, 1, 27, 28, 29, 30, 31, 32, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 34, 35, 33, 33, 33, 33, 36, 33, 33, + 1, 1, 1, 37, 38, 1, 39, 40, 41, 42, + + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 33, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 1, 64, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[65] = + { 0, + 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, + 4, 5, 1, 1, 1, 1, 6, 6, 6, 6, + 5, 5, 7, 7, 7, 8, 1, 7, 6, 6, + 6, 6, 5, 5, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 7, 7, 1 + } ; + +static yyconst flex_int16_t yy_base[719] = + { 0, + 0, 63, 88, 0, 1076, 1075, 1077, 1080, 64, 1080, + 1051, 1050, 59, 1049, 58, 60, 58, 1048, 139, 187, + 47, 1047, 56, 0, 1034, 121, 110, 137, 138, 134, + 163, 1017, 173, 177, 115, 149, 140, 1011, 159, 121, + 187, 194, 194, 172, 1022, 171, 249, 240, 1042, 1080, + 250, 1080, 1051, 241, 1080, 0, 1080, 1080, 262, 1080, + 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 236, 1080, + 238, 187, 286, 303, 1080, 0, 0, 1040, 1080, 1080, + 1080, 1039, 0, 1080, 1006, 1011, 1004, 1007, 1016, 1015, + 1001, 1004, 1016, 35, 1010, 997, 994, 1008, 994, 991, + + 991, 997, 215, 232, 991, 1002, 987, 993, 997, 998, + 0, 989, 1000, 234, 995, 975, 226, 979, 993, 983, + 119, 976, 234, 989, 991, 973, 969, 977, 974, 963, + 972, 256, 970, 976, 971, 974, 962, 965, 967, 245, + 970, 961, 974, 227, 967, 1080, 1080, 308, 294, 324, + 1080, 952, 965, 956, 967, 329, 0, 338, 0, 368, + 1080, 303, 379, 1080, 386, 393, 0, 1080, 1080, 962, + 0, 953, 957, 967, 964, 947, 946, 946, 950, 216, + 961, 958, 958, 956, 953, 944, 951, 937, 935, 948, + 933, 950, 0, 947, 934, 942, 939, 943, 944, 937, + + 934, 922, 921, 935, 938, 935, 922, 929, 919, 320, + 925, 928, 918, 926, 914, 918, 909, 924, 914, 905, + 924, 907, 905, 916, 905, 900, 898, 912, 897, 899, + 896, 908, 907, 910, 288, 901, 895, 884, 331, 903, + 905, 893, 885, 889, 901, 884, 0, 400, 410, 427, + 1080, 439, 446, 1080, 879, 890, 0, 887, 343, 0, + 880, 878, 880, 875, 884, 872, 890, 878, 346, 0, + 0, 872, 883, 882, 882, 0, 866, 350, 0, 0, + 868, 353, 876, 877, 867, 861, 860, 861, 860, 357, + 856, 0, 0, 852, 851, 850, 852, 853, 858, 852, + + 848, 862, 857, 856, 855, 846, 849, 849, 841, 844, + 839, 848, 853, 838, 851, 841, 0, 0, 848, 844, + 835, 835, 841, 840, 837, 0, 0, 0, 0, 826, + 839, 838, 837, 834, 822, 453, 463, 834, 836, 0, + 0, 0, 0, 822, 0, 822, 0, 821, 822, 816, + 827, 0, 0, 0, 817, 0, 813, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 824, 469, 823, 0, + 0, 821, 817, 0, 0, 0, 806, 415, 432, 473, + 811, 807, 813, 803, 801, 815, 799, 799, 813, 801, + 813, 808, 0, 806, 803, 807, 790, 792, 799, 805, + + 800, 799, 786, 0, 788, 0, 787, 791, 0, 785, + 834, 784, 787, 0, 775, 785, 0, 773, 773, 787, + 0, 789, 0, 482, 797, 796, 795, 766, 765, 0, + 783, 782, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 766, 780, 766, 763, 0, 0, 769, 768, + 0, 0, 766, 758, 0, 0, 0, 0, 0, 0, + 755, 767, 485, 759, 766, 763, 757, 750, 503, 766, + 751, 746, 760, 758, 0, 0, 750, 769, 768, 767, + 738, 737, 301, 481, 0, 750, 753, 751, 739, 0, + 749, 746, 745, 734, 733, 732, 509, 741, 0, 753, + + 752, 751, 722, 721, 0, 736, 0, 734, 729, 515, + 527, 773, 722, 730, 0, 0, 0, 745, 744, 0, + 726, 729, 713, 721, 711, 719, 720, 720, 719, 704, + 717, 0, 718, 706, 705, 701, 725, 724, 723, 694, + 693, 0, 723, 722, 0, 704, 707, 0, 0, 693, + 537, 1080, 561, 0, 567, 340, 1080, 0, 690, 689, + 699, 699, 686, 701, 684, 699, 694, 0, 0, 0, + 0, 679, 0, 0, 0, 700, 389, 700, 689, 692, + 676, 675, 685, 685, 675, 529, 589, 474, 683, 671, + 669, 668, 679, 0, 682, 678, 680, 676, 662, 669, + + 669, 671, 667, 669, 667, 667, 654, 653, 664, 0, + 1080, 531, 1080, 596, 0, 616, 666, 648, 665, 664, + 647, 635, 643, 633, 634, 0, 627, 646, 635, 607, + 604, 601, 0, 604, 603, 586, 533, 572, 580, 564, + 563, 0, 0, 564, 0, 540, 554, 552, 516, 530, + 505, 486, 453, 450, 0, 461, 443, 0, 0, 0, + 0, 0, 400, 406, 385, 0, 0, 0, 0, 343, + 389, 319, 267, 249, 487, 341, 235, 0, 200, 0, + 507, 498, 184, 157, 150, 564, 559, 136, 565, 591, + 1080, 593, 550, 112, 594, 1080, 569, 576, 0, 123, + + 619, 621, 637, 1080, 638, 1080, 1080, 648, 653, 658, + 663, 665, 667, 673, 680, 685, 690, 695 + } ; + +static yyconst flex_int16_t yy_def[719] = + { 0, + 707, 1, 707, 3, 708, 708, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 709, 707, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 710, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 711, 707, + 712, 19, 707, 707, 707, 713, 20, 707, 707, 707, + 707, 707, 709, 707, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 714, 707, 710, 707, + 707, 712, 707, 707, 707, 707, 713, 707, 707, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 707, 707, 707, 707, 714, 707, 707, 707, + 707, 707, 707, 707, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 707, 707, 707, 707, 707, 707, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + + 709, 709, 709, 709, 709, 709, 709, 709, 709, 707, + 707, 707, 707, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 707, 707, 707, + 707, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + + 709, 709, 709, 709, 709, 709, 709, 709, 707, 715, + 707, 707, 707, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 707, + 707, 707, 707, 716, 707, 707, 707, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 707, 717, 707, 716, 707, 707, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 707, 707, 707, 707, 718, 707, 707, 707, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 718, 707, 707, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, + 709, 709, 709, 709, 709, 707, 707, 709, 709, 709, + 709, 709, 709, 709, 709, 709, 709, 709, 709, 707, + 707, 709, 709, 709, 707, 707, 707, 709, 709, 709, + 707, 707, 707, 709, 707, 707, 707, 709, 707, 707, + 707, 707, 707, 709, 707, 707, 707, 707, 709, 707, + + 707, 707, 707, 707, 707, 707, 0, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707 + } ; + +static yyconst flex_int16_t yy_nxt[1145] = + { 0, + 8, 9, 10, 9, 11, 8, 12, 13, 8, 8, + 14, 15, 16, 17, 18, 19, 20, 20, 20, 20, + 20, 20, 8, 21, 22, 23, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 25, 24, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 24, 24, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 24, 24, 24, 46, 47, 59, 62, 59, 48, 65, + 78, 79, 67, 69, 69, 69, 69, 69, 69, 69, + 81, 82, 66, 63, 68, 179, 180, 49, 50, 51, + 52, 51, 50, 50, 50, 50, 50, 50, 50, 50, + + 50, 50, 53, 50, 54, 54, 54, 54, 54, 54, + 55, 50, 50, 50, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 50, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 50, 71, 116, 72, 72, 72, 72, 72, 72, + 73, 85, 88, 126, 89, 213, 702, 117, 90, 74, + 75, 699, 214, 127, 76, 91, 86, 87, 120, 92, + 95, 74, 75, 99, 96, 100, 93, 118, 694, 94, + 97, 119, 121, 689, 101, 146, 98, 123, 688, 76, + + 71, 102, 77, 77, 77, 77, 77, 77, 77, 103, + 142, 108, 104, 124, 143, 105, 125, 74, 75, 109, + 111, 106, 707, 112, 144, 128, 687, 113, 114, 74, + 75, 110, 129, 130, 147, 115, 135, 131, 684, 136, + 139, 150, 151, 132, 133, 140, 134, 707, 137, 141, + 148, 156, 59, 156, 149, 138, 158, 158, 158, 158, + 158, 158, 158, 59, 189, 59, 160, 161, 163, 164, + 191, 264, 265, 240, 216, 190, 241, 208, 160, 161, + 163, 164, 152, 201, 192, 209, 202, 203, 217, 153, + 204, 235, 205, 154, 226, 150, 151, 683, 155, 71, + + 236, 73, 73, 73, 73, 73, 73, 73, 680, 148, + 227, 59, 679, 149, 165, 165, 74, 75, 166, 166, + 166, 166, 166, 166, 166, 150, 151, 523, 74, 75, + 156, 321, 156, 250, 251, 524, 152, 294, 295, 296, + 322, 556, 681, 153, 675, 250, 251, 154, 326, 327, + 328, 676, 155, 158, 158, 158, 158, 158, 158, 158, + 341, 342, 343, 352, 353, 354, 152, 360, 361, 362, + 364, 365, 366, 153, 374, 375, 376, 154, 678, 248, + 248, 589, 155, 249, 249, 249, 249, 249, 249, 249, + 252, 252, 590, 682, 253, 253, 253, 253, 253, 253, + + 253, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 166, 166, 166, 249, 249, 249, 249, 249, + 249, 249, 602, 603, 254, 249, 249, 249, 249, 249, + 249, 249, 434, 435, 436, 677, 254, 674, 336, 336, + 673, 161, 337, 337, 337, 337, 337, 337, 337, 437, + 438, 439, 672, 161, 253, 253, 253, 253, 253, 253, + 253, 253, 253, 253, 253, 253, 253, 253, 337, 337, + 337, 337, 337, 337, 337, 551, 552, 164, 337, 337, + 337, 337, 337, 337, 337, 425, 426, 427, 675, 164, + 440, 441, 442, 671, 251, 676, 428, 429, 478, 479, + + 480, 500, 501, 502, 469, 670, 251, 525, 681, 481, + 482, 669, 503, 504, 668, 526, 551, 552, 510, 511, + 511, 511, 511, 511, 511, 537, 538, 539, 551, 552, + 612, 613, 612, 613, 612, 613, 540, 541, 551, 552, + 667, 685, 555, 555, 555, 555, 555, 555, 555, 686, + 554, 697, 586, 587, 587, 587, 587, 587, 587, 682, + 692, 666, 551, 552, 615, 690, 695, 693, 551, 552, + 697, 665, 664, 691, 696, 554, 553, 553, 553, 553, + 553, 553, 555, 555, 555, 555, 555, 555, 555, 615, + 612, 613, 690, 663, 692, 695, 662, 612, 613, 661, + + 691, 693, 698, 696, 616, 616, 616, 616, 616, 616, + 616, 614, 614, 614, 614, 614, 614, 612, 613, 700, + 703, 698, 705, 660, 659, 658, 657, 701, 704, 656, + 706, 616, 616, 616, 616, 616, 616, 616, 703, 705, + 655, 654, 653, 652, 651, 650, 704, 706, 57, 57, + 57, 57, 57, 57, 57, 57, 83, 83, 83, 83, + 83, 159, 159, 159, 159, 159, 69, 69, 162, 162, + 167, 167, 167, 247, 247, 649, 247, 247, 247, 247, + 247, 553, 553, 553, 648, 647, 646, 553, 588, 588, + 588, 614, 614, 614, 645, 644, 643, 614, 637, 637, + + 637, 642, 641, 640, 639, 638, 636, 635, 634, 633, + 632, 631, 630, 629, 628, 627, 626, 625, 624, 623, + 622, 621, 620, 619, 618, 617, 611, 610, 609, 608, + 607, 606, 605, 604, 601, 600, 599, 598, 597, 596, + 595, 594, 593, 592, 591, 585, 584, 583, 582, 581, + 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, + 570, 569, 568, 567, 566, 565, 564, 563, 562, 561, + 560, 559, 558, 557, 556, 550, 549, 548, 547, 546, + 545, 544, 543, 542, 536, 535, 534, 533, 532, 531, + 530, 529, 528, 527, 522, 521, 520, 519, 518, 517, + + 516, 515, 514, 513, 512, 509, 508, 507, 506, 505, + 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, + 489, 488, 487, 486, 485, 484, 483, 477, 476, 475, + 474, 473, 472, 471, 470, 469, 468, 467, 466, 465, + 464, 463, 462, 461, 460, 459, 458, 457, 456, 455, + 454, 453, 452, 451, 450, 449, 448, 447, 446, 445, + 444, 443, 433, 432, 431, 430, 424, 423, 422, 421, + 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, + 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, + 400, 399, 398, 397, 396, 395, 394, 393, 392, 391, + + 390, 389, 388, 387, 386, 385, 384, 383, 382, 381, + 380, 379, 378, 377, 373, 372, 371, 370, 369, 368, + 367, 363, 359, 358, 357, 356, 355, 351, 350, 349, + 348, 347, 346, 345, 344, 340, 339, 338, 335, 334, + 333, 332, 331, 330, 329, 325, 324, 323, 320, 319, + 318, 317, 316, 315, 314, 313, 312, 311, 310, 309, + 308, 307, 306, 305, 304, 303, 302, 301, 300, 299, + 298, 297, 293, 292, 291, 290, 289, 288, 287, 286, + 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, + 275, 274, 273, 272, 271, 270, 269, 268, 267, 266, + + 263, 262, 261, 260, 259, 258, 257, 256, 255, 246, + 245, 244, 243, 242, 239, 238, 237, 234, 233, 232, + 231, 230, 229, 228, 225, 224, 223, 222, 221, 220, + 219, 218, 215, 212, 211, 210, 207, 206, 200, 199, + 198, 197, 196, 195, 194, 193, 188, 187, 186, 185, + 184, 183, 182, 181, 178, 177, 176, 175, 174, 173, + 172, 171, 170, 169, 168, 157, 80, 145, 122, 107, + 84, 80, 70, 64, 61, 60, 707, 58, 58, 7, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707 + } ; + +static yyconst flex_int16_t yy_chk[1145] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 9, 13, 9, 2, 15, + 21, 21, 16, 17, 17, 17, 17, 17, 17, 17, + 23, 23, 15, 13, 16, 94, 94, 2, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 19, 35, 19, 19, 19, 19, 19, 19, + 19, 26, 27, 40, 27, 121, 700, 35, 27, 19, + 19, 694, 121, 40, 19, 28, 26, 26, 37, 28, + 29, 19, 19, 30, 29, 30, 28, 36, 688, 28, + 29, 36, 37, 685, 30, 46, 29, 39, 684, 19, + + 20, 31, 20, 20, 20, 20, 20, 20, 20, 31, + 44, 33, 31, 39, 44, 31, 39, 20, 20, 33, + 34, 31, 72, 34, 44, 41, 683, 34, 34, 20, + 20, 33, 41, 41, 46, 34, 42, 41, 679, 42, + 43, 48, 48, 41, 41, 43, 41, 72, 42, 43, + 47, 51, 47, 51, 47, 42, 54, 54, 54, 54, + 54, 54, 54, 59, 103, 59, 69, 69, 71, 71, + 104, 180, 180, 144, 123, 103, 144, 117, 69, 69, + 71, 71, 48, 114, 104, 117, 114, 114, 123, 48, + 114, 140, 114, 48, 132, 149, 149, 677, 48, 73, + + 140, 73, 73, 73, 73, 73, 73, 73, 674, 148, + 132, 148, 673, 148, 74, 74, 73, 73, 74, 74, + 74, 74, 74, 74, 74, 150, 150, 483, 73, 73, + 156, 235, 156, 162, 162, 483, 149, 210, 210, 210, + 235, 556, 676, 149, 670, 162, 162, 149, 239, 239, + 239, 670, 149, 158, 158, 158, 158, 158, 158, 158, + 259, 259, 259, 269, 269, 269, 150, 278, 278, 278, + 282, 282, 282, 150, 290, 290, 290, 150, 672, 160, + 160, 556, 150, 160, 160, 160, 160, 160, 160, 160, + 163, 163, 556, 676, 163, 163, 163, 163, 163, 163, + + 163, 165, 165, 165, 165, 165, 165, 165, 166, 166, + 166, 166, 166, 166, 166, 248, 248, 248, 248, 248, + 248, 248, 577, 577, 166, 249, 249, 249, 249, 249, + 249, 249, 378, 378, 378, 671, 166, 665, 250, 250, + 664, 249, 250, 250, 250, 250, 250, 250, 250, 379, + 379, 379, 663, 249, 252, 252, 252, 252, 252, 252, + 252, 253, 253, 253, 253, 253, 253, 253, 336, 336, + 336, 336, 336, 336, 336, 588, 588, 253, 337, 337, + 337, 337, 337, 337, 337, 368, 368, 368, 675, 253, + 380, 380, 380, 657, 337, 675, 368, 368, 424, 424, + + 424, 463, 463, 463, 469, 656, 337, 484, 681, 424, + 424, 654, 463, 463, 653, 484, 510, 510, 469, 469, + 469, 469, 469, 469, 469, 497, 497, 497, 511, 511, + 586, 586, 612, 612, 637, 637, 497, 497, 551, 551, + 652, 682, 511, 511, 511, 511, 511, 511, 511, 682, + 510, 693, 551, 551, 551, 551, 551, 551, 551, 681, + 687, 651, 553, 553, 586, 686, 689, 687, 555, 555, + 697, 650, 649, 686, 689, 510, 553, 553, 553, 553, + 553, 553, 555, 555, 555, 555, 555, 555, 555, 586, + 587, 587, 690, 648, 692, 695, 647, 614, 614, 646, + + 690, 692, 693, 695, 587, 587, 587, 587, 587, 587, + 587, 614, 614, 614, 614, 614, 614, 616, 616, 698, + 701, 697, 702, 644, 641, 640, 639, 698, 701, 638, + 702, 616, 616, 616, 616, 616, 616, 616, 703, 705, + 636, 635, 634, 632, 631, 630, 703, 705, 708, 708, + 708, 708, 708, 708, 708, 708, 709, 709, 709, 709, + 709, 710, 710, 710, 710, 710, 711, 711, 712, 712, + 713, 713, 713, 714, 714, 629, 714, 714, 714, 714, + 714, 715, 715, 715, 628, 627, 625, 715, 716, 716, + 716, 717, 717, 717, 624, 623, 622, 717, 718, 718, + + 718, 621, 620, 619, 618, 617, 609, 608, 607, 606, + 605, 604, 603, 602, 601, 600, 599, 598, 597, 596, + 595, 593, 592, 591, 590, 589, 585, 584, 583, 582, + 581, 580, 579, 578, 576, 572, 567, 566, 565, 564, + 563, 562, 561, 560, 559, 550, 547, 546, 544, 543, + 541, 540, 539, 538, 537, 536, 535, 534, 533, 531, + 530, 529, 528, 527, 526, 525, 524, 523, 522, 521, + 519, 518, 514, 513, 512, 509, 508, 506, 504, 503, + 502, 501, 500, 498, 496, 495, 494, 493, 492, 491, + 489, 488, 487, 486, 482, 481, 480, 479, 478, 477, + + 474, 473, 472, 471, 470, 468, 467, 466, 465, 464, + 462, 461, 454, 453, 450, 449, 446, 445, 444, 443, + 432, 431, 429, 428, 427, 426, 425, 422, 420, 419, + 418, 416, 415, 413, 412, 411, 410, 408, 407, 405, + 403, 402, 401, 400, 399, 398, 397, 396, 395, 394, + 392, 391, 390, 389, 388, 387, 386, 385, 384, 383, + 382, 381, 377, 373, 372, 369, 367, 357, 355, 351, + 350, 349, 348, 346, 344, 339, 338, 335, 334, 333, + 332, 331, 330, 325, 324, 323, 322, 321, 320, 319, + 316, 315, 314, 313, 312, 311, 310, 309, 308, 307, + + 306, 305, 304, 303, 302, 301, 300, 299, 298, 297, + 296, 295, 294, 291, 289, 288, 287, 286, 285, 284, + 283, 281, 277, 275, 274, 273, 272, 268, 267, 266, + 265, 264, 263, 262, 261, 258, 256, 255, 246, 245, + 244, 243, 242, 241, 240, 238, 237, 236, 234, 233, + 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, + 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, + 212, 211, 209, 208, 207, 206, 205, 204, 203, 202, + 201, 200, 199, 198, 197, 196, 195, 194, 192, 191, + 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, + + 179, 178, 177, 176, 175, 174, 173, 172, 170, 155, + 154, 153, 152, 145, 143, 142, 141, 139, 138, 137, + 136, 135, 134, 133, 131, 130, 129, 128, 127, 126, + 125, 124, 122, 120, 119, 118, 116, 115, 113, 112, + 110, 109, 108, 107, 106, 105, 102, 101, 100, 99, + 98, 97, 96, 95, 93, 92, 91, 90, 89, 88, + 87, 86, 85, 82, 78, 53, 49, 45, 38, 32, + 25, 22, 18, 14, 12, 11, 7, 6, 5, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, + 707, 707, 707, 707 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "glsl_lexer.lpp" +#line 2 "glsl_lexer.lpp" +/* + * Copyright © 2008, 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <ctype.h> +#include "ast.h" +#include "glsl_parser_extras.h" +#include "glsl_parser.h" + +#define YY_USER_ACTION \ + do { \ + yylloc->source = 0; \ + yylloc->first_column = yycolumn + 1; \ + yylloc->first_line = yylineno + 1; \ + yycolumn += yyleng; \ + } while(0); + +#define YY_USER_INIT yylineno = 0; yycolumn = 0; + +#define TOKEN_OR_IDENTIFIER(version, token) \ + do { \ + if (yyextra->language_version >= version) { \ + return token; \ + } else { \ + yylval->identifier = strdup(yytext); \ + return IDENTIFIER; \ + } \ + } while (0) + +#define RESERVED_WORD(version, token) \ + do { \ + if (yyextra->language_version >= version) { \ + return token; \ + } else { \ + _mesa_glsl_error(yylloc, yyextra, \ + "Illegal use of reserved word `%s'", yytext); \ + return ERROR_TOK; \ + } \ + } while (0) + +#line 989 "glsl_lexer.cpp" + +#define INITIAL 0 +#define PP 1 +#define PRAGMA 2 + +#define YY_EXTRA_TYPE struct _mesa_glsl_parse_state * + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int _mesa_glsl_lex_init (yyscan_t* scanner); + +int _mesa_glsl_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int _mesa_glsl_lex_destroy (yyscan_t yyscanner ); + +int _mesa_glsl_get_debug (yyscan_t yyscanner ); + +void _mesa_glsl_set_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE _mesa_glsl_get_extra (yyscan_t yyscanner ); + +void _mesa_glsl_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *_mesa_glsl_get_in (yyscan_t yyscanner ); + +void _mesa_glsl_set_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *_mesa_glsl_get_out (yyscan_t yyscanner ); + +void _mesa_glsl_set_out (FILE * out_str ,yyscan_t yyscanner ); + +int _mesa_glsl_get_leng (yyscan_t yyscanner ); + +char *_mesa_glsl_get_text (yyscan_t yyscanner ); + +int _mesa_glsl_get_lineno (yyscan_t yyscanner ); + +void _mesa_glsl_set_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * _mesa_glsl_get_lval (yyscan_t yyscanner ); + +void _mesa_glsl_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *_mesa_glsl_get_lloc (yyscan_t yyscanner ); + + void _mesa_glsl_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int _mesa_glsl_wrap (yyscan_t yyscanner ); +#else +extern int _mesa_glsl_wrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int _mesa_glsl_lex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int _mesa_glsl_lex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 76 "glsl_lexer.lpp" + + +#line 1231 "glsl_lexer.cpp" + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + _mesa_glsl_ensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + _mesa_glsl__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + _mesa_glsl__load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; + yy_current_state += YY_AT_BOL(); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 708 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 707 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 78 "glsl_lexer.lpp" +; + YY_BREAK +/* Preprocessor tokens. */ +case 2: +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 81 "glsl_lexer.lpp" +; + YY_BREAK +case 3: +YY_RULE_SETUP +#line 82 "glsl_lexer.lpp" +{ BEGIN PP; return VERSION; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 83 "glsl_lexer.lpp" +{ BEGIN PP; return EXTENSION; } + YY_BREAK +case 5: +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 84 "glsl_lexer.lpp" +{ + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; + yylloc->source = strtol(ptr, NULL, 0); + } + YY_BREAK +case 6: +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 99 "glsl_lexer.lpp" +{ + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; + } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 113 "glsl_lexer.lpp" +{ + BEGIN PP; + return PRAGMA_DEBUG_ON; + } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 117 "glsl_lexer.lpp" +{ + BEGIN PP; + return PRAGMA_DEBUG_OFF; + } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 121 "glsl_lexer.lpp" +{ + BEGIN PP; + return PRAGMA_OPTIMIZE_ON; + } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 125 "glsl_lexer.lpp" +{ + BEGIN PP; + return PRAGMA_OPTIMIZE_OFF; + } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 129 "glsl_lexer.lpp" +{ BEGIN PRAGMA; } + YY_BREAK +case 12: +/* rule 12 can match eol */ +YY_RULE_SETUP +#line 131 "glsl_lexer.lpp" +{ BEGIN 0; yylineno++; yycolumn = 0; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 132 "glsl_lexer.lpp" +{ } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 134 "glsl_lexer.lpp" +{ } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 135 "glsl_lexer.lpp" +{ } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 136 "glsl_lexer.lpp" +return COLON; + YY_BREAK +case 17: +YY_RULE_SETUP +#line 137 "glsl_lexer.lpp" +{ + yylval->identifier = strdup(yytext); + return IDENTIFIER; + } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 141 "glsl_lexer.lpp" +{ + yylval->n = strtol(yytext, NULL, 10); + return INTCONSTANT; + } + YY_BREAK +case 19: +/* rule 19 can match eol */ +YY_RULE_SETUP +#line 145 "glsl_lexer.lpp" +{ BEGIN 0; yylineno++; yycolumn = 0; return EOL; } + YY_BREAK +case 20: +/* rule 20 can match eol */ +YY_RULE_SETUP +#line 147 "glsl_lexer.lpp" +{ yylineno++; yycolumn = 0; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 149 "glsl_lexer.lpp" +return ATTRIBUTE; + YY_BREAK +case 22: +YY_RULE_SETUP +#line 150 "glsl_lexer.lpp" +return CONST_TOK; + YY_BREAK +case 23: +YY_RULE_SETUP +#line 151 "glsl_lexer.lpp" +return BOOL_TOK; + YY_BREAK +case 24: +YY_RULE_SETUP +#line 152 "glsl_lexer.lpp" +return FLOAT_TOK; + YY_BREAK +case 25: +YY_RULE_SETUP +#line 153 "glsl_lexer.lpp" +return INT_TOK; + YY_BREAK +case 26: +YY_RULE_SETUP +#line 155 "glsl_lexer.lpp" +return BREAK; + YY_BREAK +case 27: +YY_RULE_SETUP +#line 156 "glsl_lexer.lpp" +return CONTINUE; + YY_BREAK +case 28: +YY_RULE_SETUP +#line 157 "glsl_lexer.lpp" +return DO; + YY_BREAK +case 29: +YY_RULE_SETUP +#line 158 "glsl_lexer.lpp" +return WHILE; + YY_BREAK +case 30: +YY_RULE_SETUP +#line 159 "glsl_lexer.lpp" +return ELSE; + YY_BREAK +case 31: +YY_RULE_SETUP +#line 160 "glsl_lexer.lpp" +return FOR; + YY_BREAK +case 32: +YY_RULE_SETUP +#line 161 "glsl_lexer.lpp" +return IF; + YY_BREAK +case 33: +YY_RULE_SETUP +#line 162 "glsl_lexer.lpp" +return DISCARD; + YY_BREAK +case 34: +YY_RULE_SETUP +#line 163 "glsl_lexer.lpp" +return RETURN; + YY_BREAK +case 35: +YY_RULE_SETUP +#line 165 "glsl_lexer.lpp" +return BVEC2; + YY_BREAK +case 36: +YY_RULE_SETUP +#line 166 "glsl_lexer.lpp" +return BVEC3; + YY_BREAK +case 37: +YY_RULE_SETUP +#line 167 "glsl_lexer.lpp" +return BVEC4; + YY_BREAK +case 38: +YY_RULE_SETUP +#line 168 "glsl_lexer.lpp" +return IVEC2; + YY_BREAK +case 39: +YY_RULE_SETUP +#line 169 "glsl_lexer.lpp" +return IVEC3; + YY_BREAK +case 40: +YY_RULE_SETUP +#line 170 "glsl_lexer.lpp" +return IVEC4; + YY_BREAK +case 41: +YY_RULE_SETUP +#line 171 "glsl_lexer.lpp" +return VEC2; + YY_BREAK +case 42: +YY_RULE_SETUP +#line 172 "glsl_lexer.lpp" +return VEC3; + YY_BREAK +case 43: +YY_RULE_SETUP +#line 173 "glsl_lexer.lpp" +return VEC4; + YY_BREAK +case 44: +YY_RULE_SETUP +#line 174 "glsl_lexer.lpp" +return MAT2X2; + YY_BREAK +case 45: +YY_RULE_SETUP +#line 175 "glsl_lexer.lpp" +return MAT3X3; + YY_BREAK +case 46: +YY_RULE_SETUP +#line 176 "glsl_lexer.lpp" +return MAT4X4; + YY_BREAK +case 47: +YY_RULE_SETUP +#line 177 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MAT2X2); + YY_BREAK +case 48: +YY_RULE_SETUP +#line 178 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MAT2X3); + YY_BREAK +case 49: +YY_RULE_SETUP +#line 179 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MAT2X4); + YY_BREAK +case 50: +YY_RULE_SETUP +#line 180 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MAT3X2); + YY_BREAK +case 51: +YY_RULE_SETUP +#line 181 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MAT3X3); + YY_BREAK +case 52: +YY_RULE_SETUP +#line 182 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MAT3X4); + YY_BREAK +case 53: +YY_RULE_SETUP +#line 183 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MAT4X2); + YY_BREAK +case 54: +YY_RULE_SETUP +#line 184 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MAT4X3); + YY_BREAK +case 55: +YY_RULE_SETUP +#line 185 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MAT4X4); + YY_BREAK +case 56: +YY_RULE_SETUP +#line 187 "glsl_lexer.lpp" +return IN_TOK; + YY_BREAK +case 57: +YY_RULE_SETUP +#line 188 "glsl_lexer.lpp" +return OUT_TOK; + YY_BREAK +case 58: +YY_RULE_SETUP +#line 189 "glsl_lexer.lpp" +return INOUT_TOK; + YY_BREAK +case 59: +YY_RULE_SETUP +#line 190 "glsl_lexer.lpp" +return UNIFORM; + YY_BREAK +case 60: +YY_RULE_SETUP +#line 191 "glsl_lexer.lpp" +return VARYING; + YY_BREAK +case 61: +YY_RULE_SETUP +#line 192 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, CENTROID); + YY_BREAK +case 62: +YY_RULE_SETUP +#line 193 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, INVARIANT); + YY_BREAK +case 63: +YY_RULE_SETUP +#line 195 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, FLAT); + YY_BREAK +case 64: +YY_RULE_SETUP +#line 196 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, SMOOTH); + YY_BREAK +case 65: +YY_RULE_SETUP +#line 197 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, NOPERSPECTIVE); + YY_BREAK +case 66: +YY_RULE_SETUP +#line 199 "glsl_lexer.lpp" +return SAMPLER1D; + YY_BREAK +case 67: +YY_RULE_SETUP +#line 200 "glsl_lexer.lpp" +return SAMPLER2D; + YY_BREAK +case 68: +YY_RULE_SETUP +#line 201 "glsl_lexer.lpp" +return SAMPLER3D; + YY_BREAK +case 69: +YY_RULE_SETUP +#line 202 "glsl_lexer.lpp" +return SAMPLERCUBE; + YY_BREAK +case 70: +YY_RULE_SETUP +#line 203 "glsl_lexer.lpp" +return SAMPLER1DSHADOW; + YY_BREAK +case 71: +YY_RULE_SETUP +#line 204 "glsl_lexer.lpp" +return SAMPLER2DSHADOW; + YY_BREAK +case 72: +YY_RULE_SETUP +#line 206 "glsl_lexer.lpp" +return STRUCT; + YY_BREAK +case 73: +YY_RULE_SETUP +#line 207 "glsl_lexer.lpp" +return VOID_TOK; + YY_BREAK +case 74: +YY_RULE_SETUP +#line 209 "glsl_lexer.lpp" +{ + if ((yyextra->language_version >= 140) + || (yyextra->ARB_fragment_coord_conventions_enable)){ + return LAYOUT_TOK; + } else { + yylval->identifier = strdup(yytext); + return IDENTIFIER; + } + } + YY_BREAK +case 75: +YY_RULE_SETUP +#line 219 "glsl_lexer.lpp" +return INC_OP; + YY_BREAK +case 76: +YY_RULE_SETUP +#line 220 "glsl_lexer.lpp" +return DEC_OP; + YY_BREAK +case 77: +YY_RULE_SETUP +#line 221 "glsl_lexer.lpp" +return LE_OP; + YY_BREAK +case 78: +YY_RULE_SETUP +#line 222 "glsl_lexer.lpp" +return GE_OP; + YY_BREAK +case 79: +YY_RULE_SETUP +#line 223 "glsl_lexer.lpp" +return EQ_OP; + YY_BREAK +case 80: +YY_RULE_SETUP +#line 224 "glsl_lexer.lpp" +return NE_OP; + YY_BREAK +case 81: +YY_RULE_SETUP +#line 225 "glsl_lexer.lpp" +return AND_OP; + YY_BREAK +case 82: +YY_RULE_SETUP +#line 226 "glsl_lexer.lpp" +return OR_OP; + YY_BREAK +case 83: +YY_RULE_SETUP +#line 227 "glsl_lexer.lpp" +return XOR_OP; + YY_BREAK +case 84: +YY_RULE_SETUP +#line 229 "glsl_lexer.lpp" +return MUL_ASSIGN; + YY_BREAK +case 85: +YY_RULE_SETUP +#line 230 "glsl_lexer.lpp" +return DIV_ASSIGN; + YY_BREAK +case 86: +YY_RULE_SETUP +#line 231 "glsl_lexer.lpp" +return ADD_ASSIGN; + YY_BREAK +case 87: +YY_RULE_SETUP +#line 232 "glsl_lexer.lpp" +return MOD_ASSIGN; + YY_BREAK +case 88: +YY_RULE_SETUP +#line 233 "glsl_lexer.lpp" +return LEFT_ASSIGN; + YY_BREAK +case 89: +YY_RULE_SETUP +#line 234 "glsl_lexer.lpp" +return RIGHT_ASSIGN; + YY_BREAK +case 90: +YY_RULE_SETUP +#line 235 "glsl_lexer.lpp" +return AND_ASSIGN; + YY_BREAK +case 91: +YY_RULE_SETUP +#line 236 "glsl_lexer.lpp" +return XOR_ASSIGN; + YY_BREAK +case 92: +YY_RULE_SETUP +#line 237 "glsl_lexer.lpp" +return OR_ASSIGN; + YY_BREAK +case 93: +YY_RULE_SETUP +#line 238 "glsl_lexer.lpp" +return SUB_ASSIGN; + YY_BREAK +case 94: +YY_RULE_SETUP +#line 240 "glsl_lexer.lpp" +{ + yylval->n = strtol(yytext, NULL, 10); + return INTCONSTANT; + } + YY_BREAK +case 95: +YY_RULE_SETUP +#line 244 "glsl_lexer.lpp" +{ + yylval->n = strtol(yytext + 2, NULL, 16); + return INTCONSTANT; + } + YY_BREAK +case 96: +YY_RULE_SETUP +#line 248 "glsl_lexer.lpp" +{ + yylval->n = strtol(yytext, NULL, 8); + return INTCONSTANT; + } + YY_BREAK +case 97: +YY_RULE_SETUP +#line 253 "glsl_lexer.lpp" +{ + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } + YY_BREAK +case 98: +YY_RULE_SETUP +#line 257 "glsl_lexer.lpp" +{ + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } + YY_BREAK +case 99: +YY_RULE_SETUP +#line 261 "glsl_lexer.lpp" +{ + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } + YY_BREAK +case 100: +YY_RULE_SETUP +#line 265 "glsl_lexer.lpp" +{ + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } + YY_BREAK +case 101: +YY_RULE_SETUP +#line 269 "glsl_lexer.lpp" +{ + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } + YY_BREAK +case 102: +YY_RULE_SETUP +#line 274 "glsl_lexer.lpp" +{ + yylval->n = 1; + return BOOLCONSTANT; + } + YY_BREAK +case 103: +YY_RULE_SETUP +#line 278 "glsl_lexer.lpp" +{ + yylval->n = 0; + return BOOLCONSTANT; + } + YY_BREAK +/* Reserved words in GLSL 1.10. */ +case 104: +YY_RULE_SETUP +#line 285 "glsl_lexer.lpp" +RESERVED_WORD(999, ASM); + YY_BREAK +case 105: +YY_RULE_SETUP +#line 286 "glsl_lexer.lpp" +RESERVED_WORD(999, CLASS); + YY_BREAK +case 106: +YY_RULE_SETUP +#line 287 "glsl_lexer.lpp" +RESERVED_WORD(999, UNION); + YY_BREAK +case 107: +YY_RULE_SETUP +#line 288 "glsl_lexer.lpp" +RESERVED_WORD(999, ENUM); + YY_BREAK +case 108: +YY_RULE_SETUP +#line 289 "glsl_lexer.lpp" +RESERVED_WORD(999, TYPEDEF); + YY_BREAK +case 109: +YY_RULE_SETUP +#line 290 "glsl_lexer.lpp" +RESERVED_WORD(999, TEMPLATE); + YY_BREAK +case 110: +YY_RULE_SETUP +#line 291 "glsl_lexer.lpp" +RESERVED_WORD(999, THIS); + YY_BREAK +case 111: +YY_RULE_SETUP +#line 292 "glsl_lexer.lpp" +RESERVED_WORD(999, PACKED_TOK); + YY_BREAK +case 112: +YY_RULE_SETUP +#line 293 "glsl_lexer.lpp" +RESERVED_WORD(999, GOTO); + YY_BREAK +case 113: +YY_RULE_SETUP +#line 294 "glsl_lexer.lpp" +RESERVED_WORD(130, SWITCH); + YY_BREAK +case 114: +YY_RULE_SETUP +#line 295 "glsl_lexer.lpp" +RESERVED_WORD(130, DEFAULT); + YY_BREAK +case 115: +YY_RULE_SETUP +#line 296 "glsl_lexer.lpp" +RESERVED_WORD(999, INLINE_TOK); + YY_BREAK +case 116: +YY_RULE_SETUP +#line 297 "glsl_lexer.lpp" +RESERVED_WORD(999, NOINLINE); + YY_BREAK +case 117: +YY_RULE_SETUP +#line 298 "glsl_lexer.lpp" +RESERVED_WORD(999, VOLATILE); + YY_BREAK +case 118: +YY_RULE_SETUP +#line 299 "glsl_lexer.lpp" +RESERVED_WORD(999, PUBLIC_TOK); + YY_BREAK +case 119: +YY_RULE_SETUP +#line 300 "glsl_lexer.lpp" +RESERVED_WORD(999, STATIC); + YY_BREAK +case 120: +YY_RULE_SETUP +#line 301 "glsl_lexer.lpp" +RESERVED_WORD(999, EXTERN); + YY_BREAK +case 121: +YY_RULE_SETUP +#line 302 "glsl_lexer.lpp" +RESERVED_WORD(999, EXTERNAL); + YY_BREAK +case 122: +YY_RULE_SETUP +#line 303 "glsl_lexer.lpp" +RESERVED_WORD(999, INTERFACE); + YY_BREAK +case 123: +YY_RULE_SETUP +#line 304 "glsl_lexer.lpp" +RESERVED_WORD(999, LONG_TOK); + YY_BREAK +case 124: +YY_RULE_SETUP +#line 305 "glsl_lexer.lpp" +RESERVED_WORD(999, SHORT_TOK); + YY_BREAK +case 125: +YY_RULE_SETUP +#line 306 "glsl_lexer.lpp" +RESERVED_WORD(999, DOUBLE_TOK); + YY_BREAK +case 126: +YY_RULE_SETUP +#line 307 "glsl_lexer.lpp" +RESERVED_WORD(999, HALF); + YY_BREAK +case 127: +YY_RULE_SETUP +#line 308 "glsl_lexer.lpp" +RESERVED_WORD(999, FIXED_TOK); + YY_BREAK +case 128: +YY_RULE_SETUP +#line 309 "glsl_lexer.lpp" +RESERVED_WORD(999, UNSIGNED); + YY_BREAK +case 129: +YY_RULE_SETUP +#line 310 "glsl_lexer.lpp" +RESERVED_WORD(999, INPUT_TOK); + YY_BREAK +case 130: +YY_RULE_SETUP +#line 311 "glsl_lexer.lpp" +RESERVED_WORD(999, OUTPUT); + YY_BREAK +case 131: +YY_RULE_SETUP +#line 312 "glsl_lexer.lpp" +RESERVED_WORD(999, HVEC2); + YY_BREAK +case 132: +YY_RULE_SETUP +#line 313 "glsl_lexer.lpp" +RESERVED_WORD(999, HVEC3); + YY_BREAK +case 133: +YY_RULE_SETUP +#line 314 "glsl_lexer.lpp" +RESERVED_WORD(999, HVEC4); + YY_BREAK +case 134: +YY_RULE_SETUP +#line 315 "glsl_lexer.lpp" +RESERVED_WORD(999, DVEC2); + YY_BREAK +case 135: +YY_RULE_SETUP +#line 316 "glsl_lexer.lpp" +RESERVED_WORD(999, DVEC3); + YY_BREAK +case 136: +YY_RULE_SETUP +#line 317 "glsl_lexer.lpp" +RESERVED_WORD(999, DVEC4); + YY_BREAK +case 137: +YY_RULE_SETUP +#line 318 "glsl_lexer.lpp" +RESERVED_WORD(999, FVEC2); + YY_BREAK +case 138: +YY_RULE_SETUP +#line 319 "glsl_lexer.lpp" +RESERVED_WORD(999, FVEC3); + YY_BREAK +case 139: +YY_RULE_SETUP +#line 320 "glsl_lexer.lpp" +RESERVED_WORD(999, FVEC4); + YY_BREAK +case 140: +YY_RULE_SETUP +#line 321 "glsl_lexer.lpp" +return SAMPLER2DRECT; + YY_BREAK +case 141: +YY_RULE_SETUP +#line 322 "glsl_lexer.lpp" +RESERVED_WORD(999, SAMPLER3DRECT); + YY_BREAK +case 142: +YY_RULE_SETUP +#line 323 "glsl_lexer.lpp" +return SAMPLER2DRECTSHADOW; + YY_BREAK +case 143: +YY_RULE_SETUP +#line 324 "glsl_lexer.lpp" +RESERVED_WORD(999, SIZEOF); + YY_BREAK +case 144: +YY_RULE_SETUP +#line 325 "glsl_lexer.lpp" +RESERVED_WORD(999, CAST); + YY_BREAK +case 145: +YY_RULE_SETUP +#line 326 "glsl_lexer.lpp" +RESERVED_WORD(999, NAMESPACE); + YY_BREAK +case 146: +YY_RULE_SETUP +#line 327 "glsl_lexer.lpp" +RESERVED_WORD(999, USING); + YY_BREAK +/* Additional reserved words in GLSL 1.20. */ +case 147: +YY_RULE_SETUP +#line 330 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, LOWP); + YY_BREAK +case 148: +YY_RULE_SETUP +#line 331 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, MEDIUMP); + YY_BREAK +case 149: +YY_RULE_SETUP +#line 332 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, HIGHP); + YY_BREAK +case 150: +YY_RULE_SETUP +#line 333 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(120, PRECISION); + YY_BREAK +/* Additional reserved words in GLSL 1.30. */ +case 151: +YY_RULE_SETUP +#line 336 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, COMMON); + YY_BREAK +case 152: +YY_RULE_SETUP +#line 337 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, PARTITION); + YY_BREAK +case 153: +YY_RULE_SETUP +#line 338 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, ACTIVE); + YY_BREAK +case 154: +YY_RULE_SETUP +#line 339 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, SUPERP); + YY_BREAK +case 155: +YY_RULE_SETUP +#line 340 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, SAMPLERBUFFER); + YY_BREAK +case 156: +YY_RULE_SETUP +#line 341 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, FILTER); + YY_BREAK +case 157: +YY_RULE_SETUP +#line 342 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IMAGE1D); + YY_BREAK +case 158: +YY_RULE_SETUP +#line 343 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IMAGE2D); + YY_BREAK +case 159: +YY_RULE_SETUP +#line 344 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IMAGE3D); + YY_BREAK +case 160: +YY_RULE_SETUP +#line 345 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IMAGECUBE); + YY_BREAK +case 161: +YY_RULE_SETUP +#line 346 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IIMAGE1D); + YY_BREAK +case 162: +YY_RULE_SETUP +#line 347 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IIMAGE2D); + YY_BREAK +case 163: +YY_RULE_SETUP +#line 348 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IIMAGE3D); + YY_BREAK +case 164: +YY_RULE_SETUP +#line 349 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IIMAGECUBE); + YY_BREAK +case 165: +YY_RULE_SETUP +#line 350 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, UIMAGE1D); + YY_BREAK +case 166: +YY_RULE_SETUP +#line 351 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, UIMAGE2D); + YY_BREAK +case 167: +YY_RULE_SETUP +#line 352 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, UIMAGE3D); + YY_BREAK +case 168: +YY_RULE_SETUP +#line 353 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, UIMAGECUBE); + YY_BREAK +case 169: +YY_RULE_SETUP +#line 354 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IMAGE1DARRAY); + YY_BREAK +case 170: +YY_RULE_SETUP +#line 355 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IMAGE2DARRAY); + YY_BREAK +case 171: +YY_RULE_SETUP +#line 356 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IIMAGE1DARRAY); + YY_BREAK +case 172: +YY_RULE_SETUP +#line 357 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IIMAGE2DARRAY); + YY_BREAK +case 173: +YY_RULE_SETUP +#line 358 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, UIMAGE1DARRAY); + YY_BREAK +case 174: +YY_RULE_SETUP +#line 359 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, UIMAGE2DARRAY); + YY_BREAK +case 175: +YY_RULE_SETUP +#line 360 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IMAGE1DSHADOW); + YY_BREAK +case 176: +YY_RULE_SETUP +#line 361 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IMAGE2DSHADOW); + YY_BREAK +case 177: +YY_RULE_SETUP +#line 362 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IMAGEBUFFER); + YY_BREAK +case 178: +YY_RULE_SETUP +#line 363 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, IIMAGEBUFFER); + YY_BREAK +case 179: +YY_RULE_SETUP +#line 364 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, UIMAGEBUFFER); + YY_BREAK +case 180: +YY_RULE_SETUP +#line 365 "glsl_lexer.lpp" +TOKEN_OR_IDENTIFIER(130, ROW_MAJOR); + YY_BREAK +case 181: +YY_RULE_SETUP +#line 367 "glsl_lexer.lpp" +{ + struct _mesa_glsl_parse_state *state = yyextra; + void *ctx = state; + yylval->identifier = talloc_strdup(ctx, yytext); + return IDENTIFIER; + } + YY_BREAK +case 182: +YY_RULE_SETUP +#line 374 "glsl_lexer.lpp" +{ return yytext[0]; } + YY_BREAK +case 183: +YY_RULE_SETUP +#line 376 "glsl_lexer.lpp" +ECHO; + YY_BREAK +#line 2334 "glsl_lexer.cpp" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(PP): +case YY_STATE_EOF(PRAGMA): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * _mesa_glsl_lex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( _mesa_glsl_wrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of _mesa_glsl_lex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + _mesa_glsl_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + _mesa_glsl_restart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) _mesa_glsl_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 708 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 708 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 707); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + _mesa_glsl_restart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( _mesa_glsl_wrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void _mesa_glsl_restart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + _mesa_glsl_ensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + _mesa_glsl__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + _mesa_glsl__init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + _mesa_glsl__load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void _mesa_glsl__switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * _mesa_glsl_pop_buffer_state(); + * _mesa_glsl_push_buffer_state(new_buffer); + */ + _mesa_glsl_ensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + _mesa_glsl__load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (_mesa_glsl_wrap()) processing, but the only time this flag + * is looked at is after _mesa_glsl_wrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void _mesa_glsl__load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE _mesa_glsl__create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) _mesa_glsl_alloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in _mesa_glsl__create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) _mesa_glsl_alloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in _mesa_glsl__create_buffer()" ); + + b->yy_is_our_buffer = 1; + + _mesa_glsl__init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with _mesa_glsl__create_buffer() + * @param yyscanner The scanner object. + */ + void _mesa_glsl__delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + _mesa_glsl_free((void *) b->yy_ch_buf ,yyscanner ); + + _mesa_glsl_free((void *) b ,yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a _mesa_glsl_restart() or at EOF. + */ + static void _mesa_glsl__init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + _mesa_glsl__flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then _mesa_glsl__init_buffer was _probably_ + * called from _mesa_glsl_restart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void _mesa_glsl__flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + _mesa_glsl__load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void _mesa_glsl_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + _mesa_glsl_ensure_buffer_stack(yyscanner); + + /* This block is copied from _mesa_glsl__switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from _mesa_glsl__switch_to_buffer. */ + _mesa_glsl__load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void _mesa_glsl_pop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + _mesa_glsl__delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + _mesa_glsl__load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void _mesa_glsl_ensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)_mesa_glsl_alloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in _mesa_glsl_ensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)_mesa_glsl_realloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in _mesa_glsl_ensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE _mesa_glsl__scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) _mesa_glsl_alloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in _mesa_glsl__scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + _mesa_glsl__switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to _mesa_glsl_lex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * _mesa_glsl__scan_bytes() instead. + */ +YY_BUFFER_STATE _mesa_glsl__scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return _mesa_glsl__scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to _mesa_glsl_lex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE _mesa_glsl__scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) _mesa_glsl_alloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in _mesa_glsl__scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = _mesa_glsl__scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in _mesa_glsl__scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE _mesa_glsl_get_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int _mesa_glsl_get_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int _mesa_glsl_get_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *_mesa_glsl_get_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *_mesa_glsl_get_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int _mesa_glsl_get_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *_mesa_glsl_get_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void _mesa_glsl_set_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void _mesa_glsl_set_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "_mesa_glsl_set_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void _mesa_glsl_set_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "_mesa_glsl_set_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see _mesa_glsl__switch_to_buffer + */ +void _mesa_glsl_set_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void _mesa_glsl_set_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int _mesa_glsl_get_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void _mesa_glsl_set_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * _mesa_glsl_get_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void _mesa_glsl_set_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *_mesa_glsl_get_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void _mesa_glsl_set_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* _mesa_glsl_lex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int _mesa_glsl_lex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) _mesa_glsl_alloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* _mesa_glsl_lex_init_extra has the same functionality as _mesa_glsl_lex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to _mesa_glsl_alloc in + * the yyextra field. + */ + +int _mesa_glsl_lex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + _mesa_glsl_set_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) _mesa_glsl_alloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + _mesa_glsl_set_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from _mesa_glsl_lex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * _mesa_glsl_lex_init() + */ + return 0; +} + +/* _mesa_glsl_lex_destroy is for both reentrant and non-reentrant scanners. */ +int _mesa_glsl_lex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + _mesa_glsl__delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + _mesa_glsl_pop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + _mesa_glsl_free(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + _mesa_glsl_free(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * _mesa_glsl_lex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + _mesa_glsl_free ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *_mesa_glsl_alloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *_mesa_glsl_realloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void _mesa_glsl_free (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see _mesa_glsl_realloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 376 "glsl_lexer.lpp" + + + +void +_mesa_glsl_lexer_ctor(struct _mesa_glsl_parse_state *state, const char *string) +{ + _mesa_glsl_lex_init_extra(state,& state->scanner); + _mesa_glsl__scan_string(string,state->scanner); +} + +void +_mesa_glsl_lexer_dtor(struct _mesa_glsl_parse_state *state) +{ + _mesa_glsl_lex_destroy(state->scanner); +} + diff --git a/src/glsl/glsl_lexer.lpp b/src/glsl/glsl_lexer.lpp new file mode 100644 index 0000000000..1de1fb4cf7 --- /dev/null +++ b/src/glsl/glsl_lexer.lpp @@ -0,0 +1,389 @@ +%{ +/* + * Copyright © 2008, 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <ctype.h> +#include "ast.h" +#include "glsl_parser_extras.h" +#include "glsl_parser.h" + +#define YY_USER_ACTION \ + do { \ + yylloc->source = 0; \ + yylloc->first_column = yycolumn + 1; \ + yylloc->first_line = yylineno + 1; \ + yycolumn += yyleng; \ + } while(0); + +#define YY_USER_INIT yylineno = 0; yycolumn = 0; + +#define TOKEN_OR_IDENTIFIER(version, token) \ + do { \ + if (yyextra->language_version >= version) { \ + return token; \ + } else { \ + yylval->identifier = strdup(yytext); \ + return IDENTIFIER; \ + } \ + } while (0) + +#define RESERVED_WORD(version, token) \ + do { \ + if (yyextra->language_version >= version) { \ + return token; \ + } else { \ + _mesa_glsl_error(yylloc, yyextra, \ + "Illegal use of reserved word `%s'", yytext); \ + return ERROR_TOK; \ + } \ + } while (0) +%} + +%option bison-bridge bison-locations reentrant noyywrap +%option nounput noyy_top_state +%option never-interactive +%option prefix="_mesa_glsl_" +%option extra-type="struct _mesa_glsl_parse_state *" + +%x PP PRAGMA + +DEC_INT [1-9][0-9]* +HEX_INT 0[xX][0-9a-fA-F]+ +OCT_INT 0[0-7]* +INT ({DEC_INT}|{HEX_INT}|{OCT_INT}) +SPC [ \t]* +SPCP [ \t]+ +HASH ^{SPC}#{SPC} +%% + +[ \r\t]+ ; + + /* Preprocessor tokens. */ +^[ \t]*#[ \t]*$ ; +^[ \t]*#[ \t]*version { BEGIN PP; return VERSION; } +^[ \t]*#[ \t]*extension { BEGIN PP; return EXTENSION; } +{HASH}line{SPCP}{INT}{SPCP}{INT}{SPC}$ { + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; + yylloc->source = strtol(ptr, NULL, 0); + } +{HASH}line{SPCP}{INT}{SPC}$ { + /* Eat characters until the first digit is + * encountered + */ + char *ptr = yytext; + while (!isdigit(*ptr)) + ptr++; + + /* Subtract one from the line number because + * yylineno is zero-based instead of + * one-based. + */ + yylineno = strtol(ptr, &ptr, 0) - 1; + } +^{SPC}#{SPC}pragma{SPCP}debug{SPC}\({SPC}on{SPC}\) { + BEGIN PP; + return PRAGMA_DEBUG_ON; + } +^{SPC}#{SPC}pragma{SPCP}debug{SPC}\({SPC}off{SPC}\) { + BEGIN PP; + return PRAGMA_DEBUG_OFF; + } +^{SPC}#{SPC}pragma{SPCP}optimize{SPC}\({SPC}on{SPC}\) { + BEGIN PP; + return PRAGMA_OPTIMIZE_ON; + } +^{SPC}#{SPC}pragma{SPCP}optimize{SPC}\({SPC}off{SPC}\) { + BEGIN PP; + return PRAGMA_OPTIMIZE_OFF; + } +^{SPC}#{SPC}pragma{SPCP} { BEGIN PRAGMA; } + +<PRAGMA>\n { BEGIN 0; yylineno++; yycolumn = 0; } +<PRAGMA>. { } + +<PP>\/\/[^\n]* { } +<PP>[ \t\r]* { } +<PP>: return COLON; +<PP>[_a-zA-Z][_a-zA-Z0-9]* { + yylval->identifier = strdup(yytext); + return IDENTIFIER; + } +<PP>[1-9][0-9]* { + yylval->n = strtol(yytext, NULL, 10); + return INTCONSTANT; + } +<PP>\n { BEGIN 0; yylineno++; yycolumn = 0; return EOL; } + +\n { yylineno++; yycolumn = 0; } + +attribute return ATTRIBUTE; +const return CONST_TOK; +bool return BOOL_TOK; +float return FLOAT_TOK; +int return INT_TOK; + +break return BREAK; +continue return CONTINUE; +do return DO; +while return WHILE; +else return ELSE; +for return FOR; +if return IF; +discard return DISCARD; +return return RETURN; + +bvec2 return BVEC2; +bvec3 return BVEC3; +bvec4 return BVEC4; +ivec2 return IVEC2; +ivec3 return IVEC3; +ivec4 return IVEC4; +vec2 return VEC2; +vec3 return VEC3; +vec4 return VEC4; +mat2 return MAT2X2; +mat3 return MAT3X3; +mat4 return MAT4X4; +mat2x2 TOKEN_OR_IDENTIFIER(120, MAT2X2); +mat2x3 TOKEN_OR_IDENTIFIER(120, MAT2X3); +mat2x4 TOKEN_OR_IDENTIFIER(120, MAT2X4); +mat3x2 TOKEN_OR_IDENTIFIER(120, MAT3X2); +mat3x3 TOKEN_OR_IDENTIFIER(120, MAT3X3); +mat3x4 TOKEN_OR_IDENTIFIER(120, MAT3X4); +mat4x2 TOKEN_OR_IDENTIFIER(120, MAT4X2); +mat4x3 TOKEN_OR_IDENTIFIER(120, MAT4X3); +mat4x4 TOKEN_OR_IDENTIFIER(120, MAT4X4); + +in return IN_TOK; +out return OUT_TOK; +inout return INOUT_TOK; +uniform return UNIFORM; +varying return VARYING; +centroid TOKEN_OR_IDENTIFIER(120, CENTROID); +invariant TOKEN_OR_IDENTIFIER(120, INVARIANT); + +flat TOKEN_OR_IDENTIFIER(130, FLAT); +smooth TOKEN_OR_IDENTIFIER(130, SMOOTH); +noperspective TOKEN_OR_IDENTIFIER(130, NOPERSPECTIVE); + +sampler1D return SAMPLER1D; +sampler2D return SAMPLER2D; +sampler3D return SAMPLER3D; +samplerCube return SAMPLERCUBE; +sampler1DShadow return SAMPLER1DSHADOW; +sampler2DShadow return SAMPLER2DSHADOW; + +struct return STRUCT; +void return VOID_TOK; + +layout { + if ((yyextra->language_version >= 140) + || (yyextra->ARB_fragment_coord_conventions_enable)){ + return LAYOUT_TOK; + } else { + yylval->identifier = strdup(yytext); + return IDENTIFIER; + } + } + +\+\+ return INC_OP; +-- return DEC_OP; +\<= return LE_OP; +>= return GE_OP; +== return EQ_OP; +!= return NE_OP; +&& return AND_OP; +\|\| return OR_OP; +"^^" return XOR_OP; + +\*= return MUL_ASSIGN; +\/= return DIV_ASSIGN; +\+= return ADD_ASSIGN; +\%= return MOD_ASSIGN; +\<\<= return LEFT_ASSIGN; +>>= return RIGHT_ASSIGN; +&= return AND_ASSIGN; +^= return XOR_ASSIGN; +\|= return OR_ASSIGN; +-= return SUB_ASSIGN; + +[1-9][0-9]* { + yylval->n = strtol(yytext, NULL, 10); + return INTCONSTANT; + } +0[xX][0-9a-fA-F]+ { + yylval->n = strtol(yytext + 2, NULL, 16); + return INTCONSTANT; + } +0[0-7]* { + yylval->n = strtol(yytext, NULL, 8); + return INTCONSTANT; + } + +[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?[fF]? { + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } +\.[0-9]+([eE][+-]?[0-9]+)?[fF]? { + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } +[0-9]+\.([eE][+-]?[0-9]+)?[fF]? { + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } +[0-9]+[eE][+-]?[0-9]+[fF]? { + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } +[0-9]+[fF] { + yylval->real = strtod(yytext, NULL); + return FLOATCONSTANT; + } + +true { + yylval->n = 1; + return BOOLCONSTANT; + } +false { + yylval->n = 0; + return BOOLCONSTANT; + } + + + /* Reserved words in GLSL 1.10. */ +asm RESERVED_WORD(999, ASM); +class RESERVED_WORD(999, CLASS); +union RESERVED_WORD(999, UNION); +enum RESERVED_WORD(999, ENUM); +typedef RESERVED_WORD(999, TYPEDEF); +template RESERVED_WORD(999, TEMPLATE); +this RESERVED_WORD(999, THIS); +packed RESERVED_WORD(999, PACKED_TOK); +goto RESERVED_WORD(999, GOTO); +switch RESERVED_WORD(130, SWITCH); +default RESERVED_WORD(130, DEFAULT); +inline RESERVED_WORD(999, INLINE_TOK); +noinline RESERVED_WORD(999, NOINLINE); +volatile RESERVED_WORD(999, VOLATILE); +public RESERVED_WORD(999, PUBLIC_TOK); +static RESERVED_WORD(999, STATIC); +extern RESERVED_WORD(999, EXTERN); +external RESERVED_WORD(999, EXTERNAL); +interface RESERVED_WORD(999, INTERFACE); +long RESERVED_WORD(999, LONG_TOK); +short RESERVED_WORD(999, SHORT_TOK); +double RESERVED_WORD(999, DOUBLE_TOK); +half RESERVED_WORD(999, HALF); +fixed RESERVED_WORD(999, FIXED_TOK); +unsigned RESERVED_WORD(999, UNSIGNED); +input RESERVED_WORD(999, INPUT_TOK); +output RESERVED_WORD(999, OUTPUT); +hvec2 RESERVED_WORD(999, HVEC2); +hvec3 RESERVED_WORD(999, HVEC3); +hvec4 RESERVED_WORD(999, HVEC4); +dvec2 RESERVED_WORD(999, DVEC2); +dvec3 RESERVED_WORD(999, DVEC3); +dvec4 RESERVED_WORD(999, DVEC4); +fvec2 RESERVED_WORD(999, FVEC2); +fvec3 RESERVED_WORD(999, FVEC3); +fvec4 RESERVED_WORD(999, FVEC4); +sampler2DRect return SAMPLER2DRECT; +sampler3DRect RESERVED_WORD(999, SAMPLER3DRECT); +sampler2DRectShadow return SAMPLER2DRECTSHADOW; +sizeof RESERVED_WORD(999, SIZEOF); +cast RESERVED_WORD(999, CAST); +namespace RESERVED_WORD(999, NAMESPACE); +using RESERVED_WORD(999, USING); + + /* Additional reserved words in GLSL 1.20. */ +lowp TOKEN_OR_IDENTIFIER(120, LOWP); +mediump TOKEN_OR_IDENTIFIER(120, MEDIUMP); +highp TOKEN_OR_IDENTIFIER(120, HIGHP); +precision TOKEN_OR_IDENTIFIER(120, PRECISION); + + /* Additional reserved words in GLSL 1.30. */ +common TOKEN_OR_IDENTIFIER(130, COMMON); +partition TOKEN_OR_IDENTIFIER(130, PARTITION); +active TOKEN_OR_IDENTIFIER(130, ACTIVE); +superp TOKEN_OR_IDENTIFIER(130, SUPERP); +samplerBuffer TOKEN_OR_IDENTIFIER(130, SAMPLERBUFFER); +filter TOKEN_OR_IDENTIFIER(130, FILTER); +image1D TOKEN_OR_IDENTIFIER(130, IMAGE1D); +image2D TOKEN_OR_IDENTIFIER(130, IMAGE2D); +image3D TOKEN_OR_IDENTIFIER(130, IMAGE3D); +imageCube TOKEN_OR_IDENTIFIER(130, IMAGECUBE); +iimage1D TOKEN_OR_IDENTIFIER(130, IIMAGE1D); +iimage2D TOKEN_OR_IDENTIFIER(130, IIMAGE2D); +iimage3D TOKEN_OR_IDENTIFIER(130, IIMAGE3D); +iimageCube TOKEN_OR_IDENTIFIER(130, IIMAGECUBE); +uimage1D TOKEN_OR_IDENTIFIER(130, UIMAGE1D); +uimage2D TOKEN_OR_IDENTIFIER(130, UIMAGE2D); +uimage3D TOKEN_OR_IDENTIFIER(130, UIMAGE3D); +uimageCube TOKEN_OR_IDENTIFIER(130, UIMAGECUBE); +image1DArray TOKEN_OR_IDENTIFIER(130, IMAGE1DARRAY); +image2DArray TOKEN_OR_IDENTIFIER(130, IMAGE2DARRAY); +iimage1DArray TOKEN_OR_IDENTIFIER(130, IIMAGE1DARRAY); +iimage2DArray TOKEN_OR_IDENTIFIER(130, IIMAGE2DARRAY); +uimage1DArray TOKEN_OR_IDENTIFIER(130, UIMAGE1DARRAY); +uimage2DArray TOKEN_OR_IDENTIFIER(130, UIMAGE2DARRAY); +image1DShadow TOKEN_OR_IDENTIFIER(130, IMAGE1DSHADOW); +image2DShadow TOKEN_OR_IDENTIFIER(130, IMAGE2DSHADOW); +imageBuffer TOKEN_OR_IDENTIFIER(130, IMAGEBUFFER); +iimageBuffer TOKEN_OR_IDENTIFIER(130, IIMAGEBUFFER); +uimageBuffer TOKEN_OR_IDENTIFIER(130, UIMAGEBUFFER); +row_major TOKEN_OR_IDENTIFIER(130, ROW_MAJOR); + +[_a-zA-Z][_a-zA-Z0-9]* { + struct _mesa_glsl_parse_state *state = yyextra; + void *ctx = state; + yylval->identifier = talloc_strdup(ctx, yytext); + return IDENTIFIER; + } + +. { return yytext[0]; } + +%% + +void +_mesa_glsl_lexer_ctor(struct _mesa_glsl_parse_state *state, const char *string) +{ + yylex_init_extra(state, & state->scanner); + yy_scan_string(string, state->scanner); +} + +void +_mesa_glsl_lexer_dtor(struct _mesa_glsl_parse_state *state) +{ + yylex_destroy(state->scanner); +} diff --git a/src/glsl/glsl_parser.cpp b/src/glsl/glsl_parser.cpp new file mode 100644 index 0000000000..e36bb03c43 --- /dev/null +++ b/src/glsl/glsl_parser.cpp @@ -0,0 +1,5268 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 1 + +/* Substitute the variable and function names. */ +#define yyparse _mesa_glsl_parse +#define yylex _mesa_glsl_lex +#define yyerror _mesa_glsl_error +#define yylval _mesa_glsl_lval +#define yychar _mesa_glsl_char +#define yydebug _mesa_glsl_debug +#define yynerrs _mesa_glsl_nerrs +#define yylloc _mesa_glsl_lloc + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 1 "glsl_parser.ypp" + +/* + * Copyright © 2008, 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "ast.h" +#include "glsl_parser_extras.h" +#include "glsl_types.h" + +#define YYLEX_PARAM state->scanner + + + +/* Line 189 of yacc.c */ +#line 118 "glsl_parser.cpp" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ATTRIBUTE = 258, + CONST_TOK = 259, + BOOL_TOK = 260, + FLOAT_TOK = 261, + INT_TOK = 262, + UINT_TOK = 263, + BREAK = 264, + CONTINUE = 265, + DO = 266, + ELSE = 267, + FOR = 268, + IF = 269, + DISCARD = 270, + RETURN = 271, + SWITCH = 272, + CASE = 273, + DEFAULT = 274, + BVEC2 = 275, + BVEC3 = 276, + BVEC4 = 277, + IVEC2 = 278, + IVEC3 = 279, + IVEC4 = 280, + UVEC2 = 281, + UVEC3 = 282, + UVEC4 = 283, + VEC2 = 284, + VEC3 = 285, + VEC4 = 286, + CENTROID = 287, + IN_TOK = 288, + OUT_TOK = 289, + INOUT_TOK = 290, + UNIFORM = 291, + VARYING = 292, + NOPERSPECTIVE = 293, + FLAT = 294, + SMOOTH = 295, + MAT2X2 = 296, + MAT2X3 = 297, + MAT2X4 = 298, + MAT3X2 = 299, + MAT3X3 = 300, + MAT3X4 = 301, + MAT4X2 = 302, + MAT4X3 = 303, + MAT4X4 = 304, + SAMPLER1D = 305, + SAMPLER2D = 306, + SAMPLER3D = 307, + SAMPLERCUBE = 308, + SAMPLER1DSHADOW = 309, + SAMPLER2DSHADOW = 310, + SAMPLERCUBESHADOW = 311, + SAMPLER1DARRAY = 312, + SAMPLER2DARRAY = 313, + SAMPLER1DARRAYSHADOW = 314, + SAMPLER2DARRAYSHADOW = 315, + ISAMPLER1D = 316, + ISAMPLER2D = 317, + ISAMPLER3D = 318, + ISAMPLERCUBE = 319, + ISAMPLER1DARRAY = 320, + ISAMPLER2DARRAY = 321, + USAMPLER1D = 322, + USAMPLER2D = 323, + USAMPLER3D = 324, + USAMPLERCUBE = 325, + USAMPLER1DARRAY = 326, + USAMPLER2DARRAY = 327, + STRUCT = 328, + VOID_TOK = 329, + WHILE = 330, + IDENTIFIER = 331, + FLOATCONSTANT = 332, + INTCONSTANT = 333, + UINTCONSTANT = 334, + BOOLCONSTANT = 335, + FIELD_SELECTION = 336, + LEFT_OP = 337, + RIGHT_OP = 338, + INC_OP = 339, + DEC_OP = 340, + LE_OP = 341, + GE_OP = 342, + EQ_OP = 343, + NE_OP = 344, + AND_OP = 345, + OR_OP = 346, + XOR_OP = 347, + MUL_ASSIGN = 348, + DIV_ASSIGN = 349, + ADD_ASSIGN = 350, + MOD_ASSIGN = 351, + LEFT_ASSIGN = 352, + RIGHT_ASSIGN = 353, + AND_ASSIGN = 354, + XOR_ASSIGN = 355, + OR_ASSIGN = 356, + SUB_ASSIGN = 357, + INVARIANT = 358, + LOWP = 359, + MEDIUMP = 360, + HIGHP = 361, + SUPERP = 362, + PRECISION = 363, + VERSION = 364, + EXTENSION = 365, + LINE = 366, + COLON = 367, + EOL = 368, + INTERFACE = 369, + OUTPUT = 370, + PRAGMA_DEBUG_ON = 371, + PRAGMA_DEBUG_OFF = 372, + PRAGMA_OPTIMIZE_ON = 373, + PRAGMA_OPTIMIZE_OFF = 374, + LAYOUT_TOK = 375, + ASM = 376, + CLASS = 377, + UNION = 378, + ENUM = 379, + TYPEDEF = 380, + TEMPLATE = 381, + THIS = 382, + PACKED_TOK = 383, + GOTO = 384, + INLINE_TOK = 385, + NOINLINE = 386, + VOLATILE = 387, + PUBLIC_TOK = 388, + STATIC = 389, + EXTERN = 390, + EXTERNAL = 391, + LONG_TOK = 392, + SHORT_TOK = 393, + DOUBLE_TOK = 394, + HALF = 395, + FIXED_TOK = 396, + UNSIGNED = 397, + INPUT_TOK = 398, + OUPTUT = 399, + HVEC2 = 400, + HVEC3 = 401, + HVEC4 = 402, + DVEC2 = 403, + DVEC3 = 404, + DVEC4 = 405, + FVEC2 = 406, + FVEC3 = 407, + FVEC4 = 408, + SAMPLER2DRECT = 409, + SAMPLER3DRECT = 410, + SAMPLER2DRECTSHADOW = 411, + SIZEOF = 412, + CAST = 413, + NAMESPACE = 414, + USING = 415, + ERROR_TOK = 416, + COMMON = 417, + PARTITION = 418, + ACTIVE = 419, + SAMPLERBUFFER = 420, + FILTER = 421, + IMAGE1D = 422, + IMAGE2D = 423, + IMAGE3D = 424, + IMAGECUBE = 425, + IMAGE1DARRAY = 426, + IMAGE2DARRAY = 427, + IIMAGE1D = 428, + IIMAGE2D = 429, + IIMAGE3D = 430, + IIMAGECUBE = 431, + IIMAGE1DARRAY = 432, + IIMAGE2DARRAY = 433, + UIMAGE1D = 434, + UIMAGE2D = 435, + UIMAGE3D = 436, + UIMAGECUBE = 437, + UIMAGE1DARRAY = 438, + UIMAGE2DARRAY = 439, + IMAGE1DSHADOW = 440, + IMAGE2DSHADOW = 441, + IMAGEBUFFER = 442, + IIMAGEBUFFER = 443, + UIMAGEBUFFER = 444, + ROW_MAJOR = 445 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 214 of yacc.c */ +#line 52 "glsl_parser.ypp" + + int n; + float real; + char *identifier; + + union { + struct ast_type_qualifier q; + unsigned i; + } type_qualifier; + + ast_node *node; + ast_type_specifier *type_specifier; + ast_fully_specified_type *fully_specified_type; + ast_function *function; + ast_parameter_declarator *parameter_declarator; + ast_function_definition *function_definition; + ast_compound_statement *compound_statement; + ast_expression *expression; + ast_declarator_list *declarator_list; + ast_struct_specifier *struct_specifier; + ast_declaration *declaration; + + struct { + ast_node *cond; + ast_expression *rest; + } for_rest_statement; + + + +/* Line 214 of yacc.c */ +#line 374 "glsl_parser.cpp" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 399 "glsl_parser.cpp" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 5 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 4115 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 215 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 90 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 278 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 419 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 445 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 199, 2, 2, 2, 203, 206, 2, + 191, 192, 201, 197, 196, 198, 195, 202, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 210, 212, + 204, 211, 205, 209, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 193, 2, 194, 207, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 213, 208, 214, 200, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 4, 9, 10, 14, 17, 20, 23, + 26, 27, 30, 36, 38, 41, 43, 45, 47, 49, + 51, 53, 57, 59, 64, 66, 70, 73, 76, 78, + 80, 82, 86, 89, 92, 95, 97, 100, 104, 107, + 109, 111, 113, 115, 118, 121, 124, 126, 128, 130, + 132, 134, 138, 142, 146, 148, 152, 156, 158, 162, + 166, 168, 172, 176, 180, 184, 186, 190, 194, 196, + 200, 202, 206, 208, 212, 214, 218, 220, 224, 226, + 230, 232, 238, 240, 244, 246, 248, 250, 252, 254, + 256, 258, 260, 262, 264, 266, 268, 272, 274, 277, + 280, 285, 288, 290, 292, 295, 299, 303, 306, 312, + 316, 319, 323, 326, 327, 329, 331, 333, 335, 337, + 341, 347, 354, 362, 371, 377, 379, 382, 387, 393, + 400, 408, 413, 416, 418, 421, 422, 424, 429, 431, + 435, 437, 439, 441, 443, 445, 447, 450, 453, 455, + 457, 460, 463, 466, 468, 471, 474, 476, 478, 481, + 483, 487, 492, 494, 496, 498, 500, 502, 504, 506, + 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, + 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, + 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, + 568, 570, 572, 574, 576, 578, 580, 582, 584, 586, + 588, 590, 592, 594, 596, 598, 600, 602, 604, 606, + 612, 617, 619, 622, 626, 628, 632, 634, 639, 641, + 643, 645, 647, 649, 651, 653, 655, 657, 659, 661, + 663, 665, 667, 670, 674, 676, 678, 681, 685, 687, + 690, 692, 695, 703, 709, 715, 723, 725, 730, 736, + 740, 743, 749, 757, 764, 766, 768, 770, 771, 774, + 778, 781, 784, 787, 791, 794, 796, 798, 800 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 216, 0, -1, -1, 218, 220, 217, 222, -1, -1, + 109, 78, 113, -1, 116, 113, -1, 117, 113, -1, + 118, 113, -1, 119, 113, -1, -1, 220, 221, -1, + 110, 76, 112, 76, 113, -1, 303, -1, 222, 303, + -1, 76, -1, 223, -1, 78, -1, 79, -1, 77, + -1, 80, -1, 191, 250, 192, -1, 224, -1, 225, + 193, 226, 194, -1, 227, -1, 225, 195, 76, -1, + 225, 84, -1, 225, 85, -1, 250, -1, 228, -1, + 229, -1, 225, 195, 229, -1, 231, 192, -1, 230, + 192, -1, 232, 74, -1, 232, -1, 232, 248, -1, + 231, 196, 248, -1, 233, 191, -1, 272, -1, 76, + -1, 81, -1, 225, -1, 84, 234, -1, 85, 234, + -1, 235, 234, -1, 197, -1, 198, -1, 199, -1, + 200, -1, 234, -1, 236, 201, 234, -1, 236, 202, + 234, -1, 236, 203, 234, -1, 236, -1, 237, 197, + 236, -1, 237, 198, 236, -1, 237, -1, 238, 82, + 237, -1, 238, 83, 237, -1, 238, -1, 239, 204, + 238, -1, 239, 205, 238, -1, 239, 86, 238, -1, + 239, 87, 238, -1, 239, -1, 240, 88, 239, -1, + 240, 89, 239, -1, 240, -1, 241, 206, 240, -1, + 241, -1, 242, 207, 241, -1, 242, -1, 243, 208, + 242, -1, 243, -1, 244, 90, 243, -1, 244, -1, + 245, 92, 244, -1, 245, -1, 246, 91, 245, -1, + 246, -1, 246, 209, 250, 210, 248, -1, 247, -1, + 234, 249, 248, -1, 211, -1, 93, -1, 94, -1, + 96, -1, 95, -1, 102, -1, 97, -1, 98, -1, + 99, -1, 100, -1, 101, -1, 248, -1, 250, 196, + 248, -1, 247, -1, 253, 212, -1, 261, 212, -1, + 108, 276, 273, 212, -1, 254, 192, -1, 256, -1, + 255, -1, 256, 258, -1, 255, 196, 258, -1, 263, + 76, 191, -1, 272, 76, -1, 272, 76, 193, 251, + 194, -1, 269, 259, 257, -1, 259, 257, -1, 269, + 259, 260, -1, 259, 260, -1, -1, 33, -1, 34, + -1, 35, -1, 272, -1, 262, -1, 261, 196, 76, + -1, 261, 196, 76, 193, 194, -1, 261, 196, 76, + 193, 251, 194, -1, 261, 196, 76, 193, 194, 211, + 282, -1, 261, 196, 76, 193, 251, 194, 211, 282, + -1, 261, 196, 76, 211, 282, -1, 263, -1, 263, + 76, -1, 263, 76, 193, 194, -1, 263, 76, 193, + 251, 194, -1, 263, 76, 193, 194, 211, 282, -1, + 263, 76, 193, 251, 194, 211, 282, -1, 263, 76, + 211, 282, -1, 103, 76, -1, 272, -1, 270, 272, + -1, -1, 265, -1, 120, 191, 266, 192, -1, 267, + -1, 266, 196, 267, -1, 76, -1, 40, -1, 39, + -1, 38, -1, 4, -1, 271, -1, 268, 270, -1, + 103, 270, -1, 4, -1, 3, -1, 264, 37, -1, + 32, 37, -1, 264, 33, -1, 34, -1, 32, 33, + -1, 32, 34, -1, 36, -1, 273, -1, 276, 273, + -1, 274, -1, 274, 193, 194, -1, 274, 193, 251, + 194, -1, 275, -1, 277, -1, 76, -1, 74, -1, + 6, -1, 7, -1, 8, -1, 5, -1, 29, -1, + 30, -1, 31, -1, 20, -1, 21, -1, 22, -1, + 23, -1, 24, -1, 25, -1, 26, -1, 27, -1, + 28, -1, 41, -1, 42, -1, 43, -1, 44, -1, + 45, -1, 46, -1, 47, -1, 48, -1, 49, -1, + 50, -1, 51, -1, 154, -1, 52, -1, 53, -1, + 54, -1, 55, -1, 156, -1, 56, -1, 57, -1, + 58, -1, 59, -1, 60, -1, 61, -1, 62, -1, + 63, -1, 64, -1, 65, -1, 66, -1, 67, -1, + 68, -1, 69, -1, 70, -1, 71, -1, 72, -1, + 106, -1, 105, -1, 104, -1, 73, 76, 213, 278, + 214, -1, 73, 213, 278, 214, -1, 279, -1, 278, + 279, -1, 272, 280, 212, -1, 281, -1, 280, 196, + 281, -1, 76, -1, 76, 193, 251, 194, -1, 248, + -1, 252, -1, 285, -1, 286, -1, 288, -1, 287, + -1, 294, -1, 283, -1, 292, -1, 293, -1, 296, + -1, 297, -1, 298, -1, 302, -1, 213, 214, -1, + 213, 291, 214, -1, 290, -1, 287, -1, 213, 214, + -1, 213, 291, 214, -1, 284, -1, 291, 284, -1, + 212, -1, 250, 212, -1, 14, 191, 250, 192, 285, + 12, 285, -1, 14, 191, 250, 192, 285, -1, 14, + 191, 250, 192, 286, -1, 14, 191, 250, 192, 285, + 12, 286, -1, 250, -1, 263, 76, 211, 282, -1, + 17, 191, 250, 192, 288, -1, 18, 250, 210, -1, + 19, 210, -1, 75, 191, 295, 192, 289, -1, 11, + 284, 75, 191, 250, 192, 212, -1, 13, 191, 299, + 301, 192, 289, -1, 292, -1, 283, -1, 295, -1, + -1, 300, 212, -1, 300, 212, 250, -1, 10, 212, + -1, 9, 212, -1, 16, 212, -1, 16, 250, 212, + -1, 15, 212, -1, 304, -1, 252, -1, 219, -1, + 253, 290, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 211, 211, 210, 219, 223, 242, 243, 244, 245, + 248, 250, 254, 263, 271, 282, 286, 293, 300, 307, + 314, 321, 328, 329, 335, 339, 346, 352, 361, 365, + 369, 370, 379, 380, 384, 385, 389, 395, 407, 411, + 417, 424, 435, 436, 442, 448, 458, 459, 460, 461, + 465, 466, 472, 478, 487, 488, 494, 503, 504, 510, + 519, 520, 526, 532, 538, 547, 548, 554, 563, 564, + 573, 574, 583, 584, 593, 594, 603, 604, 613, 614, + 623, 624, 633, 634, 643, 644, 645, 646, 647, 648, + 649, 650, 651, 652, 653, 657, 661, 677, 681, 685, + 689, 703, 707, 708, 712, 717, 725, 736, 746, 761, + 768, 773, 784, 796, 797, 798, 799, 803, 807, 808, + 817, 826, 835, 844, 853, 866, 877, 886, 895, 904, + 913, 922, 931, 945, 952, 963, 964, 968, 975, 976, + 983, 1017, 1018, 1019, 1023, 1027, 1028, 1032, 1040, 1041, + 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1052, 1053, 1061, + 1062, 1068, 1077, 1083, 1089, 1098, 1099, 1100, 1101, 1102, + 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, + 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, + 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, + 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, + 1143, 1144, 1145, 1146, 1147, 1148, 1152, 1163, 1174, 1188, + 1194, 1203, 1208, 1216, 1231, 1236, 1244, 1250, 1259, 1263, + 1269, 1270, 1274, 1275, 1279, 1283, 1284, 1285, 1286, 1287, + 1288, 1289, 1293, 1299, 1308, 1309, 1313, 1319, 1328, 1338, + 1350, 1356, 1365, 1374, 1380, 1386, 1395, 1399, 1413, 1417, + 1418, 1422, 1429, 1436, 1446, 1447, 1451, 1453, 1459, 1464, + 1473, 1479, 1485, 1491, 1497, 1506, 1507, 1508, 1512 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "ATTRIBUTE", "CONST_TOK", "BOOL_TOK", + "FLOAT_TOK", "INT_TOK", "UINT_TOK", "BREAK", "CONTINUE", "DO", "ELSE", + "FOR", "IF", "DISCARD", "RETURN", "SWITCH", "CASE", "DEFAULT", "BVEC2", + "BVEC3", "BVEC4", "IVEC2", "IVEC3", "IVEC4", "UVEC2", "UVEC3", "UVEC4", + "VEC2", "VEC3", "VEC4", "CENTROID", "IN_TOK", "OUT_TOK", "INOUT_TOK", + "UNIFORM", "VARYING", "NOPERSPECTIVE", "FLAT", "SMOOTH", "MAT2X2", + "MAT2X3", "MAT2X4", "MAT3X2", "MAT3X3", "MAT3X4", "MAT4X2", "MAT4X3", + "MAT4X4", "SAMPLER1D", "SAMPLER2D", "SAMPLER3D", "SAMPLERCUBE", + "SAMPLER1DSHADOW", "SAMPLER2DSHADOW", "SAMPLERCUBESHADOW", + "SAMPLER1DARRAY", "SAMPLER2DARRAY", "SAMPLER1DARRAYSHADOW", + "SAMPLER2DARRAYSHADOW", "ISAMPLER1D", "ISAMPLER2D", "ISAMPLER3D", + "ISAMPLERCUBE", "ISAMPLER1DARRAY", "ISAMPLER2DARRAY", "USAMPLER1D", + "USAMPLER2D", "USAMPLER3D", "USAMPLERCUBE", "USAMPLER1DARRAY", + "USAMPLER2DARRAY", "STRUCT", "VOID_TOK", "WHILE", "IDENTIFIER", + "FLOATCONSTANT", "INTCONSTANT", "UINTCONSTANT", "BOOLCONSTANT", + "FIELD_SELECTION", "LEFT_OP", "RIGHT_OP", "INC_OP", "DEC_OP", "LE_OP", + "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP", "XOR_OP", "MUL_ASSIGN", + "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", + "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN", "SUB_ASSIGN", "INVARIANT", + "LOWP", "MEDIUMP", "HIGHP", "SUPERP", "PRECISION", "VERSION", + "EXTENSION", "LINE", "COLON", "EOL", "INTERFACE", "OUTPUT", + "PRAGMA_DEBUG_ON", "PRAGMA_DEBUG_OFF", "PRAGMA_OPTIMIZE_ON", + "PRAGMA_OPTIMIZE_OFF", "LAYOUT_TOK", "ASM", "CLASS", "UNION", "ENUM", + "TYPEDEF", "TEMPLATE", "THIS", "PACKED_TOK", "GOTO", "INLINE_TOK", + "NOINLINE", "VOLATILE", "PUBLIC_TOK", "STATIC", "EXTERN", "EXTERNAL", + "LONG_TOK", "SHORT_TOK", "DOUBLE_TOK", "HALF", "FIXED_TOK", "UNSIGNED", + "INPUT_TOK", "OUPTUT", "HVEC2", "HVEC3", "HVEC4", "DVEC2", "DVEC3", + "DVEC4", "FVEC2", "FVEC3", "FVEC4", "SAMPLER2DRECT", "SAMPLER3DRECT", + "SAMPLER2DRECTSHADOW", "SIZEOF", "CAST", "NAMESPACE", "USING", + "ERROR_TOK", "COMMON", "PARTITION", "ACTIVE", "SAMPLERBUFFER", "FILTER", + "IMAGE1D", "IMAGE2D", "IMAGE3D", "IMAGECUBE", "IMAGE1DARRAY", + "IMAGE2DARRAY", "IIMAGE1D", "IIMAGE2D", "IIMAGE3D", "IIMAGECUBE", + "IIMAGE1DARRAY", "IIMAGE2DARRAY", "UIMAGE1D", "UIMAGE2D", "UIMAGE3D", + "UIMAGECUBE", "UIMAGE1DARRAY", "UIMAGE2DARRAY", "IMAGE1DSHADOW", + "IMAGE2DSHADOW", "IMAGEBUFFER", "IIMAGEBUFFER", "UIMAGEBUFFER", + "ROW_MAJOR", "'('", "')'", "'['", "']'", "'.'", "','", "'+'", "'-'", + "'!'", "'~'", "'*'", "'/'", "'%'", "'<'", "'>'", "'&'", "'^'", "'|'", + "'?'", "':'", "'='", "';'", "'{'", "'}'", "$accept", "translation_unit", + "$@1", "version_statement", "pragma_statement", + "extension_statement_list", "extension_statement", + "external_declaration_list", "variable_identifier", "primary_expression", + "postfix_expression", "integer_expression", "function_call", + "function_call_or_method", "function_call_generic", + "function_call_header_no_parameters", + "function_call_header_with_parameters", "function_call_header", + "function_identifier", "unary_expression", "unary_operator", + "multiplicative_expression", "additive_expression", "shift_expression", + "relational_expression", "equality_expression", "and_expression", + "exclusive_or_expression", "inclusive_or_expression", + "logical_and_expression", "logical_xor_expression", + "logical_or_expression", "conditional_expression", + "assignment_expression", "assignment_operator", "expression", + "constant_expression", "declaration", "function_prototype", + "function_declarator", "function_header_with_parameters", + "function_header", "parameter_declarator", "parameter_declaration", + "parameter_qualifier", "parameter_type_specifier", + "init_declarator_list", "single_declaration", "fully_specified_type", + "opt_layout_qualifier", "layout_qualifier", "layout_qualifier_id_list", + "layout_qualifier_id", "interpolation_qualifier", + "parameter_type_qualifier", "type_qualifier", "storage_qualifier", + "type_specifier", "type_specifier_no_prec", "type_specifier_nonarray", + "basic_type_specifier_nonarray", "precision_qualifier", + "struct_specifier", "struct_declaration_list", "struct_declaration", + "struct_declarator_list", "struct_declarator", "initializer", + "declaration_statement", "statement", "statement_matched", + "statement_unmatched", "simple_statement", "compound_statement", + "statement_no_new_scope", "compound_statement_no_new_scope", + "statement_list", "expression_statement", "selection_statement_matched", + "selection_statement_unmatched", "condition", "switch_statement", + "case_label", "iteration_statement", "for_init_statement", + "conditionopt", "for_rest_statement", "jump_statement", + "external_declaration", "function_definition", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 40, 41, 91, 93, 46, 44, 43, 45, 33, + 126, 42, 47, 37, 60, 62, 38, 94, 124, 63, + 58, 61, 59, 123, 125 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint16 yyr1[] = +{ + 0, 215, 217, 216, 218, 218, 219, 219, 219, 219, + 220, 220, 221, 222, 222, 223, 224, 224, 224, 224, + 224, 224, 225, 225, 225, 225, 225, 225, 226, 227, + 228, 228, 229, 229, 230, 230, 231, 231, 232, 233, + 233, 233, 234, 234, 234, 234, 235, 235, 235, 235, + 236, 236, 236, 236, 237, 237, 237, 238, 238, 238, + 239, 239, 239, 239, 239, 240, 240, 240, 241, 241, + 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, + 247, 247, 248, 248, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 250, 250, 251, 252, 252, + 252, 253, 254, 254, 255, 255, 256, 257, 257, 258, + 258, 258, 258, 259, 259, 259, 259, 260, 261, 261, + 261, 261, 261, 261, 261, 262, 262, 262, 262, 262, + 262, 262, 262, 263, 263, 264, 264, 265, 266, 266, + 267, 268, 268, 268, 269, 270, 270, 270, 271, 271, + 271, 271, 271, 271, 271, 271, 271, 272, 272, 273, + 273, 273, 274, 274, 274, 275, 275, 275, 275, 275, + 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, + 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, + 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, + 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, + 275, 275, 275, 275, 275, 275, 276, 276, 276, 277, + 277, 278, 278, 279, 280, 280, 281, 281, 282, 283, + 284, 284, 285, 285, 286, 287, 287, 287, 287, 287, + 287, 287, 288, 288, 289, 289, 290, 290, 291, 291, + 292, 292, 293, 294, 294, 294, 295, 295, 296, 297, + 297, 298, 298, 298, 299, 299, 300, 300, 301, 301, + 302, 302, 302, 302, 302, 303, 303, 303, 304 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 4, 0, 3, 2, 2, 2, 2, + 0, 2, 5, 1, 2, 1, 1, 1, 1, 1, + 1, 3, 1, 4, 1, 3, 2, 2, 1, 1, + 1, 3, 2, 2, 2, 1, 2, 3, 2, 1, + 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, + 1, 3, 3, 3, 1, 3, 3, 1, 3, 3, + 1, 3, 3, 3, 3, 1, 3, 3, 1, 3, + 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, + 1, 5, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, 2, 2, + 4, 2, 1, 1, 2, 3, 3, 2, 5, 3, + 2, 3, 2, 0, 1, 1, 1, 1, 1, 3, + 5, 6, 7, 8, 5, 1, 2, 4, 5, 6, + 7, 4, 2, 1, 2, 0, 1, 4, 1, 3, + 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, + 2, 2, 2, 1, 2, 2, 1, 1, 2, 1, + 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, + 4, 1, 2, 3, 1, 3, 1, 4, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 3, 1, 1, 2, 3, 1, 2, + 1, 2, 7, 5, 5, 7, 1, 4, 5, 3, + 2, 5, 7, 6, 1, 1, 1, 0, 2, 3, + 2, 2, 2, 3, 2, 1, 1, 1, 2 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 4, 0, 0, 10, 0, 1, 2, 5, 0, 135, + 11, 0, 149, 148, 169, 166, 167, 168, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 170, 171, 172, + 0, 153, 156, 143, 142, 141, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 194, 195, 196, + 197, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 0, 165, + 164, 135, 218, 217, 216, 0, 0, 0, 0, 0, + 0, 193, 198, 277, 135, 276, 0, 0, 103, 113, + 0, 118, 125, 0, 136, 135, 0, 145, 133, 157, + 159, 162, 0, 163, 13, 275, 0, 154, 155, 151, + 0, 0, 132, 135, 147, 0, 6, 7, 8, 9, + 0, 14, 98, 135, 278, 101, 113, 144, 114, 115, + 116, 104, 0, 113, 0, 99, 126, 152, 150, 146, + 134, 0, 158, 0, 0, 0, 0, 221, 0, 140, + 0, 138, 0, 0, 135, 0, 0, 0, 0, 0, + 0, 0, 0, 15, 19, 17, 18, 20, 41, 0, + 0, 0, 46, 47, 48, 49, 250, 135, 246, 16, + 22, 42, 24, 29, 30, 0, 0, 35, 0, 50, + 0, 54, 57, 60, 65, 68, 70, 72, 74, 76, + 78, 80, 82, 95, 0, 229, 0, 133, 235, 248, + 230, 231, 233, 232, 135, 236, 237, 234, 238, 239, + 240, 241, 105, 110, 112, 117, 0, 119, 106, 0, + 0, 160, 50, 97, 0, 39, 12, 0, 226, 0, + 224, 220, 222, 100, 137, 0, 271, 270, 0, 135, + 0, 274, 272, 0, 0, 0, 260, 135, 43, 44, + 0, 242, 135, 26, 27, 0, 0, 33, 32, 0, + 165, 36, 38, 85, 86, 88, 87, 90, 91, 92, + 93, 94, 89, 84, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 251, 247, 249, + 107, 109, 111, 0, 0, 127, 0, 228, 131, 161, + 219, 0, 0, 223, 139, 0, 265, 264, 135, 0, + 273, 0, 259, 256, 0, 0, 21, 243, 0, 28, + 25, 31, 37, 83, 51, 52, 53, 55, 56, 58, + 59, 63, 64, 61, 62, 66, 67, 69, 71, 73, + 75, 77, 79, 0, 96, 0, 120, 0, 124, 0, + 128, 0, 225, 0, 266, 0, 0, 135, 0, 0, + 135, 23, 0, 0, 0, 121, 129, 0, 227, 0, + 268, 135, 253, 254, 258, 0, 0, 245, 261, 244, + 81, 108, 122, 0, 130, 0, 269, 263, 135, 257, + 0, 123, 262, 252, 255, 0, 135, 0, 135 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 2, 9, 3, 83, 6, 10, 84, 179, 180, + 181, 338, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 284, 204, 234, 205, 206, 87, + 88, 89, 223, 131, 132, 224, 90, 91, 92, 93, + 94, 150, 151, 95, 133, 96, 97, 235, 99, 100, + 101, 102, 103, 146, 147, 239, 240, 318, 208, 209, + 210, 211, 212, 213, 398, 399, 214, 215, 216, 217, + 335, 218, 219, 220, 328, 375, 376, 221, 104, 105 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -367 +static const yytype_int16 yypact[] = +{ + -88, -21, 24, -367, -53, -367, -3, -367, 9, 3699, + -367, 0, -367, -367, -367, -367, -367, -367, -367, -367, + -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, + 126, -367, -367, -367, -367, -367, -367, -367, -367, -367, + -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, + -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, + -367, -367, -367, -367, -367, -367, -367, -367, -75, -367, + -367, 29, -367, -367, -367, 92, 4, 12, 20, 26, + -49, -367, -367, -367, 3580, -367, -197, -45, -46, 3, + -134, -367, 82, 71, -367, 52, 3887, -367, -367, -367, + -29, -367, 3959, -367, -367, -367, 97, -367, -367, -367, + -19, 3887, -367, 52, -367, 3959, -367, -367, -367, -367, + 130, -367, -367, 282, -367, -367, 47, -367, -367, -367, + -367, -367, 3887, 187, 139, -367, -162, -367, -367, -367, + -367, 2675, -367, 105, 3887, 154, 2064, -367, 23, -367, + -62, -367, 27, 31, 1130, 50, 53, 33, 2296, 55, + 3218, 37, 58, -67, -367, -367, -367, -367, -367, 3218, + 3218, 3218, -367, -367, -367, -367, -367, 494, -367, -367, + -367, -66, -367, -367, -367, 60, -56, 3399, 64, -54, + 3218, 22, 6, 118, -84, 120, 51, 54, 56, 168, + 167, -83, -367, -367, -103, -367, 48, 72, -367, -367, + -367, -367, -367, -367, 706, -367, -367, -367, -367, -367, + -367, -367, -367, -367, -367, 186, 3887, -139, -367, 2856, + 3218, -367, -367, -367, 73, -367, -367, 2180, 75, -102, + -367, -367, -367, -367, -367, 130, -367, -367, 190, 1750, + 3218, -367, -367, -90, 3218, -146, -367, 2494, -367, -367, + -48, -367, 918, -367, -367, 3218, 3815, -367, -367, 3218, + 74, -367, -367, -367, -367, -367, -367, -367, -367, -367, + -367, -367, -367, -367, 3218, -367, 3218, 3218, 3218, 3218, + 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218, + 3218, 3218, 3218, 3218, 3218, 3218, 3218, -367, -367, -367, + 76, -367, -367, 3037, 3218, 59, 77, -367, -367, -367, + -367, 3218, 154, -367, -367, 81, -367, -367, 1948, -40, + -367, -27, -367, 78, 197, 83, -367, -367, 84, 78, + 85, -367, -367, -367, -367, -367, -367, 22, 22, 6, + 6, 118, 118, 118, 118, -84, -84, 120, 51, 54, + 56, 168, 167, -97, -367, 3218, 66, 86, -367, 3218, + 68, 87, -367, 3218, -367, 70, 91, 1130, 102, 106, + 1341, -367, 3218, 90, 3218, 153, -367, 3218, -367, -26, + 3218, 1341, 353, -367, -367, 3218, 103, -367, -367, -367, + -367, -367, -367, 3218, -367, 157, 78, -367, 1130, -367, + 3218, -367, -367, -367, -367, -25, 1552, 358, 1552 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -367, -367, -367, -367, -367, -367, -367, -367, -367, -367, + -367, -367, -367, -367, 107, -367, -367, -367, -367, -111, + -367, -63, -59, -82, -60, 79, 80, 88, 89, 69, + 93, -367, -114, -153, -367, -154, -224, 11, 14, -367, + -367, -367, 148, 249, 243, 151, -367, -367, -245, -367, + -367, -367, 134, -367, -367, -43, -367, -9, -89, -367, + -367, 306, -367, 239, -136, -367, 62, -241, 143, -143, + -342, -355, -366, 15, 5, 308, 218, 149, -367, -367, + 94, -367, -367, -367, -367, -367, -367, -367, 316, -367 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -268 +static const yytype_int16 yytable[] = +{ + 98, 110, 293, 294, 253, 316, 255, 127, 304, -164, + 242, 248, 334, 142, 397, 122, 123, 260, 263, 264, + 85, 1, 393, 86, 5, 397, 148, 233, 114, 228, + 232, 229, 12, 13, 271, 392, 128, 129, 130, 273, + 274, 275, 276, 277, 278, 279, 280, 281, 282, 230, + 306, 127, 139, 414, 313, 12, 13, 4, 258, 259, + 7, 30, 134, 31, 332, 32, 413, 33, 34, 35, + 114, 309, 314, 368, 417, 98, 413, 317, 135, 285, + 128, 129, 130, 334, 30, 11, 31, 140, 32, 367, + 33, 34, 35, 306, 322, 85, 329, 371, 86, 306, + 331, 242, 145, 333, 137, 112, 306, 8, 138, 307, + 323, 339, 106, 382, 207, 233, 342, 116, 232, 309, + 295, 296, 330, 225, -40, 117, 305, 265, 386, 266, + 244, 343, 113, 118, 245, 145, 268, 145, 111, 119, + 269, 383, 120, 402, 336, 207, 404, 125, 306, 80, + 126, 363, 377, 364, 409, 113, 306, 283, 136, 107, + 108, 317, 411, 109, 141, 378, 405, 416, 207, 306, + 306, 306, 80, 143, 333, 344, 345, 346, 232, 232, + 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 232, 232, 232, 232, 144, -102, 72, 73, 74, 233, + 291, 292, 232, 289, 290, 207, 149, 233, 297, 298, + 232, 351, 352, 353, 354, 227, 317, 225, 236, 389, + 128, 129, 130, 286, 287, 288, 347, 348, 145, 400, + 238, 317, 349, 350, 317, 243, 406, 355, 356, 246, + 207, 249, 317, 247, 250, 251, 254, 256, 207, 257, + 317, 233, 267, 207, 232, 272, 415, 299, 302, 303, + 122, 300, 310, -39, 301, 325, -34, 319, 321, 365, + 369, 370, 373, 379, 306, 380, -40, 384, 381, 387, + 385, 388, 390, 391, 401, 12, 13, 14, 15, 16, + 17, 152, 153, 154, 410, 155, 156, 157, 158, 159, + 160, 161, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 177, 31, 395, 32, 207, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 162, 163, 164, + 165, 166, 167, 168, 403, 408, 169, 170, 207, 412, + 418, 207, 361, 341, 311, 222, 226, 312, 357, 324, + 358, 115, 207, 237, 372, 71, 72, 73, 74, 359, + 75, 360, 326, 394, 124, 262, 407, 362, 327, 207, + 121, 0, 80, 0, 0, 0, 0, 207, 0, 207, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 374, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 81, 0, 82, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 171, 0, 0, 0, 0, 0, 172, + 173, 174, 175, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 176, 177, 178, 12, 13, 14, + 15, 16, 17, 152, 153, 154, 0, 155, 156, 157, + 158, 159, 160, 161, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 0, 31, 0, + 32, 0, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 162, + 163, 164, 165, 166, 167, 168, 0, 0, 169, 170, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, + 74, 0, 75, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, + 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, + 0, 172, 173, 174, 175, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 176, 177, 261, 12, + 13, 14, 15, 16, 17, 152, 153, 154, 0, 155, + 156, 157, 158, 159, 160, 161, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 0, + 31, 0, 32, 0, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 162, 163, 164, 165, 166, 167, 168, 0, 0, + 169, 170, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, + 72, 73, 74, 0, 75, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 82, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 171, 0, 0, + 0, 0, 0, 172, 173, 174, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 176, 177, + 308, 12, 13, 14, 15, 16, 17, 152, 153, 154, + 0, 155, 156, 157, 158, 159, 160, 161, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 0, 31, 0, 32, 0, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 162, 163, 164, 165, 166, 167, 168, + 0, 0, 169, 170, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 71, 72, 73, 74, 0, 75, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 81, 0, 82, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, + 0, 0, 0, 0, 0, 172, 173, 174, 175, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 176, 177, 337, 12, 13, 14, 15, 16, 17, 152, + 153, 154, 0, 155, 156, 157, 158, 159, 160, 161, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 0, 31, 0, 32, 0, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 162, 163, 164, 165, 166, + 167, 168, 0, 0, 169, 170, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 71, 72, 73, 74, 0, 75, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 81, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 171, 0, 0, 0, 0, 0, 172, 173, 174, + 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 176, 177, 12, 13, 14, 15, 16, 17, + 152, 153, 154, 0, 155, 396, 157, 158, 159, 160, + 161, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 0, 31, 0, 32, 0, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 162, 163, 164, 165, + 166, 167, 168, 0, 0, 169, 170, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 71, 72, 73, 74, 0, 75, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 81, 0, 82, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 171, 0, 0, 0, 0, 0, 172, 173, + 174, 175, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 176, 123, 12, 13, 14, 15, 16, + 17, 152, 153, 154, 0, 155, 396, 157, 158, 159, + 160, 161, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 0, 31, 0, 32, 0, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 162, 163, 164, + 165, 166, 167, 168, 0, 0, 169, 170, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 71, 72, 73, 74, 0, + 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 81, 0, 82, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 171, 0, 0, 0, 0, 0, 172, + 173, 174, 175, 12, 13, 14, 15, 16, 17, 0, + 0, 0, 0, 0, 176, 177, 0, 0, 0, 0, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 0, 31, 0, 32, 0, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 0, 163, 164, 165, 166, + 167, 168, 0, 0, 169, 170, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 71, 72, 73, 74, 0, 75, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 81, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 171, 0, 0, 0, 0, 0, 172, 173, 174, + 175, 12, 13, 14, 15, 16, 17, 0, 0, 0, + 0, 0, 176, 0, 0, 0, 0, 0, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 0, 31, 0, 32, 0, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 0, 163, 164, 165, 166, 167, 168, + 0, 0, 169, 170, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 113, 72, 73, 74, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 80, 14, + 15, 16, 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, + 0, 0, 81, 0, 82, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 171, + 70, 0, 0, 0, 0, 172, 173, 174, 175, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -267, 0, 0, 0, 0, 0, 0, 0, 72, 73, + 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 14, 15, 16, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 0, 0, 0, 0, 0, 0, 81, 0, + 82, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 0, 70, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 241, 0, + 0, 0, 0, 0, 72, 73, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 14, 15, 16, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, + 0, 0, 0, 0, 81, 0, 82, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 0, 163, 164, 165, 166, 167, 168, 0, 0, + 169, 170, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 320, 0, 0, 0, 0, 0, + 72, 73, 74, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 82, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 171, 0, 0, + 0, 0, 0, 172, 173, 174, 175, 12, 13, 14, + 15, 16, 17, 0, 0, 0, 0, 0, 252, 0, + 0, 0, 0, 0, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 0, 31, 0, + 32, 0, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, + 163, 164, 165, 166, 167, 168, 0, 0, 169, 170, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 113, 72, 73, + 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, + 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 14, 15, 16, 17, 0, 171, 0, 0, 0, 0, + 0, 172, 173, 174, 175, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 0, 163, 164, 165, 166, 167, 168, 0, 0, 169, + 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, + 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, + 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 14, 15, 16, 17, 0, 171, 0, 0, 231, + 0, 0, 172, 173, 174, 175, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 0, 163, 164, 165, 166, 167, 168, 0, 0, + 169, 170, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 73, 74, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 82, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 14, 15, 16, 17, 0, 171, 0, 0, + 315, 0, 0, 172, 173, 174, 175, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 0, 163, 164, 165, 166, 167, 168, 0, + 0, 169, 170, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 72, 73, 74, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 81, 0, 82, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 14, 15, 16, 17, 0, 171, 0, + 0, 366, 0, 0, 172, 173, 174, 175, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 0, 163, 164, 165, 166, 167, 168, + 0, 0, 169, 170, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 72, 73, 74, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 81, 0, 82, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 14, 15, 16, 17, 0, 171, + 0, 0, 0, 0, 0, 172, 173, 174, 175, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 270, 0, 163, 164, 165, 166, 167, + 168, 0, 0, 169, 170, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 72, 73, 74, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 81, 0, 82, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -3, 0, 0, 12, 13, 14, 15, 16, 17, 0, + 171, 0, 0, 0, 0, 0, 172, 173, 174, 175, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 0, 31, 0, 32, 0, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 0, 70, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 71, 72, 73, 74, 0, 75, 0, + 0, 0, 0, 0, 0, 0, 76, 77, 78, 79, + 80, 0, 12, 13, 14, 15, 16, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 0, 31, 81, 32, 82, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 0, 70, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 71, 72, 73, 74, 0, 75, 0, 0, + 0, 0, 0, 0, 0, 76, 77, 78, 79, 80, + 14, 15, 16, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, + 0, 0, 0, 81, 0, 82, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 0, 340, 14, 15, 16, 17, 168, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 72, + 73, 74, 0, 0, 0, 0, 0, 0, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 0, 70, 14, 15, 16, 17, 0, 81, + 0, 82, 0, 0, 0, 0, 0, 0, 0, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 72, 73, 74, 0, 0, 0, 0, 0, 0, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 0, 70, 0, 0, 0, 0, + 0, 81, 0, 82, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 81, 0, 82 +}; + +static const yytype_int16 yycheck[] = +{ + 9, 76, 86, 87, 158, 229, 160, 4, 91, 76, + 146, 154, 257, 102, 380, 212, 213, 171, 84, 85, + 9, 109, 377, 9, 0, 391, 115, 141, 71, 191, + 141, 193, 3, 4, 187, 377, 33, 34, 35, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 211, + 196, 4, 95, 408, 193, 3, 4, 78, 169, 170, + 113, 32, 196, 34, 210, 36, 408, 38, 39, 40, + 113, 214, 211, 314, 416, 84, 418, 230, 212, 190, + 33, 34, 35, 328, 32, 76, 34, 96, 36, 313, + 38, 39, 40, 196, 196, 84, 250, 321, 84, 196, + 254, 237, 111, 257, 33, 76, 196, 110, 37, 212, + 212, 265, 112, 210, 123, 229, 269, 113, 229, 262, + 204, 205, 212, 132, 191, 113, 209, 193, 369, 195, + 192, 284, 103, 113, 196, 144, 192, 146, 213, 113, + 196, 365, 191, 384, 192, 154, 387, 192, 196, 120, + 196, 305, 192, 306, 395, 103, 196, 211, 76, 33, + 34, 314, 403, 37, 193, 192, 192, 192, 177, 196, + 196, 196, 120, 76, 328, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 213, 192, 104, 105, 106, 313, + 82, 83, 313, 197, 198, 214, 76, 321, 88, 89, + 321, 293, 294, 295, 296, 76, 369, 226, 113, 373, + 33, 34, 35, 201, 202, 203, 289, 290, 237, 382, + 76, 384, 291, 292, 387, 212, 390, 297, 298, 212, + 249, 191, 395, 212, 191, 212, 191, 210, 257, 191, + 403, 365, 192, 262, 365, 191, 410, 206, 90, 92, + 212, 207, 76, 191, 208, 75, 192, 194, 193, 193, + 211, 194, 191, 76, 196, 192, 191, 211, 194, 211, + 194, 194, 212, 192, 194, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 191, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 213, 34, 211, 36, 328, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 211, 12, 84, 85, 377, 212, + 12, 380, 303, 266, 226, 126, 133, 226, 299, 245, + 300, 75, 391, 144, 322, 103, 104, 105, 106, 301, + 108, 302, 249, 378, 86, 177, 391, 304, 249, 408, + 84, -1, 120, -1, -1, -1, -1, 416, -1, 418, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 328, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 154, -1, 156, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 191, -1, -1, -1, -1, -1, 197, + 198, 199, 200, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 212, 213, 214, 3, 4, 5, + 6, 7, 8, 9, 10, 11, -1, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, -1, 34, -1, + 36, -1, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, -1, -1, 84, 85, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 103, 104, 105, + 106, -1, 108, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 120, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 154, -1, + 156, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 191, -1, -1, -1, -1, + -1, 197, 198, 199, 200, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 212, 213, 214, 3, + 4, 5, 6, 7, 8, 9, 10, 11, -1, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, + 34, -1, 36, -1, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, -1, -1, + 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 103, + 104, 105, 106, -1, 108, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 120, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 154, -1, 156, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 191, -1, -1, + -1, -1, -1, 197, 198, 199, 200, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 212, 213, + 214, 3, 4, 5, 6, 7, 8, 9, 10, 11, + -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, -1, 34, -1, 36, -1, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 103, 104, 105, 106, -1, 108, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 120, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 154, -1, 156, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 191, + -1, -1, -1, -1, -1, 197, 198, 199, 200, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 212, 213, 214, 3, 4, 5, 6, 7, 8, 9, + 10, 11, -1, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, -1, 34, -1, 36, -1, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, -1, -1, 84, 85, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 103, 104, 105, 106, -1, 108, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 154, -1, 156, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 191, -1, -1, -1, -1, -1, 197, 198, 199, + 200, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 212, 213, 3, 4, 5, 6, 7, 8, + 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, -1, 34, -1, 36, -1, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, -1, -1, 84, 85, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 103, 104, 105, 106, -1, 108, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 120, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 154, -1, 156, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 191, -1, -1, -1, -1, -1, 197, 198, + 199, 200, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 212, 213, 3, 4, 5, 6, 7, + 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, -1, 34, -1, 36, -1, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, -1, -1, 84, 85, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 103, 104, 105, 106, -1, + 108, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 120, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 154, -1, 156, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 191, -1, -1, -1, -1, -1, 197, + 198, 199, 200, 3, 4, 5, 6, 7, 8, -1, + -1, -1, -1, -1, 212, 213, -1, -1, -1, -1, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, -1, 34, -1, 36, -1, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, -1, 76, 77, 78, 79, + 80, 81, -1, -1, 84, 85, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 103, 104, 105, 106, -1, 108, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 154, -1, 156, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 191, -1, -1, -1, -1, -1, 197, 198, 199, + 200, 3, 4, 5, 6, 7, 8, -1, -1, -1, + -1, -1, 212, -1, -1, -1, -1, -1, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, -1, 34, -1, 36, -1, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, -1, 76, 77, 78, 79, 80, 81, + -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 103, 104, 105, 106, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 120, 5, + 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, + -1, -1, 154, -1, 156, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 191, + 76, -1, -1, -1, -1, 197, 198, 199, 200, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 212, -1, -1, -1, -1, -1, -1, -1, 104, 105, + 106, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 5, 6, 7, 8, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, -1, -1, -1, -1, -1, -1, 154, -1, + 156, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, -1, 76, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 214, -1, + -1, -1, -1, -1, 104, 105, 106, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 5, 6, 7, 8, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, + -1, -1, -1, -1, 154, -1, 156, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, -1, 76, 77, 78, 79, 80, 81, -1, -1, + 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 214, -1, -1, -1, -1, -1, + 104, 105, 106, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 154, -1, 156, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 191, -1, -1, + -1, -1, -1, 197, 198, 199, 200, 3, 4, 5, + 6, 7, 8, -1, -1, -1, -1, -1, 212, -1, + -1, -1, -1, -1, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, -1, 34, -1, + 36, -1, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, -1, + 76, 77, 78, 79, 80, 81, -1, -1, 84, 85, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 103, 104, 105, + 106, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 120, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 154, -1, + 156, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 5, 6, 7, 8, -1, 191, -1, -1, -1, -1, + -1, 197, 198, 199, 200, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + -1, 76, 77, 78, 79, 80, 81, -1, -1, 84, + 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, + 105, 106, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 154, + -1, 156, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 5, 6, 7, 8, -1, 191, -1, -1, 194, + -1, -1, 197, 198, 199, 200, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, -1, 76, 77, 78, 79, 80, 81, -1, -1, + 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 104, 105, 106, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 154, -1, 156, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 5, 6, 7, 8, -1, 191, -1, -1, + 194, -1, -1, 197, 198, 199, 200, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, -1, 76, 77, 78, 79, 80, 81, -1, + -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 104, 105, 106, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 154, -1, 156, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 5, 6, 7, 8, -1, 191, -1, + -1, 194, -1, -1, 197, 198, 199, 200, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, -1, 76, 77, 78, 79, 80, 81, + -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 104, 105, 106, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 154, -1, 156, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 5, 6, 7, 8, -1, 191, + -1, -1, -1, -1, -1, 197, 198, 199, 200, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, -1, 76, 77, 78, 79, 80, + 81, -1, -1, 84, 85, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 104, 105, 106, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 154, -1, 156, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, -1, -1, 3, 4, 5, 6, 7, 8, -1, + 191, -1, -1, -1, -1, -1, 197, 198, 199, 200, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, -1, 34, -1, 36, -1, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, -1, 76, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 103, 104, 105, 106, -1, 108, -1, + -1, -1, -1, -1, -1, -1, 116, 117, 118, 119, + 120, -1, 3, 4, 5, 6, 7, 8, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, -1, 34, 154, 36, 156, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, -1, 76, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 103, 104, 105, 106, -1, 108, -1, -1, + -1, -1, -1, -1, -1, 116, 117, 118, 119, 120, + 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, + -1, -1, -1, 154, -1, 156, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + -1, 76, 5, 6, 7, 8, 81, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 104, + 105, 106, -1, -1, -1, -1, -1, -1, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, -1, 76, 5, 6, 7, 8, -1, 154, + -1, 156, -1, -1, -1, -1, -1, -1, -1, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 104, 105, 106, -1, -1, -1, -1, -1, -1, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, -1, 76, -1, -1, -1, -1, + -1, 154, -1, 156, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 154, -1, 156 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint16 yystos[] = +{ + 0, 109, 216, 218, 78, 0, 220, 113, 110, 217, + 221, 76, 3, 4, 5, 6, 7, 8, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 34, 36, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 76, 103, 104, 105, 106, 108, 116, 117, 118, 119, + 120, 154, 156, 219, 222, 252, 253, 254, 255, 256, + 261, 262, 263, 264, 265, 268, 270, 271, 272, 273, + 274, 275, 276, 277, 303, 304, 112, 33, 34, 37, + 76, 213, 76, 103, 270, 276, 113, 113, 113, 113, + 191, 303, 212, 213, 290, 192, 196, 4, 33, 34, + 35, 258, 259, 269, 196, 212, 76, 33, 37, 270, + 272, 193, 273, 76, 213, 272, 278, 279, 273, 76, + 266, 267, 9, 10, 11, 13, 14, 15, 16, 17, + 18, 19, 75, 76, 77, 78, 79, 80, 81, 84, + 85, 191, 197, 198, 199, 200, 212, 213, 214, 223, + 224, 225, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 250, 252, 253, 272, 283, 284, + 285, 286, 287, 288, 291, 292, 293, 294, 296, 297, + 298, 302, 258, 257, 260, 272, 259, 76, 191, 193, + 211, 194, 234, 247, 251, 272, 113, 278, 76, 280, + 281, 214, 279, 212, 192, 196, 212, 212, 284, 191, + 191, 212, 212, 250, 191, 250, 210, 191, 234, 234, + 250, 214, 291, 84, 85, 193, 195, 192, 192, 196, + 74, 248, 191, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 211, 249, 234, 201, 202, 203, 197, + 198, 82, 83, 86, 87, 204, 205, 88, 89, 206, + 207, 208, 90, 92, 91, 209, 196, 212, 214, 284, + 76, 257, 260, 193, 211, 194, 251, 248, 282, 194, + 214, 193, 196, 212, 267, 75, 283, 292, 299, 250, + 212, 250, 210, 250, 263, 295, 192, 214, 226, 250, + 76, 229, 248, 248, 234, 234, 234, 236, 236, 237, + 237, 238, 238, 238, 238, 239, 239, 240, 241, 242, + 243, 244, 245, 250, 248, 193, 194, 251, 282, 211, + 194, 251, 281, 191, 295, 300, 301, 192, 192, 76, + 192, 194, 210, 251, 211, 194, 282, 211, 194, 250, + 212, 192, 285, 286, 288, 211, 14, 287, 289, 290, + 248, 194, 282, 211, 282, 192, 250, 289, 12, 282, + 191, 282, 212, 285, 286, 250, 192, 285, 12 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, state, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, &yylloc, scanner) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, state); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct _mesa_glsl_parse_state *state) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + struct _mesa_glsl_parse_state *state; +#endif +{ + if (!yyvaluep) + return; + YYUSE (yylocationp); + YYUSE (state); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct _mesa_glsl_parse_state *state) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, state) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + struct _mesa_glsl_parse_state *state; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, state); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, struct _mesa_glsl_parse_state *state) +#else +static void +yy_reduce_print (yyvsp, yylsp, yyrule, state) + YYSTYPE *yyvsp; + YYLTYPE *yylsp; + int yyrule; + struct _mesa_glsl_parse_state *state; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , state); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, yylsp, Rule, state); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, struct _mesa_glsl_parse_state *state) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, yylocationp, state) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + YYLTYPE *yylocationp; + struct _mesa_glsl_parse_state *state; +#endif +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (state); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (struct _mesa_glsl_parse_state *state); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (struct _mesa_glsl_parse_state *state) +#else +int +yyparse (state) + struct _mesa_glsl_parse_state *state; +#endif +#endif +{ +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Location data for the lookahead symbol. */ +YYLTYPE yylloc; + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls; + YYLTYPE *yylsp; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[2]; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yyls = yylsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + yylsp = yyls; + +#if YYLTYPE_IS_TRIVIAL + /* Initialize the default location before parsing starts. */ + yylloc.first_line = yylloc.last_line = 1; + yylloc.first_column = yylloc.last_column = 1; +#endif + +/* User initialization code. */ + +/* Line 1242 of yacc.c */ +#line 41 "glsl_parser.ypp" +{ + yylloc.first_line = 1; + yylloc.first_column = 1; + yylloc.last_line = 1; + yylloc.last_column = 1; + yylloc.source = 0; +} + +/* Line 1242 of yacc.c */ +#line 2705 "glsl_parser.cpp" + yylsp[0] = yylloc; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + +/* Line 1455 of yacc.c */ +#line 211 "glsl_parser.ypp" + { + _mesa_glsl_initialize_types(state); + ;} + break; + + case 4: + +/* Line 1455 of yacc.c */ +#line 219 "glsl_parser.ypp" + { + state->language_version = 110; + state->symbols->language_version = 110; + ;} + break; + + case 5: + +/* Line 1455 of yacc.c */ +#line 224 "glsl_parser.ypp" + { + switch ((yyvsp[(2) - (3)].n)) { + case 110: + case 120: + case 130: + /* FINISHME: Check against implementation support versions. */ + state->language_version = (yyvsp[(2) - (3)].n); + state->symbols->language_version = (yyvsp[(2) - (3)].n); + break; + default: + _mesa_glsl_error(& (yylsp[(2) - (3)]), state, "Shading language version" + "%u is not supported\n", (yyvsp[(2) - (3)].n)); + break; + } + ;} + break; + + case 12: + +/* Line 1455 of yacc.c */ +#line 255 "glsl_parser.ypp" + { + if (!_mesa_glsl_process_extension((yyvsp[(2) - (5)].identifier), & (yylsp[(2) - (5)]), (yyvsp[(4) - (5)].identifier), & (yylsp[(4) - (5)]), state)) { + YYERROR; + } + ;} + break; + + case 13: + +/* Line 1455 of yacc.c */ +#line 264 "glsl_parser.ypp" + { + /* FINISHME: The NULL test is only required because 'precision' + * FINISHME: statements are not yet supported. + */ + if ((yyvsp[(1) - (1)].node) != NULL) + state->translation_unit.push_tail(& (yyvsp[(1) - (1)].node)->link); + ;} + break; + + case 14: + +/* Line 1455 of yacc.c */ +#line 272 "glsl_parser.ypp" + { + /* FINISHME: The NULL test is only required because 'precision' + * FINISHME: statements are not yet supported. + */ + if ((yyvsp[(2) - (2)].node) != NULL) + state->translation_unit.push_tail(& (yyvsp[(2) - (2)].node)->link); + ;} + break; + + case 16: + +/* Line 1455 of yacc.c */ +#line 287 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_identifier, NULL, NULL, NULL); + (yyval.expression)->set_location(yylloc); + (yyval.expression)->primary_expression.identifier = (yyvsp[(1) - (1)].identifier); + ;} + break; + + case 17: + +/* Line 1455 of yacc.c */ +#line 294 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_int_constant, NULL, NULL, NULL); + (yyval.expression)->set_location(yylloc); + (yyval.expression)->primary_expression.int_constant = (yyvsp[(1) - (1)].n); + ;} + break; + + case 18: + +/* Line 1455 of yacc.c */ +#line 301 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_uint_constant, NULL, NULL, NULL); + (yyval.expression)->set_location(yylloc); + (yyval.expression)->primary_expression.uint_constant = (yyvsp[(1) - (1)].n); + ;} + break; + + case 19: + +/* Line 1455 of yacc.c */ +#line 308 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_float_constant, NULL, NULL, NULL); + (yyval.expression)->set_location(yylloc); + (yyval.expression)->primary_expression.float_constant = (yyvsp[(1) - (1)].real); + ;} + break; + + case 20: + +/* Line 1455 of yacc.c */ +#line 315 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_bool_constant, NULL, NULL, NULL); + (yyval.expression)->set_location(yylloc); + (yyval.expression)->primary_expression.bool_constant = (yyvsp[(1) - (1)].n); + ;} + break; + + case 21: + +/* Line 1455 of yacc.c */ +#line 322 "glsl_parser.ypp" + { + (yyval.expression) = (yyvsp[(2) - (3)].expression); + ;} + break; + + case 23: + +/* Line 1455 of yacc.c */ +#line 330 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_array_index, (yyvsp[(1) - (4)].expression), (yyvsp[(3) - (4)].expression), NULL); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 24: + +/* Line 1455 of yacc.c */ +#line 336 "glsl_parser.ypp" + { + (yyval.expression) = (yyvsp[(1) - (1)].expression); + ;} + break; + + case 25: + +/* Line 1455 of yacc.c */ +#line 340 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_field_selection, (yyvsp[(1) - (3)].expression), NULL, NULL); + (yyval.expression)->set_location(yylloc); + (yyval.expression)->primary_expression.identifier = (yyvsp[(3) - (3)].identifier); + ;} + break; + + case 26: + +/* Line 1455 of yacc.c */ +#line 347 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_post_inc, (yyvsp[(1) - (2)].expression), NULL, NULL); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 27: + +/* Line 1455 of yacc.c */ +#line 353 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_post_dec, (yyvsp[(1) - (2)].expression), NULL, NULL); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 31: + +/* Line 1455 of yacc.c */ +#line 371 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_field_selection, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression), NULL); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 36: + +/* Line 1455 of yacc.c */ +#line 390 "glsl_parser.ypp" + { + (yyval.expression) = (yyvsp[(1) - (2)].expression); + (yyval.expression)->set_location(yylloc); + (yyval.expression)->expressions.push_tail(& (yyvsp[(2) - (2)].expression)->link); + ;} + break; + + case 37: + +/* Line 1455 of yacc.c */ +#line 396 "glsl_parser.ypp" + { + (yyval.expression) = (yyvsp[(1) - (3)].expression); + (yyval.expression)->set_location(yylloc); + (yyval.expression)->expressions.push_tail(& (yyvsp[(3) - (3)].expression)->link); + ;} + break; + + case 39: + +/* Line 1455 of yacc.c */ +#line 412 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_function_expression((yyvsp[(1) - (1)].type_specifier)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 40: + +/* Line 1455 of yacc.c */ +#line 418 "glsl_parser.ypp" + { + void *ctx = state; + ast_expression *callee = new(ctx) ast_expression((yyvsp[(1) - (1)].identifier)); + (yyval.expression) = new(ctx) ast_function_expression(callee); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 41: + +/* Line 1455 of yacc.c */ +#line 425 "glsl_parser.ypp" + { + void *ctx = state; + ast_expression *callee = new(ctx) ast_expression((yyvsp[(1) - (1)].identifier)); + (yyval.expression) = new(ctx) ast_function_expression(callee); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 43: + +/* Line 1455 of yacc.c */ +#line 437 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_pre_inc, (yyvsp[(2) - (2)].expression), NULL, NULL); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 44: + +/* Line 1455 of yacc.c */ +#line 443 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_pre_dec, (yyvsp[(2) - (2)].expression), NULL, NULL); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 45: + +/* Line 1455 of yacc.c */ +#line 449 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression((yyvsp[(1) - (2)].n), (yyvsp[(2) - (2)].expression), NULL, NULL); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 46: + +/* Line 1455 of yacc.c */ +#line 458 "glsl_parser.ypp" + { (yyval.n) = ast_plus; ;} + break; + + case 47: + +/* Line 1455 of yacc.c */ +#line 459 "glsl_parser.ypp" + { (yyval.n) = ast_neg; ;} + break; + + case 48: + +/* Line 1455 of yacc.c */ +#line 460 "glsl_parser.ypp" + { (yyval.n) = ast_logic_not; ;} + break; + + case 49: + +/* Line 1455 of yacc.c */ +#line 461 "glsl_parser.ypp" + { (yyval.n) = ast_bit_not; ;} + break; + + case 51: + +/* Line 1455 of yacc.c */ +#line 467 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_mul, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 52: + +/* Line 1455 of yacc.c */ +#line 473 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_div, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 53: + +/* Line 1455 of yacc.c */ +#line 479 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_mod, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 55: + +/* Line 1455 of yacc.c */ +#line 489 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_add, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 56: + +/* Line 1455 of yacc.c */ +#line 495 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_sub, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 58: + +/* Line 1455 of yacc.c */ +#line 505 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_lshift, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 59: + +/* Line 1455 of yacc.c */ +#line 511 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_rshift, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 61: + +/* Line 1455 of yacc.c */ +#line 521 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_less, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 62: + +/* Line 1455 of yacc.c */ +#line 527 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_greater, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 63: + +/* Line 1455 of yacc.c */ +#line 533 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_lequal, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 64: + +/* Line 1455 of yacc.c */ +#line 539 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_gequal, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 66: + +/* Line 1455 of yacc.c */ +#line 549 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_equal, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 67: + +/* Line 1455 of yacc.c */ +#line 555 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_nequal, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 69: + +/* Line 1455 of yacc.c */ +#line 565 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_bit_or, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 71: + +/* Line 1455 of yacc.c */ +#line 575 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_bit_xor, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 73: + +/* Line 1455 of yacc.c */ +#line 585 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_bit_or, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 75: + +/* Line 1455 of yacc.c */ +#line 595 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_logic_and, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 77: + +/* Line 1455 of yacc.c */ +#line 605 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_logic_xor, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 79: + +/* Line 1455 of yacc.c */ +#line 615 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression_bin(ast_logic_or, (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 81: + +/* Line 1455 of yacc.c */ +#line 625 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression(ast_conditional, (yyvsp[(1) - (5)].expression), (yyvsp[(3) - (5)].expression), (yyvsp[(5) - (5)].expression)); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 83: + +/* Line 1455 of yacc.c */ +#line 635 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.expression) = new(ctx) ast_expression((yyvsp[(2) - (3)].n), (yyvsp[(1) - (3)].expression), (yyvsp[(3) - (3)].expression), NULL); + (yyval.expression)->set_location(yylloc); + ;} + break; + + case 84: + +/* Line 1455 of yacc.c */ +#line 643 "glsl_parser.ypp" + { (yyval.n) = ast_assign; ;} + break; + + case 85: + +/* Line 1455 of yacc.c */ +#line 644 "glsl_parser.ypp" + { (yyval.n) = ast_mul_assign; ;} + break; + + case 86: + +/* Line 1455 of yacc.c */ +#line 645 "glsl_parser.ypp" + { (yyval.n) = ast_div_assign; ;} + break; + + case 87: + +/* Line 1455 of yacc.c */ +#line 646 "glsl_parser.ypp" + { (yyval.n) = ast_mod_assign; ;} + break; + + case 88: + +/* Line 1455 of yacc.c */ +#line 647 "glsl_parser.ypp" + { (yyval.n) = ast_add_assign; ;} + break; + + case 89: + +/* Line 1455 of yacc.c */ +#line 648 "glsl_parser.ypp" + { (yyval.n) = ast_sub_assign; ;} + break; + + case 90: + +/* Line 1455 of yacc.c */ +#line 649 "glsl_parser.ypp" + { (yyval.n) = ast_ls_assign; ;} + break; + + case 91: + +/* Line 1455 of yacc.c */ +#line 650 "glsl_parser.ypp" + { (yyval.n) = ast_rs_assign; ;} + break; + + case 92: + +/* Line 1455 of yacc.c */ +#line 651 "glsl_parser.ypp" + { (yyval.n) = ast_and_assign; ;} + break; + + case 93: + +/* Line 1455 of yacc.c */ +#line 652 "glsl_parser.ypp" + { (yyval.n) = ast_xor_assign; ;} + break; + + case 94: + +/* Line 1455 of yacc.c */ +#line 653 "glsl_parser.ypp" + { (yyval.n) = ast_or_assign; ;} + break; + + case 95: + +/* Line 1455 of yacc.c */ +#line 658 "glsl_parser.ypp" + { + (yyval.expression) = (yyvsp[(1) - (1)].expression); + ;} + break; + + case 96: + +/* Line 1455 of yacc.c */ +#line 662 "glsl_parser.ypp" + { + void *ctx = state; + if ((yyvsp[(1) - (3)].expression)->oper != ast_sequence) { + (yyval.expression) = new(ctx) ast_expression(ast_sequence, NULL, NULL, NULL); + (yyval.expression)->set_location(yylloc); + (yyval.expression)->expressions.push_tail(& (yyvsp[(1) - (3)].expression)->link); + } else { + (yyval.expression) = (yyvsp[(1) - (3)].expression); + } + + (yyval.expression)->expressions.push_tail(& (yyvsp[(3) - (3)].expression)->link); + ;} + break; + + case 98: + +/* Line 1455 of yacc.c */ +#line 682 "glsl_parser.ypp" + { + (yyval.node) = (yyvsp[(1) - (2)].function); + ;} + break; + + case 99: + +/* Line 1455 of yacc.c */ +#line 686 "glsl_parser.ypp" + { + (yyval.node) = (yyvsp[(1) - (2)].declarator_list); + ;} + break; + + case 100: + +/* Line 1455 of yacc.c */ +#line 690 "glsl_parser.ypp" + { + if (((yyvsp[(3) - (4)].type_specifier)->type_specifier != ast_float) + && ((yyvsp[(3) - (4)].type_specifier)->type_specifier != ast_int)) { + _mesa_glsl_error(& (yylsp[(3) - (4)]), state, "global precision qualifier can " + "only be applied to `int' or `float'\n"); + YYERROR; + } + + (yyval.node) = NULL; /* FINISHME */ + ;} + break; + + case 104: + +/* Line 1455 of yacc.c */ +#line 713 "glsl_parser.ypp" + { + (yyval.function) = (yyvsp[(1) - (2)].function); + (yyval.function)->parameters.push_tail(& (yyvsp[(2) - (2)].parameter_declarator)->link); + ;} + break; + + case 105: + +/* Line 1455 of yacc.c */ +#line 718 "glsl_parser.ypp" + { + (yyval.function) = (yyvsp[(1) - (3)].function); + (yyval.function)->parameters.push_tail(& (yyvsp[(3) - (3)].parameter_declarator)->link); + ;} + break; + + case 106: + +/* Line 1455 of yacc.c */ +#line 726 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.function) = new(ctx) ast_function(); + (yyval.function)->set_location(yylloc); + (yyval.function)->return_type = (yyvsp[(1) - (3)].fully_specified_type); + (yyval.function)->identifier = (yyvsp[(2) - (3)].identifier); + ;} + break; + + case 107: + +/* Line 1455 of yacc.c */ +#line 737 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.parameter_declarator) = new(ctx) ast_parameter_declarator(); + (yyval.parameter_declarator)->set_location(yylloc); + (yyval.parameter_declarator)->type = new(ctx) ast_fully_specified_type(); + (yyval.parameter_declarator)->type->set_location(yylloc); + (yyval.parameter_declarator)->type->specifier = (yyvsp[(1) - (2)].type_specifier); + (yyval.parameter_declarator)->identifier = (yyvsp[(2) - (2)].identifier); + ;} + break; + + case 108: + +/* Line 1455 of yacc.c */ +#line 747 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.parameter_declarator) = new(ctx) ast_parameter_declarator(); + (yyval.parameter_declarator)->set_location(yylloc); + (yyval.parameter_declarator)->type = new(ctx) ast_fully_specified_type(); + (yyval.parameter_declarator)->type->set_location(yylloc); + (yyval.parameter_declarator)->type->specifier = (yyvsp[(1) - (5)].type_specifier); + (yyval.parameter_declarator)->identifier = (yyvsp[(2) - (5)].identifier); + (yyval.parameter_declarator)->is_array = true; + (yyval.parameter_declarator)->array_size = (yyvsp[(4) - (5)].expression); + ;} + break; + + case 109: + +/* Line 1455 of yacc.c */ +#line 762 "glsl_parser.ypp" + { + (yyvsp[(1) - (3)].type_qualifier).i |= (yyvsp[(2) - (3)].type_qualifier).i; + + (yyval.parameter_declarator) = (yyvsp[(3) - (3)].parameter_declarator); + (yyval.parameter_declarator)->type->qualifier = (yyvsp[(1) - (3)].type_qualifier).q; + ;} + break; + + case 110: + +/* Line 1455 of yacc.c */ +#line 769 "glsl_parser.ypp" + { + (yyval.parameter_declarator) = (yyvsp[(2) - (2)].parameter_declarator); + (yyval.parameter_declarator)->type->qualifier = (yyvsp[(1) - (2)].type_qualifier).q; + ;} + break; + + case 111: + +/* Line 1455 of yacc.c */ +#line 774 "glsl_parser.ypp" + { + void *ctx = state; + (yyvsp[(1) - (3)].type_qualifier).i |= (yyvsp[(2) - (3)].type_qualifier).i; + + (yyval.parameter_declarator) = new(ctx) ast_parameter_declarator(); + (yyval.parameter_declarator)->set_location(yylloc); + (yyval.parameter_declarator)->type = new(ctx) ast_fully_specified_type(); + (yyval.parameter_declarator)->type->qualifier = (yyvsp[(1) - (3)].type_qualifier).q; + (yyval.parameter_declarator)->type->specifier = (yyvsp[(3) - (3)].type_specifier); + ;} + break; + + case 112: + +/* Line 1455 of yacc.c */ +#line 785 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.parameter_declarator) = new(ctx) ast_parameter_declarator(); + (yyval.parameter_declarator)->set_location(yylloc); + (yyval.parameter_declarator)->type = new(ctx) ast_fully_specified_type(); + (yyval.parameter_declarator)->type->qualifier = (yyvsp[(1) - (2)].type_qualifier).q; + (yyval.parameter_declarator)->type->specifier = (yyvsp[(2) - (2)].type_specifier); + ;} + break; + + case 113: + +/* Line 1455 of yacc.c */ +#line 796 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; ;} + break; + + case 114: + +/* Line 1455 of yacc.c */ +#line 797 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.in = 1; ;} + break; + + case 115: + +/* Line 1455 of yacc.c */ +#line 798 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.out = 1; ;} + break; + + case 116: + +/* Line 1455 of yacc.c */ +#line 799 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.in = 1; (yyval.type_qualifier).q.out = 1; ;} + break; + + case 119: + +/* Line 1455 of yacc.c */ +#line 809 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (3)].identifier), false, NULL, NULL); + decl->set_location(yylloc); + + (yyval.declarator_list) = (yyvsp[(1) - (3)].declarator_list); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 120: + +/* Line 1455 of yacc.c */ +#line 818 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (5)].identifier), true, NULL, NULL); + decl->set_location(yylloc); + + (yyval.declarator_list) = (yyvsp[(1) - (5)].declarator_list); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 121: + +/* Line 1455 of yacc.c */ +#line 827 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (6)].identifier), true, (yyvsp[(5) - (6)].expression), NULL); + decl->set_location(yylloc); + + (yyval.declarator_list) = (yyvsp[(1) - (6)].declarator_list); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 122: + +/* Line 1455 of yacc.c */ +#line 836 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (7)].identifier), true, NULL, (yyvsp[(7) - (7)].expression)); + decl->set_location(yylloc); + + (yyval.declarator_list) = (yyvsp[(1) - (7)].declarator_list); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 123: + +/* Line 1455 of yacc.c */ +#line 845 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (8)].identifier), true, (yyvsp[(5) - (8)].expression), (yyvsp[(8) - (8)].expression)); + decl->set_location(yylloc); + + (yyval.declarator_list) = (yyvsp[(1) - (8)].declarator_list); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 124: + +/* Line 1455 of yacc.c */ +#line 854 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(3) - (5)].identifier), false, NULL, (yyvsp[(5) - (5)].expression)); + decl->set_location(yylloc); + + (yyval.declarator_list) = (yyvsp[(1) - (5)].declarator_list); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 125: + +/* Line 1455 of yacc.c */ +#line 867 "glsl_parser.ypp" + { + void *ctx = state; + if ((yyvsp[(1) - (1)].fully_specified_type)->specifier->type_specifier != ast_struct) { + _mesa_glsl_error(& (yylsp[(1) - (1)]), state, "empty declaration list\n"); + YYERROR; + } else { + (yyval.declarator_list) = new(ctx) ast_declarator_list((yyvsp[(1) - (1)].fully_specified_type)); + (yyval.declarator_list)->set_location(yylloc); + } + ;} + break; + + case 126: + +/* Line 1455 of yacc.c */ +#line 878 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (2)].identifier), false, NULL, NULL); + + (yyval.declarator_list) = new(ctx) ast_declarator_list((yyvsp[(1) - (2)].fully_specified_type)); + (yyval.declarator_list)->set_location(yylloc); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 127: + +/* Line 1455 of yacc.c */ +#line 887 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (4)].identifier), true, NULL, NULL); + + (yyval.declarator_list) = new(ctx) ast_declarator_list((yyvsp[(1) - (4)].fully_specified_type)); + (yyval.declarator_list)->set_location(yylloc); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 128: + +/* Line 1455 of yacc.c */ +#line 896 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (5)].identifier), true, (yyvsp[(4) - (5)].expression), NULL); + + (yyval.declarator_list) = new(ctx) ast_declarator_list((yyvsp[(1) - (5)].fully_specified_type)); + (yyval.declarator_list)->set_location(yylloc); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 129: + +/* Line 1455 of yacc.c */ +#line 905 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (6)].identifier), true, NULL, (yyvsp[(6) - (6)].expression)); + + (yyval.declarator_list) = new(ctx) ast_declarator_list((yyvsp[(1) - (6)].fully_specified_type)); + (yyval.declarator_list)->set_location(yylloc); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 130: + +/* Line 1455 of yacc.c */ +#line 914 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (7)].identifier), true, (yyvsp[(4) - (7)].expression), (yyvsp[(7) - (7)].expression)); + + (yyval.declarator_list) = new(ctx) ast_declarator_list((yyvsp[(1) - (7)].fully_specified_type)); + (yyval.declarator_list)->set_location(yylloc); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 131: + +/* Line 1455 of yacc.c */ +#line 923 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (4)].identifier), false, NULL, (yyvsp[(4) - (4)].expression)); + + (yyval.declarator_list) = new(ctx) ast_declarator_list((yyvsp[(1) - (4)].fully_specified_type)); + (yyval.declarator_list)->set_location(yylloc); + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 132: + +/* Line 1455 of yacc.c */ +#line 932 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (2)].identifier), false, NULL, NULL); + + (yyval.declarator_list) = new(ctx) ast_declarator_list(NULL); + (yyval.declarator_list)->set_location(yylloc); + (yyval.declarator_list)->invariant = true; + + (yyval.declarator_list)->declarations.push_tail(&decl->link); + ;} + break; + + case 133: + +/* Line 1455 of yacc.c */ +#line 946 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.fully_specified_type) = new(ctx) ast_fully_specified_type(); + (yyval.fully_specified_type)->set_location(yylloc); + (yyval.fully_specified_type)->specifier = (yyvsp[(1) - (1)].type_specifier); + ;} + break; + + case 134: + +/* Line 1455 of yacc.c */ +#line 953 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.fully_specified_type) = new(ctx) ast_fully_specified_type(); + (yyval.fully_specified_type)->set_location(yylloc); + (yyval.fully_specified_type)->qualifier = (yyvsp[(1) - (2)].type_qualifier).q; + (yyval.fully_specified_type)->specifier = (yyvsp[(2) - (2)].type_specifier); + ;} + break; + + case 135: + +/* Line 1455 of yacc.c */ +#line 963 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; ;} + break; + + case 137: + +/* Line 1455 of yacc.c */ +#line 969 "glsl_parser.ypp" + { + (yyval.type_qualifier) = (yyvsp[(3) - (4)].type_qualifier); + ;} + break; + + case 139: + +/* Line 1455 of yacc.c */ +#line 977 "glsl_parser.ypp" + { + (yyval.type_qualifier).i = (yyvsp[(1) - (3)].type_qualifier).i | (yyvsp[(3) - (3)].type_qualifier).i; + ;} + break; + + case 140: + +/* Line 1455 of yacc.c */ +#line 984 "glsl_parser.ypp" + { + (yyval.type_qualifier).i = 0; + + if (state->ARB_fragment_coord_conventions_enable) { + bool got_one = false; + + if (strcmp((yyvsp[(1) - (1)].identifier), "origin_upper_left") == 0) { + got_one = true; + (yyval.type_qualifier).q.origin_upper_left = 1; + } else if (strcmp((yyvsp[(1) - (1)].identifier), "pixel_center_integer") == 0) { + got_one = true; + (yyval.type_qualifier).q.pixel_center_integer = 1; + } + + if (state->ARB_fragment_coord_conventions_warn && got_one) { + _mesa_glsl_warning(& (yylsp[(1) - (1)]), state, + "GL_ARB_fragment_coord_conventions layout " + "identifier `%s' used\n", (yyvsp[(1) - (1)].identifier)); + } + } + + /* If the identifier didn't match any known layout identifiers, + * emit an error. + */ + if ((yyval.type_qualifier).i == 0) { + _mesa_glsl_error(& (yylsp[(1) - (1)]), state, "unrecognized layout identifier " + "`%s'\n", (yyvsp[(1) - (1)].identifier)); + YYERROR; + } + ;} + break; + + case 141: + +/* Line 1455 of yacc.c */ +#line 1017 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.smooth = 1; ;} + break; + + case 142: + +/* Line 1455 of yacc.c */ +#line 1018 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.flat = 1; ;} + break; + + case 143: + +/* Line 1455 of yacc.c */ +#line 1019 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.noperspective = 1; ;} + break; + + case 144: + +/* Line 1455 of yacc.c */ +#line 1023 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.constant = 1; ;} + break; + + case 146: + +/* Line 1455 of yacc.c */ +#line 1029 "glsl_parser.ypp" + { + (yyval.type_qualifier).i = (yyvsp[(1) - (2)].type_qualifier).i | (yyvsp[(2) - (2)].type_qualifier).i; + ;} + break; + + case 147: + +/* Line 1455 of yacc.c */ +#line 1033 "glsl_parser.ypp" + { + (yyval.type_qualifier) = (yyvsp[(2) - (2)].type_qualifier); + (yyval.type_qualifier).q.invariant = 1; + ;} + break; + + case 148: + +/* Line 1455 of yacc.c */ +#line 1040 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.constant = 1; ;} + break; + + case 149: + +/* Line 1455 of yacc.c */ +#line 1041 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.attribute = 1; ;} + break; + + case 150: + +/* Line 1455 of yacc.c */ +#line 1042 "glsl_parser.ypp" + { (yyval.type_qualifier).i = (yyvsp[(1) - (2)].type_qualifier).i; (yyval.type_qualifier).q.varying = 1; ;} + break; + + case 151: + +/* Line 1455 of yacc.c */ +#line 1043 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.centroid = 1; (yyval.type_qualifier).q.varying = 1; ;} + break; + + case 152: + +/* Line 1455 of yacc.c */ +#line 1044 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.in = 1; ;} + break; + + case 153: + +/* Line 1455 of yacc.c */ +#line 1045 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.out = 1; ;} + break; + + case 154: + +/* Line 1455 of yacc.c */ +#line 1046 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.centroid = 1; (yyval.type_qualifier).q.in = 1; ;} + break; + + case 155: + +/* Line 1455 of yacc.c */ +#line 1047 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.centroid = 1; (yyval.type_qualifier).q.out = 1; ;} + break; + + case 156: + +/* Line 1455 of yacc.c */ +#line 1048 "glsl_parser.ypp" + { (yyval.type_qualifier).i = 0; (yyval.type_qualifier).q.uniform = 1; ;} + break; + + case 158: + +/* Line 1455 of yacc.c */ +#line 1054 "glsl_parser.ypp" + { + (yyval.type_specifier) = (yyvsp[(2) - (2)].type_specifier); + (yyval.type_specifier)->precision = (yyvsp[(1) - (2)].n); + ;} + break; + + case 160: + +/* Line 1455 of yacc.c */ +#line 1063 "glsl_parser.ypp" + { + (yyval.type_specifier) = (yyvsp[(1) - (3)].type_specifier); + (yyval.type_specifier)->is_array = true; + (yyval.type_specifier)->array_size = NULL; + ;} + break; + + case 161: + +/* Line 1455 of yacc.c */ +#line 1069 "glsl_parser.ypp" + { + (yyval.type_specifier) = (yyvsp[(1) - (4)].type_specifier); + (yyval.type_specifier)->is_array = true; + (yyval.type_specifier)->array_size = (yyvsp[(3) - (4)].expression); + ;} + break; + + case 162: + +/* Line 1455 of yacc.c */ +#line 1078 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.type_specifier) = new(ctx) ast_type_specifier((yyvsp[(1) - (1)].n)); + (yyval.type_specifier)->set_location(yylloc); + ;} + break; + + case 163: + +/* Line 1455 of yacc.c */ +#line 1084 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.type_specifier) = new(ctx) ast_type_specifier((yyvsp[(1) - (1)].struct_specifier)); + (yyval.type_specifier)->set_location(yylloc); + ;} + break; + + case 164: + +/* Line 1455 of yacc.c */ +#line 1090 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.type_specifier) = new(ctx) ast_type_specifier((yyvsp[(1) - (1)].identifier)); + (yyval.type_specifier)->set_location(yylloc); + ;} + break; + + case 165: + +/* Line 1455 of yacc.c */ +#line 1098 "glsl_parser.ypp" + { (yyval.n) = ast_void; ;} + break; + + case 166: + +/* Line 1455 of yacc.c */ +#line 1099 "glsl_parser.ypp" + { (yyval.n) = ast_float; ;} + break; + + case 167: + +/* Line 1455 of yacc.c */ +#line 1100 "glsl_parser.ypp" + { (yyval.n) = ast_int; ;} + break; + + case 168: + +/* Line 1455 of yacc.c */ +#line 1101 "glsl_parser.ypp" + { (yyval.n) = ast_uint; ;} + break; + + case 169: + +/* Line 1455 of yacc.c */ +#line 1102 "glsl_parser.ypp" + { (yyval.n) = ast_bool; ;} + break; + + case 170: + +/* Line 1455 of yacc.c */ +#line 1103 "glsl_parser.ypp" + { (yyval.n) = ast_vec2; ;} + break; + + case 171: + +/* Line 1455 of yacc.c */ +#line 1104 "glsl_parser.ypp" + { (yyval.n) = ast_vec3; ;} + break; + + case 172: + +/* Line 1455 of yacc.c */ +#line 1105 "glsl_parser.ypp" + { (yyval.n) = ast_vec4; ;} + break; + + case 173: + +/* Line 1455 of yacc.c */ +#line 1106 "glsl_parser.ypp" + { (yyval.n) = ast_bvec2; ;} + break; + + case 174: + +/* Line 1455 of yacc.c */ +#line 1107 "glsl_parser.ypp" + { (yyval.n) = ast_bvec3; ;} + break; + + case 175: + +/* Line 1455 of yacc.c */ +#line 1108 "glsl_parser.ypp" + { (yyval.n) = ast_bvec4; ;} + break; + + case 176: + +/* Line 1455 of yacc.c */ +#line 1109 "glsl_parser.ypp" + { (yyval.n) = ast_ivec2; ;} + break; + + case 177: + +/* Line 1455 of yacc.c */ +#line 1110 "glsl_parser.ypp" + { (yyval.n) = ast_ivec3; ;} + break; + + case 178: + +/* Line 1455 of yacc.c */ +#line 1111 "glsl_parser.ypp" + { (yyval.n) = ast_ivec4; ;} + break; + + case 179: + +/* Line 1455 of yacc.c */ +#line 1112 "glsl_parser.ypp" + { (yyval.n) = ast_uvec2; ;} + break; + + case 180: + +/* Line 1455 of yacc.c */ +#line 1113 "glsl_parser.ypp" + { (yyval.n) = ast_uvec3; ;} + break; + + case 181: + +/* Line 1455 of yacc.c */ +#line 1114 "glsl_parser.ypp" + { (yyval.n) = ast_uvec4; ;} + break; + + case 182: + +/* Line 1455 of yacc.c */ +#line 1115 "glsl_parser.ypp" + { (yyval.n) = ast_mat2; ;} + break; + + case 183: + +/* Line 1455 of yacc.c */ +#line 1116 "glsl_parser.ypp" + { (yyval.n) = ast_mat2x3; ;} + break; + + case 184: + +/* Line 1455 of yacc.c */ +#line 1117 "glsl_parser.ypp" + { (yyval.n) = ast_mat2x4; ;} + break; + + case 185: + +/* Line 1455 of yacc.c */ +#line 1118 "glsl_parser.ypp" + { (yyval.n) = ast_mat3x2; ;} + break; + + case 186: + +/* Line 1455 of yacc.c */ +#line 1119 "glsl_parser.ypp" + { (yyval.n) = ast_mat3; ;} + break; + + case 187: + +/* Line 1455 of yacc.c */ +#line 1120 "glsl_parser.ypp" + { (yyval.n) = ast_mat3x4; ;} + break; + + case 188: + +/* Line 1455 of yacc.c */ +#line 1121 "glsl_parser.ypp" + { (yyval.n) = ast_mat4x2; ;} + break; + + case 189: + +/* Line 1455 of yacc.c */ +#line 1122 "glsl_parser.ypp" + { (yyval.n) = ast_mat4x3; ;} + break; + + case 190: + +/* Line 1455 of yacc.c */ +#line 1123 "glsl_parser.ypp" + { (yyval.n) = ast_mat4; ;} + break; + + case 191: + +/* Line 1455 of yacc.c */ +#line 1124 "glsl_parser.ypp" + { (yyval.n) = ast_sampler1d; ;} + break; + + case 192: + +/* Line 1455 of yacc.c */ +#line 1125 "glsl_parser.ypp" + { (yyval.n) = ast_sampler2d; ;} + break; + + case 193: + +/* Line 1455 of yacc.c */ +#line 1126 "glsl_parser.ypp" + { (yyval.n) = ast_sampler2drect; ;} + break; + + case 194: + +/* Line 1455 of yacc.c */ +#line 1127 "glsl_parser.ypp" + { (yyval.n) = ast_sampler3d; ;} + break; + + case 195: + +/* Line 1455 of yacc.c */ +#line 1128 "glsl_parser.ypp" + { (yyval.n) = ast_samplercube; ;} + break; + + case 196: + +/* Line 1455 of yacc.c */ +#line 1129 "glsl_parser.ypp" + { (yyval.n) = ast_sampler1dshadow; ;} + break; + + case 197: + +/* Line 1455 of yacc.c */ +#line 1130 "glsl_parser.ypp" + { (yyval.n) = ast_sampler2dshadow; ;} + break; + + case 198: + +/* Line 1455 of yacc.c */ +#line 1131 "glsl_parser.ypp" + { (yyval.n) = ast_sampler2drectshadow; ;} + break; + + case 199: + +/* Line 1455 of yacc.c */ +#line 1132 "glsl_parser.ypp" + { (yyval.n) = ast_samplercubeshadow; ;} + break; + + case 200: + +/* Line 1455 of yacc.c */ +#line 1133 "glsl_parser.ypp" + { (yyval.n) = ast_sampler1darray; ;} + break; + + case 201: + +/* Line 1455 of yacc.c */ +#line 1134 "glsl_parser.ypp" + { (yyval.n) = ast_sampler2darray; ;} + break; + + case 202: + +/* Line 1455 of yacc.c */ +#line 1135 "glsl_parser.ypp" + { (yyval.n) = ast_sampler1darrayshadow; ;} + break; + + case 203: + +/* Line 1455 of yacc.c */ +#line 1136 "glsl_parser.ypp" + { (yyval.n) = ast_sampler2darrayshadow; ;} + break; + + case 204: + +/* Line 1455 of yacc.c */ +#line 1137 "glsl_parser.ypp" + { (yyval.n) = ast_isampler1d; ;} + break; + + case 205: + +/* Line 1455 of yacc.c */ +#line 1138 "glsl_parser.ypp" + { (yyval.n) = ast_isampler2d; ;} + break; + + case 206: + +/* Line 1455 of yacc.c */ +#line 1139 "glsl_parser.ypp" + { (yyval.n) = ast_isampler3d; ;} + break; + + case 207: + +/* Line 1455 of yacc.c */ +#line 1140 "glsl_parser.ypp" + { (yyval.n) = ast_isamplercube; ;} + break; + + case 208: + +/* Line 1455 of yacc.c */ +#line 1141 "glsl_parser.ypp" + { (yyval.n) = ast_isampler1darray; ;} + break; + + case 209: + +/* Line 1455 of yacc.c */ +#line 1142 "glsl_parser.ypp" + { (yyval.n) = ast_isampler2darray; ;} + break; + + case 210: + +/* Line 1455 of yacc.c */ +#line 1143 "glsl_parser.ypp" + { (yyval.n) = ast_usampler1d; ;} + break; + + case 211: + +/* Line 1455 of yacc.c */ +#line 1144 "glsl_parser.ypp" + { (yyval.n) = ast_usampler2d; ;} + break; + + case 212: + +/* Line 1455 of yacc.c */ +#line 1145 "glsl_parser.ypp" + { (yyval.n) = ast_usampler3d; ;} + break; + + case 213: + +/* Line 1455 of yacc.c */ +#line 1146 "glsl_parser.ypp" + { (yyval.n) = ast_usamplercube; ;} + break; + + case 214: + +/* Line 1455 of yacc.c */ +#line 1147 "glsl_parser.ypp" + { (yyval.n) = ast_usampler1darray; ;} + break; + + case 215: + +/* Line 1455 of yacc.c */ +#line 1148 "glsl_parser.ypp" + { (yyval.n) = ast_usampler2darray; ;} + break; + + case 216: + +/* Line 1455 of yacc.c */ +#line 1152 "glsl_parser.ypp" + { + if (state->language_version < 130) + _mesa_glsl_error(& (yylsp[(1) - (1)]), state, + "precision qualifier forbidden " + "in GLSL %d.%d (1.30 or later " + "required)\n", + state->language_version / 100, + state->language_version % 100); + + (yyval.n) = ast_precision_high; + ;} + break; + + case 217: + +/* Line 1455 of yacc.c */ +#line 1163 "glsl_parser.ypp" + { + if (state->language_version < 130) + _mesa_glsl_error(& (yylsp[(1) - (1)]), state, + "precision qualifier forbidden " + "in GLSL %d.%d (1.30 or later " + "required)\n", + state->language_version / 100, + state->language_version % 100); + + (yyval.n) = ast_precision_medium; + ;} + break; + + case 218: + +/* Line 1455 of yacc.c */ +#line 1174 "glsl_parser.ypp" + { + if (state->language_version < 130) + _mesa_glsl_error(& (yylsp[(1) - (1)]), state, + "precision qualifier forbidden " + "in GLSL %d.%d (1.30 or later " + "required)\n", + state->language_version / 100, + state->language_version % 100); + + (yyval.n) = ast_precision_low; + ;} + break; + + case 219: + +/* Line 1455 of yacc.c */ +#line 1189 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.struct_specifier) = new(ctx) ast_struct_specifier((yyvsp[(2) - (5)].identifier), (yyvsp[(4) - (5)].node)); + (yyval.struct_specifier)->set_location(yylloc); + ;} + break; + + case 220: + +/* Line 1455 of yacc.c */ +#line 1195 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.struct_specifier) = new(ctx) ast_struct_specifier(NULL, (yyvsp[(3) - (4)].node)); + (yyval.struct_specifier)->set_location(yylloc); + ;} + break; + + case 221: + +/* Line 1455 of yacc.c */ +#line 1204 "glsl_parser.ypp" + { + (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].declarator_list); + (yyvsp[(1) - (1)].declarator_list)->link.self_link(); + ;} + break; + + case 222: + +/* Line 1455 of yacc.c */ +#line 1209 "glsl_parser.ypp" + { + (yyval.node) = (ast_node *) (yyvsp[(1) - (2)].node); + (yyval.node)->link.insert_before(& (yyvsp[(2) - (2)].declarator_list)->link); + ;} + break; + + case 223: + +/* Line 1455 of yacc.c */ +#line 1217 "glsl_parser.ypp" + { + void *ctx = state; + ast_fully_specified_type *type = new(ctx) ast_fully_specified_type(); + type->set_location(yylloc); + + type->specifier = (yyvsp[(1) - (3)].type_specifier); + (yyval.declarator_list) = new(ctx) ast_declarator_list(type); + (yyval.declarator_list)->set_location(yylloc); + + (yyval.declarator_list)->declarations.push_degenerate_list_at_head(& (yyvsp[(2) - (3)].declaration)->link); + ;} + break; + + case 224: + +/* Line 1455 of yacc.c */ +#line 1232 "glsl_parser.ypp" + { + (yyval.declaration) = (yyvsp[(1) - (1)].declaration); + (yyvsp[(1) - (1)].declaration)->link.self_link(); + ;} + break; + + case 225: + +/* Line 1455 of yacc.c */ +#line 1237 "glsl_parser.ypp" + { + (yyval.declaration) = (yyvsp[(1) - (3)].declaration); + (yyval.declaration)->link.insert_before(& (yyvsp[(3) - (3)].declaration)->link); + ;} + break; + + case 226: + +/* Line 1455 of yacc.c */ +#line 1245 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.declaration) = new(ctx) ast_declaration((yyvsp[(1) - (1)].identifier), false, NULL, NULL); + (yyval.declaration)->set_location(yylloc); + ;} + break; + + case 227: + +/* Line 1455 of yacc.c */ +#line 1251 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.declaration) = new(ctx) ast_declaration((yyvsp[(1) - (4)].identifier), true, (yyvsp[(3) - (4)].expression), NULL); + (yyval.declaration)->set_location(yylloc); + ;} + break; + + case 232: + +/* Line 1455 of yacc.c */ +#line 1274 "glsl_parser.ypp" + { (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].compound_statement); ;} + break; + + case 238: + +/* Line 1455 of yacc.c */ +#line 1286 "glsl_parser.ypp" + { (yyval.node) = NULL; ;} + break; + + case 239: + +/* Line 1455 of yacc.c */ +#line 1287 "glsl_parser.ypp" + { (yyval.node) = NULL; ;} + break; + + case 242: + +/* Line 1455 of yacc.c */ +#line 1294 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.compound_statement) = new(ctx) ast_compound_statement(true, NULL); + (yyval.compound_statement)->set_location(yylloc); + ;} + break; + + case 243: + +/* Line 1455 of yacc.c */ +#line 1300 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.compound_statement) = new(ctx) ast_compound_statement(true, (yyvsp[(2) - (3)].node)); + (yyval.compound_statement)->set_location(yylloc); + ;} + break; + + case 244: + +/* Line 1455 of yacc.c */ +#line 1308 "glsl_parser.ypp" + { (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].compound_statement); ;} + break; + + case 246: + +/* Line 1455 of yacc.c */ +#line 1314 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.compound_statement) = new(ctx) ast_compound_statement(false, NULL); + (yyval.compound_statement)->set_location(yylloc); + ;} + break; + + case 247: + +/* Line 1455 of yacc.c */ +#line 1320 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.compound_statement) = new(ctx) ast_compound_statement(false, (yyvsp[(2) - (3)].node)); + (yyval.compound_statement)->set_location(yylloc); + ;} + break; + + case 248: + +/* Line 1455 of yacc.c */ +#line 1329 "glsl_parser.ypp" + { + if ((yyvsp[(1) - (1)].node) == NULL) { + _mesa_glsl_error(& (yylsp[(1) - (1)]), state, "<nil> statement\n"); + assert((yyvsp[(1) - (1)].node) != NULL); + } + + (yyval.node) = (yyvsp[(1) - (1)].node); + (yyval.node)->link.self_link(); + ;} + break; + + case 249: + +/* Line 1455 of yacc.c */ +#line 1339 "glsl_parser.ypp" + { + if ((yyvsp[(2) - (2)].node) == NULL) { + _mesa_glsl_error(& (yylsp[(2) - (2)]), state, "<nil> statement\n"); + assert((yyvsp[(2) - (2)].node) != NULL); + } + (yyval.node) = (yyvsp[(1) - (2)].node); + (yyval.node)->link.insert_before(& (yyvsp[(2) - (2)].node)->link); + ;} + break; + + case 250: + +/* Line 1455 of yacc.c */ +#line 1351 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_expression_statement(NULL); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 251: + +/* Line 1455 of yacc.c */ +#line 1357 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_expression_statement((yyvsp[(1) - (2)].expression)); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 252: + +/* Line 1455 of yacc.c */ +#line 1366 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_selection_statement((yyvsp[(3) - (7)].expression), (yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 253: + +/* Line 1455 of yacc.c */ +#line 1375 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_selection_statement((yyvsp[(3) - (5)].expression), (yyvsp[(5) - (5)].node), NULL); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 254: + +/* Line 1455 of yacc.c */ +#line 1381 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_selection_statement((yyvsp[(3) - (5)].expression), (yyvsp[(5) - (5)].node), NULL); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 255: + +/* Line 1455 of yacc.c */ +#line 1387 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_selection_statement((yyvsp[(3) - (7)].expression), (yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 256: + +/* Line 1455 of yacc.c */ +#line 1396 "glsl_parser.ypp" + { + (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].expression); + ;} + break; + + case 257: + +/* Line 1455 of yacc.c */ +#line 1400 "glsl_parser.ypp" + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (4)].identifier), false, NULL, (yyvsp[(4) - (4)].expression)); + ast_declarator_list *declarator = new(ctx) ast_declarator_list((yyvsp[(1) - (4)].fully_specified_type)); + decl->set_location(yylloc); + declarator->set_location(yylloc); + + declarator->declarations.push_tail(&decl->link); + (yyval.node) = declarator; + ;} + break; + + case 261: + +/* Line 1455 of yacc.c */ +#line 1423 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_while, + NULL, (yyvsp[(3) - (5)].node), NULL, (yyvsp[(5) - (5)].node)); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 262: + +/* Line 1455 of yacc.c */ +#line 1430 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_do_while, + NULL, (yyvsp[(5) - (7)].expression), NULL, (yyvsp[(2) - (7)].node)); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 263: + +/* Line 1455 of yacc.c */ +#line 1437 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_for, + (yyvsp[(3) - (6)].node), (yyvsp[(4) - (6)].for_rest_statement).cond, (yyvsp[(4) - (6)].for_rest_statement).rest, (yyvsp[(6) - (6)].node)); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 267: + +/* Line 1455 of yacc.c */ +#line 1453 "glsl_parser.ypp" + { + (yyval.node) = NULL; + ;} + break; + + case 268: + +/* Line 1455 of yacc.c */ +#line 1460 "glsl_parser.ypp" + { + (yyval.for_rest_statement).cond = (yyvsp[(1) - (2)].node); + (yyval.for_rest_statement).rest = NULL; + ;} + break; + + case 269: + +/* Line 1455 of yacc.c */ +#line 1465 "glsl_parser.ypp" + { + (yyval.for_rest_statement).cond = (yyvsp[(1) - (3)].node); + (yyval.for_rest_statement).rest = (yyvsp[(3) - (3)].expression); + ;} + break; + + case 270: + +/* Line 1455 of yacc.c */ +#line 1474 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_continue, NULL); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 271: + +/* Line 1455 of yacc.c */ +#line 1480 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_break, NULL); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 272: + +/* Line 1455 of yacc.c */ +#line 1486 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, NULL); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 273: + +/* Line 1455 of yacc.c */ +#line 1492 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, (yyvsp[(2) - (3)].expression)); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 274: + +/* Line 1455 of yacc.c */ +#line 1498 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_discard, NULL); + (yyval.node)->set_location(yylloc); + ;} + break; + + case 275: + +/* Line 1455 of yacc.c */ +#line 1506 "glsl_parser.ypp" + { (yyval.node) = (yyvsp[(1) - (1)].function_definition); ;} + break; + + case 276: + +/* Line 1455 of yacc.c */ +#line 1507 "glsl_parser.ypp" + { (yyval.node) = (yyvsp[(1) - (1)].node); ;} + break; + + case 277: + +/* Line 1455 of yacc.c */ +#line 1508 "glsl_parser.ypp" + { (yyval.node) = NULL; ;} + break; + + case 278: + +/* Line 1455 of yacc.c */ +#line 1513 "glsl_parser.ypp" + { + void *ctx = state; + (yyval.function_definition) = new(ctx) ast_function_definition(); + (yyval.function_definition)->set_location(yylloc); + (yyval.function_definition)->prototype = (yyvsp[(1) - (2)].function); + (yyval.function_definition)->body = (yyvsp[(2) - (2)].compound_statement); + ;} + break; + + + +/* Line 1455 of yacc.c */ +#line 5052 "glsl_parser.cpp" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, state, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (&yylloc, state, yymsg); + } + else + { + yyerror (&yylloc, state, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + yyerror_range[0] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, state); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[0] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[0] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, state); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + yyerror_range[1] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the lookahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, state, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, state); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, state); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + diff --git a/src/glsl/glsl_parser.h b/src/glsl/glsl_parser.h new file mode 100644 index 0000000000..3ed90853ad --- /dev/null +++ b/src/glsl/glsl_parser.h @@ -0,0 +1,294 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ATTRIBUTE = 258, + CONST_TOK = 259, + BOOL_TOK = 260, + FLOAT_TOK = 261, + INT_TOK = 262, + UINT_TOK = 263, + BREAK = 264, + CONTINUE = 265, + DO = 266, + ELSE = 267, + FOR = 268, + IF = 269, + DISCARD = 270, + RETURN = 271, + SWITCH = 272, + CASE = 273, + DEFAULT = 274, + BVEC2 = 275, + BVEC3 = 276, + BVEC4 = 277, + IVEC2 = 278, + IVEC3 = 279, + IVEC4 = 280, + UVEC2 = 281, + UVEC3 = 282, + UVEC4 = 283, + VEC2 = 284, + VEC3 = 285, + VEC4 = 286, + CENTROID = 287, + IN_TOK = 288, + OUT_TOK = 289, + INOUT_TOK = 290, + UNIFORM = 291, + VARYING = 292, + NOPERSPECTIVE = 293, + FLAT = 294, + SMOOTH = 295, + MAT2X2 = 296, + MAT2X3 = 297, + MAT2X4 = 298, + MAT3X2 = 299, + MAT3X3 = 300, + MAT3X4 = 301, + MAT4X2 = 302, + MAT4X3 = 303, + MAT4X4 = 304, + SAMPLER1D = 305, + SAMPLER2D = 306, + SAMPLER3D = 307, + SAMPLERCUBE = 308, + SAMPLER1DSHADOW = 309, + SAMPLER2DSHADOW = 310, + SAMPLERCUBESHADOW = 311, + SAMPLER1DARRAY = 312, + SAMPLER2DARRAY = 313, + SAMPLER1DARRAYSHADOW = 314, + SAMPLER2DARRAYSHADOW = 315, + ISAMPLER1D = 316, + ISAMPLER2D = 317, + ISAMPLER3D = 318, + ISAMPLERCUBE = 319, + ISAMPLER1DARRAY = 320, + ISAMPLER2DARRAY = 321, + USAMPLER1D = 322, + USAMPLER2D = 323, + USAMPLER3D = 324, + USAMPLERCUBE = 325, + USAMPLER1DARRAY = 326, + USAMPLER2DARRAY = 327, + STRUCT = 328, + VOID_TOK = 329, + WHILE = 330, + IDENTIFIER = 331, + FLOATCONSTANT = 332, + INTCONSTANT = 333, + UINTCONSTANT = 334, + BOOLCONSTANT = 335, + FIELD_SELECTION = 336, + LEFT_OP = 337, + RIGHT_OP = 338, + INC_OP = 339, + DEC_OP = 340, + LE_OP = 341, + GE_OP = 342, + EQ_OP = 343, + NE_OP = 344, + AND_OP = 345, + OR_OP = 346, + XOR_OP = 347, + MUL_ASSIGN = 348, + DIV_ASSIGN = 349, + ADD_ASSIGN = 350, + MOD_ASSIGN = 351, + LEFT_ASSIGN = 352, + RIGHT_ASSIGN = 353, + AND_ASSIGN = 354, + XOR_ASSIGN = 355, + OR_ASSIGN = 356, + SUB_ASSIGN = 357, + INVARIANT = 358, + LOWP = 359, + MEDIUMP = 360, + HIGHP = 361, + SUPERP = 362, + PRECISION = 363, + VERSION = 364, + EXTENSION = 365, + LINE = 366, + COLON = 367, + EOL = 368, + INTERFACE = 369, + OUTPUT = 370, + PRAGMA_DEBUG_ON = 371, + PRAGMA_DEBUG_OFF = 372, + PRAGMA_OPTIMIZE_ON = 373, + PRAGMA_OPTIMIZE_OFF = 374, + LAYOUT_TOK = 375, + ASM = 376, + CLASS = 377, + UNION = 378, + ENUM = 379, + TYPEDEF = 380, + TEMPLATE = 381, + THIS = 382, + PACKED_TOK = 383, + GOTO = 384, + INLINE_TOK = 385, + NOINLINE = 386, + VOLATILE = 387, + PUBLIC_TOK = 388, + STATIC = 389, + EXTERN = 390, + EXTERNAL = 391, + LONG_TOK = 392, + SHORT_TOK = 393, + DOUBLE_TOK = 394, + HALF = 395, + FIXED_TOK = 396, + UNSIGNED = 397, + INPUT_TOK = 398, + OUPTUT = 399, + HVEC2 = 400, + HVEC3 = 401, + HVEC4 = 402, + DVEC2 = 403, + DVEC3 = 404, + DVEC4 = 405, + FVEC2 = 406, + FVEC3 = 407, + FVEC4 = 408, + SAMPLER2DRECT = 409, + SAMPLER3DRECT = 410, + SAMPLER2DRECTSHADOW = 411, + SIZEOF = 412, + CAST = 413, + NAMESPACE = 414, + USING = 415, + ERROR_TOK = 416, + COMMON = 417, + PARTITION = 418, + ACTIVE = 419, + SAMPLERBUFFER = 420, + FILTER = 421, + IMAGE1D = 422, + IMAGE2D = 423, + IMAGE3D = 424, + IMAGECUBE = 425, + IMAGE1DARRAY = 426, + IMAGE2DARRAY = 427, + IIMAGE1D = 428, + IIMAGE2D = 429, + IIMAGE3D = 430, + IIMAGECUBE = 431, + IIMAGE1DARRAY = 432, + IIMAGE2DARRAY = 433, + UIMAGE1D = 434, + UIMAGE2D = 435, + UIMAGE3D = 436, + UIMAGECUBE = 437, + UIMAGE1DARRAY = 438, + UIMAGE2DARRAY = 439, + IMAGE1DSHADOW = 440, + IMAGE2DSHADOW = 441, + IMAGEBUFFER = 442, + IIMAGEBUFFER = 443, + UIMAGEBUFFER = 444, + ROW_MAJOR = 445 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 1676 of yacc.c */ +#line 52 "glsl_parser.ypp" + + int n; + float real; + char *identifier; + + union { + struct ast_type_qualifier q; + unsigned i; + } type_qualifier; + + ast_node *node; + ast_type_specifier *type_specifier; + ast_fully_specified_type *fully_specified_type; + ast_function *function; + ast_parameter_declarator *parameter_declarator; + ast_function_definition *function_definition; + ast_compound_statement *compound_statement; + ast_expression *expression; + ast_declarator_list *declarator_list; + ast_struct_specifier *struct_specifier; + ast_declaration *declaration; + + struct { + ast_node *cond; + ast_expression *rest; + } for_rest_statement; + + + +/* Line 1676 of yacc.c */ +#line 272 "glsl_parser.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + diff --git a/src/glsl/glsl_parser.ypp b/src/glsl/glsl_parser.ypp new file mode 100644 index 0000000000..6d99c52503 --- /dev/null +++ b/src/glsl/glsl_parser.ypp @@ -0,0 +1,1520 @@ +%{ +/* + * Copyright © 2008, 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "ast.h" +#include "glsl_parser_extras.h" +#include "glsl_types.h" + +#define YYLEX_PARAM state->scanner + +%} + +%pure-parser +%error-verbose + +%locations +%initial-action { + @$.first_line = 1; + @$.first_column = 1; + @$.last_line = 1; + @$.last_column = 1; + @$.source = 0; +} + +%lex-param {void *scanner} +%parse-param {struct _mesa_glsl_parse_state *state} + +%union { + int n; + float real; + char *identifier; + + union { + struct ast_type_qualifier q; + unsigned i; + } type_qualifier; + + ast_node *node; + ast_type_specifier *type_specifier; + ast_fully_specified_type *fully_specified_type; + ast_function *function; + ast_parameter_declarator *parameter_declarator; + ast_function_definition *function_definition; + ast_compound_statement *compound_statement; + ast_expression *expression; + ast_declarator_list *declarator_list; + ast_struct_specifier *struct_specifier; + ast_declaration *declaration; + + struct { + ast_node *cond; + ast_expression *rest; + } for_rest_statement; +} + +%token ATTRIBUTE CONST_TOK BOOL_TOK FLOAT_TOK INT_TOK UINT_TOK +%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT +%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4 +%token CENTROID IN_TOK OUT_TOK INOUT_TOK UNIFORM VARYING +%token NOPERSPECTIVE FLAT SMOOTH +%token MAT2X2 MAT2X3 MAT2X4 +%token MAT3X2 MAT3X3 MAT3X4 +%token MAT4X2 MAT4X3 MAT4X4 +%token SAMPLER1D SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER1DSHADOW SAMPLER2DSHADOW +%token SAMPLERCUBESHADOW SAMPLER1DARRAY SAMPLER2DARRAY SAMPLER1DARRAYSHADOW +%token SAMPLER2DARRAYSHADOW ISAMPLER1D ISAMPLER2D ISAMPLER3D ISAMPLERCUBE +%token ISAMPLER1DARRAY ISAMPLER2DARRAY USAMPLER1D USAMPLER2D USAMPLER3D +%token USAMPLERCUBE USAMPLER1DARRAY USAMPLER2DARRAY +%token STRUCT VOID_TOK WHILE +%token <identifier> IDENTIFIER +%token <real> FLOATCONSTANT +%token <n> INTCONSTANT UINTCONSTANT BOOLCONSTANT +%token <identifier> FIELD_SELECTION +%token LEFT_OP RIGHT_OP +%token INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN +%token MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN +%token SUB_ASSIGN +%token INVARIANT +%token LOWP MEDIUMP HIGHP SUPERP PRECISION + +%token VERSION EXTENSION LINE COLON EOL INTERFACE OUTPUT +%token PRAGMA_DEBUG_ON PRAGMA_DEBUG_OFF +%token PRAGMA_OPTIMIZE_ON PRAGMA_OPTIMIZE_OFF +%token LAYOUT_TOK + + /* Reserved words that are not actually used in the grammar. + */ +%token ASM CLASS UNION ENUM TYPEDEF TEMPLATE THIS PACKED_TOK GOTO +%token INLINE_TOK NOINLINE VOLATILE PUBLIC_TOK STATIC EXTERN EXTERNAL +%token LONG_TOK SHORT_TOK DOUBLE_TOK HALF FIXED_TOK UNSIGNED INPUT_TOK OUPTUT +%token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4 +%token SAMPLER2DRECT SAMPLER3DRECT SAMPLER2DRECTSHADOW +%token SIZEOF CAST NAMESPACE USING + +%token ERROR_TOK + +%token COMMON PARTITION ACTIVE SAMPLERBUFFER FILTER +%token IMAGE1D IMAGE2D IMAGE3D IMAGECUBE IMAGE1DARRAY IMAGE2DARRAY +%token IIMAGE1D IIMAGE2D IIMAGE3D IIMAGECUBE IIMAGE1DARRAY IIMAGE2DARRAY +%token UIMAGE1D UIMAGE2D UIMAGE3D UIMAGECUBE UIMAGE1DARRAY UIMAGE2DARRAY +%token IMAGE1DSHADOW IMAGE2DSHADOW IMAGEBUFFER IIMAGEBUFFER UIMAGEBUFFER +%token ROW_MAJOR + +%type <identifier> variable_identifier +%type <node> statement +%type <node> statement_list +%type <node> simple_statement +%type <node> statement_matched +%type <node> statement_unmatched +%type <n> precision_qualifier +%type <type_qualifier> type_qualifier +%type <type_qualifier> storage_qualifier +%type <type_qualifier> interpolation_qualifier +%type <type_qualifier> opt_layout_qualifier layout_qualifier +%type <type_qualifier> layout_qualifier_id_list layout_qualifier_id +%type <type_specifier> type_specifier +%type <type_specifier> type_specifier_no_prec +%type <type_specifier> type_specifier_nonarray +%type <n> basic_type_specifier_nonarray +%type <fully_specified_type> fully_specified_type +%type <function> function_prototype +%type <function> function_header +%type <function> function_header_with_parameters +%type <function> function_declarator +%type <parameter_declarator> parameter_declarator +%type <parameter_declarator> parameter_declaration +%type <type_qualifier> parameter_qualifier +%type <type_qualifier> parameter_type_qualifier +%type <type_specifier> parameter_type_specifier +%type <function_definition> function_definition +%type <compound_statement> compound_statement_no_new_scope +%type <compound_statement> compound_statement +%type <node> statement_no_new_scope +%type <node> expression_statement +%type <expression> expression +%type <expression> primary_expression +%type <expression> assignment_expression +%type <expression> conditional_expression +%type <expression> logical_or_expression +%type <expression> logical_xor_expression +%type <expression> logical_and_expression +%type <expression> inclusive_or_expression +%type <expression> exclusive_or_expression +%type <expression> and_expression +%type <expression> equality_expression +%type <expression> relational_expression +%type <expression> shift_expression +%type <expression> additive_expression +%type <expression> multiplicative_expression +%type <expression> unary_expression +%type <expression> constant_expression +%type <expression> integer_expression +%type <expression> postfix_expression +%type <expression> function_call_header_with_parameters +%type <expression> function_call_header_no_parameters +%type <expression> function_call_header +%type <expression> function_call_generic +%type <expression> function_call_or_method +%type <expression> function_call +%type <n> assignment_operator +%type <n> unary_operator +%type <expression> function_identifier +%type <node> external_declaration +%type <declarator_list> init_declarator_list +%type <declarator_list> single_declaration +%type <expression> initializer +%type <node> declaration +%type <node> declaration_statement +%type <node> jump_statement +%type <struct_specifier> struct_specifier +%type <node> struct_declaration_list +%type <declarator_list> struct_declaration +%type <declaration> struct_declarator +%type <declaration> struct_declarator_list +%type <node> selection_statement_matched +%type <node> selection_statement_unmatched +%type <node> iteration_statement +%type <node> condition +%type <node> conditionopt +%type <node> for_init_statement +%type <for_rest_statement> for_rest_statement +%% + +translation_unit: + version_statement extension_statement_list + { + _mesa_glsl_initialize_types(state); + } + external_declaration_list + ; + +version_statement: + /* blank - no #version specified */ + { + state->language_version = 110; + state->symbols->language_version = 110; + } + | VERSION INTCONSTANT EOL + { + switch ($2) { + case 110: + case 120: + case 130: + /* FINISHME: Check against implementation support versions. */ + state->language_version = $2; + state->symbols->language_version = $2; + break; + default: + _mesa_glsl_error(& @2, state, "Shading language version" + "%u is not supported\n", $2); + break; + } + } + ; + +pragma_statement: + PRAGMA_DEBUG_ON EOL + | PRAGMA_DEBUG_OFF EOL + | PRAGMA_OPTIMIZE_ON EOL + | PRAGMA_OPTIMIZE_OFF EOL + ; + +extension_statement_list: + + | extension_statement_list extension_statement + ; + +extension_statement: + EXTENSION IDENTIFIER COLON IDENTIFIER EOL + { + if (!_mesa_glsl_process_extension($2, & @2, $4, & @4, state)) { + YYERROR; + } + } + ; + +external_declaration_list: + external_declaration + { + /* FINISHME: The NULL test is only required because 'precision' + * FINISHME: statements are not yet supported. + */ + if ($1 != NULL) + state->translation_unit.push_tail(& $1->link); + } + | external_declaration_list external_declaration + { + /* FINISHME: The NULL test is only required because 'precision' + * FINISHME: statements are not yet supported. + */ + if ($2 != NULL) + state->translation_unit.push_tail(& $2->link); + } + ; + +variable_identifier: + IDENTIFIER + ; + +primary_expression: + variable_identifier + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_identifier, NULL, NULL, NULL); + $$->set_location(yylloc); + $$->primary_expression.identifier = $1; + } + | INTCONSTANT + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_int_constant, NULL, NULL, NULL); + $$->set_location(yylloc); + $$->primary_expression.int_constant = $1; + } + | UINTCONSTANT + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_uint_constant, NULL, NULL, NULL); + $$->set_location(yylloc); + $$->primary_expression.uint_constant = $1; + } + | FLOATCONSTANT + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_float_constant, NULL, NULL, NULL); + $$->set_location(yylloc); + $$->primary_expression.float_constant = $1; + } + | BOOLCONSTANT + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_bool_constant, NULL, NULL, NULL); + $$->set_location(yylloc); + $$->primary_expression.bool_constant = $1; + } + | '(' expression ')' + { + $$ = $2; + } + ; + +postfix_expression: + primary_expression + | postfix_expression '[' integer_expression ']' + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_array_index, $1, $3, NULL); + $$->set_location(yylloc); + } + | function_call + { + $$ = $1; + } + | postfix_expression '.' IDENTIFIER + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_field_selection, $1, NULL, NULL); + $$->set_location(yylloc); + $$->primary_expression.identifier = $3; + } + | postfix_expression INC_OP + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_post_inc, $1, NULL, NULL); + $$->set_location(yylloc); + } + | postfix_expression DEC_OP + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_post_dec, $1, NULL, NULL); + $$->set_location(yylloc); + } + ; + +integer_expression: + expression + ; + +function_call: + function_call_or_method + ; + +function_call_or_method: + function_call_generic + | postfix_expression '.' function_call_generic + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_field_selection, $1, $3, NULL); + $$->set_location(yylloc); + } + ; + +function_call_generic: + function_call_header_with_parameters ')' + | function_call_header_no_parameters ')' + ; + +function_call_header_no_parameters: + function_call_header VOID_TOK + | function_call_header + ; + +function_call_header_with_parameters: + function_call_header assignment_expression + { + $$ = $1; + $$->set_location(yylloc); + $$->expressions.push_tail(& $2->link); + } + | function_call_header_with_parameters ',' assignment_expression + { + $$ = $1; + $$->set_location(yylloc); + $$->expressions.push_tail(& $3->link); + } + ; + + // Grammar Note: Constructors look like functions, but lexical + // analysis recognized most of them as keywords. They are now + // recognized through "type_specifier". +function_call_header: + function_identifier '(' + ; + +function_identifier: + type_specifier + { + void *ctx = state; + $$ = new(ctx) ast_function_expression($1); + $$->set_location(yylloc); + } + | IDENTIFIER + { + void *ctx = state; + ast_expression *callee = new(ctx) ast_expression($1); + $$ = new(ctx) ast_function_expression(callee); + $$->set_location(yylloc); + } + | FIELD_SELECTION + { + void *ctx = state; + ast_expression *callee = new(ctx) ast_expression($1); + $$ = new(ctx) ast_function_expression(callee); + $$->set_location(yylloc); + } + ; + + // Grammar Note: No traditional style type casts. +unary_expression: + postfix_expression + | INC_OP unary_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_pre_inc, $2, NULL, NULL); + $$->set_location(yylloc); + } + | DEC_OP unary_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_pre_dec, $2, NULL, NULL); + $$->set_location(yylloc); + } + | unary_operator unary_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression($1, $2, NULL, NULL); + $$->set_location(yylloc); + } + ; + + // Grammar Note: No '*' or '&' unary ops. Pointers are not supported. +unary_operator: + '+' { $$ = ast_plus; } + | '-' { $$ = ast_neg; } + | '!' { $$ = ast_logic_not; } + | '~' { $$ = ast_bit_not; } + ; + +multiplicative_expression: + unary_expression + | multiplicative_expression '*' unary_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_mul, $1, $3); + $$->set_location(yylloc); + } + | multiplicative_expression '/' unary_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_div, $1, $3); + $$->set_location(yylloc); + } + | multiplicative_expression '%' unary_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_mod, $1, $3); + $$->set_location(yylloc); + } + ; + +additive_expression: + multiplicative_expression + | additive_expression '+' multiplicative_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_add, $1, $3); + $$->set_location(yylloc); + } + | additive_expression '-' multiplicative_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_sub, $1, $3); + $$->set_location(yylloc); + } + ; + +shift_expression: + additive_expression + | shift_expression LEFT_OP additive_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_lshift, $1, $3); + $$->set_location(yylloc); + } + | shift_expression RIGHT_OP additive_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_rshift, $1, $3); + $$->set_location(yylloc); + } + ; + +relational_expression: + shift_expression + | relational_expression '<' shift_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_less, $1, $3); + $$->set_location(yylloc); + } + | relational_expression '>' shift_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_greater, $1, $3); + $$->set_location(yylloc); + } + | relational_expression LE_OP shift_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_lequal, $1, $3); + $$->set_location(yylloc); + } + | relational_expression GE_OP shift_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_gequal, $1, $3); + $$->set_location(yylloc); + } + ; + +equality_expression: + relational_expression + | equality_expression EQ_OP relational_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_equal, $1, $3); + $$->set_location(yylloc); + } + | equality_expression NE_OP relational_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_nequal, $1, $3); + $$->set_location(yylloc); + } + ; + +and_expression: + equality_expression + | and_expression '&' equality_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_bit_or, $1, $3); + $$->set_location(yylloc); + } + ; + +exclusive_or_expression: + and_expression + | exclusive_or_expression '^' and_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_bit_xor, $1, $3); + $$->set_location(yylloc); + } + ; + +inclusive_or_expression: + exclusive_or_expression + | inclusive_or_expression '|' exclusive_or_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_bit_or, $1, $3); + $$->set_location(yylloc); + } + ; + +logical_and_expression: + inclusive_or_expression + | logical_and_expression AND_OP inclusive_or_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_logic_and, $1, $3); + $$->set_location(yylloc); + } + ; + +logical_xor_expression: + logical_and_expression + | logical_xor_expression XOR_OP logical_and_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_logic_xor, $1, $3); + $$->set_location(yylloc); + } + ; + +logical_or_expression: + logical_xor_expression + | logical_or_expression OR_OP logical_xor_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression_bin(ast_logic_or, $1, $3); + $$->set_location(yylloc); + } + ; + +conditional_expression: + logical_or_expression + | logical_or_expression '?' expression ':' assignment_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression(ast_conditional, $1, $3, $5); + $$->set_location(yylloc); + } + ; + +assignment_expression: + conditional_expression + | unary_expression assignment_operator assignment_expression + { + void *ctx = state; + $$ = new(ctx) ast_expression($2, $1, $3, NULL); + $$->set_location(yylloc); + } + ; + +assignment_operator: + '=' { $$ = ast_assign; } + | MUL_ASSIGN { $$ = ast_mul_assign; } + | DIV_ASSIGN { $$ = ast_div_assign; } + | MOD_ASSIGN { $$ = ast_mod_assign; } + | ADD_ASSIGN { $$ = ast_add_assign; } + | SUB_ASSIGN { $$ = ast_sub_assign; } + | LEFT_ASSIGN { $$ = ast_ls_assign; } + | RIGHT_ASSIGN { $$ = ast_rs_assign; } + | AND_ASSIGN { $$ = ast_and_assign; } + | XOR_ASSIGN { $$ = ast_xor_assign; } + | OR_ASSIGN { $$ = ast_or_assign; } + ; + +expression: + assignment_expression + { + $$ = $1; + } + | expression ',' assignment_expression + { + void *ctx = state; + if ($1->oper != ast_sequence) { + $$ = new(ctx) ast_expression(ast_sequence, NULL, NULL, NULL); + $$->set_location(yylloc); + $$->expressions.push_tail(& $1->link); + } else { + $$ = $1; + } + + $$->expressions.push_tail(& $3->link); + } + ; + +constant_expression: + conditional_expression + ; + +declaration: + function_prototype ';' + { + $$ = $1; + } + | init_declarator_list ';' + { + $$ = $1; + } + | PRECISION precision_qualifier type_specifier_no_prec ';' + { + if (($3->type_specifier != ast_float) + && ($3->type_specifier != ast_int)) { + _mesa_glsl_error(& @3, state, "global precision qualifier can " + "only be applied to `int' or `float'\n"); + YYERROR; + } + + $$ = NULL; /* FINISHME */ + } + ; + +function_prototype: + function_declarator ')' + ; + +function_declarator: + function_header + | function_header_with_parameters + ; + +function_header_with_parameters: + function_header parameter_declaration + { + $$ = $1; + $$->parameters.push_tail(& $2->link); + } + | function_header_with_parameters ',' parameter_declaration + { + $$ = $1; + $$->parameters.push_tail(& $3->link); + } + ; + +function_header: + fully_specified_type IDENTIFIER '(' + { + void *ctx = state; + $$ = new(ctx) ast_function(); + $$->set_location(yylloc); + $$->return_type = $1; + $$->identifier = $2; + } + ; + +parameter_declarator: + type_specifier IDENTIFIER + { + void *ctx = state; + $$ = new(ctx) ast_parameter_declarator(); + $$->set_location(yylloc); + $$->type = new(ctx) ast_fully_specified_type(); + $$->type->set_location(yylloc); + $$->type->specifier = $1; + $$->identifier = $2; + } + | type_specifier IDENTIFIER '[' constant_expression ']' + { + void *ctx = state; + $$ = new(ctx) ast_parameter_declarator(); + $$->set_location(yylloc); + $$->type = new(ctx) ast_fully_specified_type(); + $$->type->set_location(yylloc); + $$->type->specifier = $1; + $$->identifier = $2; + $$->is_array = true; + $$->array_size = $4; + } + ; + +parameter_declaration: + parameter_type_qualifier parameter_qualifier parameter_declarator + { + $1.i |= $2.i; + + $$ = $3; + $$->type->qualifier = $1.q; + } + | parameter_qualifier parameter_declarator + { + $$ = $2; + $$->type->qualifier = $1.q; + } + | parameter_type_qualifier parameter_qualifier parameter_type_specifier + { + void *ctx = state; + $1.i |= $2.i; + + $$ = new(ctx) ast_parameter_declarator(); + $$->set_location(yylloc); + $$->type = new(ctx) ast_fully_specified_type(); + $$->type->qualifier = $1.q; + $$->type->specifier = $3; + } + | parameter_qualifier parameter_type_specifier + { + void *ctx = state; + $$ = new(ctx) ast_parameter_declarator(); + $$->set_location(yylloc); + $$->type = new(ctx) ast_fully_specified_type(); + $$->type->qualifier = $1.q; + $$->type->specifier = $2; + } + ; + +parameter_qualifier: + /* empty */ { $$.i = 0; } + | IN_TOK { $$.i = 0; $$.q.in = 1; } + | OUT_TOK { $$.i = 0; $$.q.out = 1; } + | INOUT_TOK { $$.i = 0; $$.q.in = 1; $$.q.out = 1; } + ; + +parameter_type_specifier: + type_specifier + ; + +init_declarator_list: + single_declaration + | init_declarator_list ',' IDENTIFIER + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($3, false, NULL, NULL); + decl->set_location(yylloc); + + $$ = $1; + $$->declarations.push_tail(&decl->link); + } + | init_declarator_list ',' IDENTIFIER '[' ']' + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($3, true, NULL, NULL); + decl->set_location(yylloc); + + $$ = $1; + $$->declarations.push_tail(&decl->link); + } + | init_declarator_list ',' IDENTIFIER '[' constant_expression ']' + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($3, true, $5, NULL); + decl->set_location(yylloc); + + $$ = $1; + $$->declarations.push_tail(&decl->link); + } + | init_declarator_list ',' IDENTIFIER '[' ']' '=' initializer + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($3, true, NULL, $7); + decl->set_location(yylloc); + + $$ = $1; + $$->declarations.push_tail(&decl->link); + } + | init_declarator_list ',' IDENTIFIER '[' constant_expression ']' '=' initializer + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($3, true, $5, $8); + decl->set_location(yylloc); + + $$ = $1; + $$->declarations.push_tail(&decl->link); + } + | init_declarator_list ',' IDENTIFIER '=' initializer + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($3, false, NULL, $5); + decl->set_location(yylloc); + + $$ = $1; + $$->declarations.push_tail(&decl->link); + } + ; + + // Grammar Note: No 'enum', or 'typedef'. +single_declaration: + fully_specified_type + { + void *ctx = state; + if ($1->specifier->type_specifier != ast_struct) { + _mesa_glsl_error(& @1, state, "empty declaration list\n"); + YYERROR; + } else { + $$ = new(ctx) ast_declarator_list($1); + $$->set_location(yylloc); + } + } + | fully_specified_type IDENTIFIER + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, NULL); + + $$ = new(ctx) ast_declarator_list($1); + $$->set_location(yylloc); + $$->declarations.push_tail(&decl->link); + } + | fully_specified_type IDENTIFIER '[' ']' + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($2, true, NULL, NULL); + + $$ = new(ctx) ast_declarator_list($1); + $$->set_location(yylloc); + $$->declarations.push_tail(&decl->link); + } + | fully_specified_type IDENTIFIER '[' constant_expression ']' + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($2, true, $4, NULL); + + $$ = new(ctx) ast_declarator_list($1); + $$->set_location(yylloc); + $$->declarations.push_tail(&decl->link); + } + | fully_specified_type IDENTIFIER '[' ']' '=' initializer + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($2, true, NULL, $6); + + $$ = new(ctx) ast_declarator_list($1); + $$->set_location(yylloc); + $$->declarations.push_tail(&decl->link); + } + | fully_specified_type IDENTIFIER '[' constant_expression ']' '=' initializer + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($2, true, $4, $7); + + $$ = new(ctx) ast_declarator_list($1); + $$->set_location(yylloc); + $$->declarations.push_tail(&decl->link); + } + | fully_specified_type IDENTIFIER '=' initializer + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, $4); + + $$ = new(ctx) ast_declarator_list($1); + $$->set_location(yylloc); + $$->declarations.push_tail(&decl->link); + } + | INVARIANT IDENTIFIER // Vertex only. + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, NULL); + + $$ = new(ctx) ast_declarator_list(NULL); + $$->set_location(yylloc); + $$->invariant = true; + + $$->declarations.push_tail(&decl->link); + } + ; + +fully_specified_type: + type_specifier + { + void *ctx = state; + $$ = new(ctx) ast_fully_specified_type(); + $$->set_location(yylloc); + $$->specifier = $1; + } + | type_qualifier type_specifier + { + void *ctx = state; + $$ = new(ctx) ast_fully_specified_type(); + $$->set_location(yylloc); + $$->qualifier = $1.q; + $$->specifier = $2; + } + ; + +opt_layout_qualifier: + { $$.i = 0; } + | layout_qualifier + ; + +layout_qualifier: + LAYOUT_TOK '(' layout_qualifier_id_list ')' + { + $$ = $3; + } + ; + +layout_qualifier_id_list: + layout_qualifier_id + | layout_qualifier_id_list ',' layout_qualifier_id + { + $$.i = $1.i | $3.i; + } + ; + +layout_qualifier_id: + IDENTIFIER + { + $$.i = 0; + + if (state->ARB_fragment_coord_conventions_enable) { + bool got_one = false; + + if (strcmp($1, "origin_upper_left") == 0) { + got_one = true; + $$.q.origin_upper_left = 1; + } else if (strcmp($1, "pixel_center_integer") == 0) { + got_one = true; + $$.q.pixel_center_integer = 1; + } + + if (state->ARB_fragment_coord_conventions_warn && got_one) { + _mesa_glsl_warning(& @1, state, + "GL_ARB_fragment_coord_conventions layout " + "identifier `%s' used\n", $1); + } + } + + /* If the identifier didn't match any known layout identifiers, + * emit an error. + */ + if ($$.i == 0) { + _mesa_glsl_error(& @1, state, "unrecognized layout identifier " + "`%s'\n", $1); + YYERROR; + } + } + ; + +interpolation_qualifier: + SMOOTH { $$.i = 0; $$.q.smooth = 1; } + | FLAT { $$.i = 0; $$.q.flat = 1; } + | NOPERSPECTIVE { $$.i = 0; $$.q.noperspective = 1; } + ; + +parameter_type_qualifier: + CONST_TOK { $$.i = 0; $$.q.constant = 1; } + ; + +type_qualifier: + storage_qualifier + | interpolation_qualifier type_qualifier + { + $$.i = $1.i | $2.i; + } + | INVARIANT type_qualifier + { + $$ = $2; + $$.q.invariant = 1; + } + ; + +storage_qualifier: + CONST_TOK { $$.i = 0; $$.q.constant = 1; } + | ATTRIBUTE { $$.i = 0; $$.q.attribute = 1; } + | opt_layout_qualifier VARYING { $$.i = $1.i; $$.q.varying = 1; } + | CENTROID VARYING { $$.i = 0; $$.q.centroid = 1; $$.q.varying = 1; } + | opt_layout_qualifier IN_TOK { $$.i = 0; $$.q.in = 1; } + | OUT_TOK { $$.i = 0; $$.q.out = 1; } + | CENTROID IN_TOK { $$.i = 0; $$.q.centroid = 1; $$.q.in = 1; } + | CENTROID OUT_TOK { $$.i = 0; $$.q.centroid = 1; $$.q.out = 1; } + | UNIFORM { $$.i = 0; $$.q.uniform = 1; } + ; + +type_specifier: + type_specifier_no_prec + | precision_qualifier type_specifier_no_prec + { + $$ = $2; + $$->precision = $1; + } + ; + +type_specifier_no_prec: + type_specifier_nonarray + | type_specifier_nonarray '[' ']' + { + $$ = $1; + $$->is_array = true; + $$->array_size = NULL; + } + | type_specifier_nonarray '[' constant_expression ']' + { + $$ = $1; + $$->is_array = true; + $$->array_size = $3; + } + ; + +type_specifier_nonarray: + basic_type_specifier_nonarray + { + void *ctx = state; + $$ = new(ctx) ast_type_specifier($1); + $$->set_location(yylloc); + } + | struct_specifier + { + void *ctx = state; + $$ = new(ctx) ast_type_specifier($1); + $$->set_location(yylloc); + } + | IDENTIFIER + { + void *ctx = state; + $$ = new(ctx) ast_type_specifier($1); + $$->set_location(yylloc); + } + ; + +basic_type_specifier_nonarray: + VOID_TOK { $$ = ast_void; } + | FLOAT_TOK { $$ = ast_float; } + | INT_TOK { $$ = ast_int; } + | UINT_TOK { $$ = ast_uint; } + | BOOL_TOK { $$ = ast_bool; } + | VEC2 { $$ = ast_vec2; } + | VEC3 { $$ = ast_vec3; } + | VEC4 { $$ = ast_vec4; } + | BVEC2 { $$ = ast_bvec2; } + | BVEC3 { $$ = ast_bvec3; } + | BVEC4 { $$ = ast_bvec4; } + | IVEC2 { $$ = ast_ivec2; } + | IVEC3 { $$ = ast_ivec3; } + | IVEC4 { $$ = ast_ivec4; } + | UVEC2 { $$ = ast_uvec2; } + | UVEC3 { $$ = ast_uvec3; } + | UVEC4 { $$ = ast_uvec4; } + | MAT2X2 { $$ = ast_mat2; } + | MAT2X3 { $$ = ast_mat2x3; } + | MAT2X4 { $$ = ast_mat2x4; } + | MAT3X2 { $$ = ast_mat3x2; } + | MAT3X3 { $$ = ast_mat3; } + | MAT3X4 { $$ = ast_mat3x4; } + | MAT4X2 { $$ = ast_mat4x2; } + | MAT4X3 { $$ = ast_mat4x3; } + | MAT4X4 { $$ = ast_mat4; } + | SAMPLER1D { $$ = ast_sampler1d; } + | SAMPLER2D { $$ = ast_sampler2d; } + | SAMPLER2DRECT { $$ = ast_sampler2drect; } + | SAMPLER3D { $$ = ast_sampler3d; } + | SAMPLERCUBE { $$ = ast_samplercube; } + | SAMPLER1DSHADOW { $$ = ast_sampler1dshadow; } + | SAMPLER2DSHADOW { $$ = ast_sampler2dshadow; } + | SAMPLER2DRECTSHADOW { $$ = ast_sampler2drectshadow; } + | SAMPLERCUBESHADOW { $$ = ast_samplercubeshadow; } + | SAMPLER1DARRAY { $$ = ast_sampler1darray; } + | SAMPLER2DARRAY { $$ = ast_sampler2darray; } + | SAMPLER1DARRAYSHADOW { $$ = ast_sampler1darrayshadow; } + | SAMPLER2DARRAYSHADOW { $$ = ast_sampler2darrayshadow; } + | ISAMPLER1D { $$ = ast_isampler1d; } + | ISAMPLER2D { $$ = ast_isampler2d; } + | ISAMPLER3D { $$ = ast_isampler3d; } + | ISAMPLERCUBE { $$ = ast_isamplercube; } + | ISAMPLER1DARRAY { $$ = ast_isampler1darray; } + | ISAMPLER2DARRAY { $$ = ast_isampler2darray; } + | USAMPLER1D { $$ = ast_usampler1d; } + | USAMPLER2D { $$ = ast_usampler2d; } + | USAMPLER3D { $$ = ast_usampler3d; } + | USAMPLERCUBE { $$ = ast_usamplercube; } + | USAMPLER1DARRAY { $$ = ast_usampler1darray; } + | USAMPLER2DARRAY { $$ = ast_usampler2darray; } + ; + +precision_qualifier: + HIGHP { + if (state->language_version < 130) + _mesa_glsl_error(& @1, state, + "precision qualifier forbidden " + "in GLSL %d.%d (1.30 or later " + "required)\n", + state->language_version / 100, + state->language_version % 100); + + $$ = ast_precision_high; + } + | MEDIUMP { + if (state->language_version < 130) + _mesa_glsl_error(& @1, state, + "precision qualifier forbidden " + "in GLSL %d.%d (1.30 or later " + "required)\n", + state->language_version / 100, + state->language_version % 100); + + $$ = ast_precision_medium; + } + | LOWP { + if (state->language_version < 130) + _mesa_glsl_error(& @1, state, + "precision qualifier forbidden " + "in GLSL %d.%d (1.30 or later " + "required)\n", + state->language_version / 100, + state->language_version % 100); + + $$ = ast_precision_low; + } + ; + +struct_specifier: + STRUCT IDENTIFIER '{' struct_declaration_list '}' + { + void *ctx = state; + $$ = new(ctx) ast_struct_specifier($2, $4); + $$->set_location(yylloc); + } + | STRUCT '{' struct_declaration_list '}' + { + void *ctx = state; + $$ = new(ctx) ast_struct_specifier(NULL, $3); + $$->set_location(yylloc); + } + ; + +struct_declaration_list: + struct_declaration + { + $$ = (ast_node *) $1; + $1->link.self_link(); + } + | struct_declaration_list struct_declaration + { + $$ = (ast_node *) $1; + $$->link.insert_before(& $2->link); + } + ; + +struct_declaration: + type_specifier struct_declarator_list ';' + { + void *ctx = state; + ast_fully_specified_type *type = new(ctx) ast_fully_specified_type(); + type->set_location(yylloc); + + type->specifier = $1; + $$ = new(ctx) ast_declarator_list(type); + $$->set_location(yylloc); + + $$->declarations.push_degenerate_list_at_head(& $2->link); + } + ; + +struct_declarator_list: + struct_declarator + { + $$ = $1; + $1->link.self_link(); + } + | struct_declarator_list ',' struct_declarator + { + $$ = $1; + $$->link.insert_before(& $3->link); + } + ; + +struct_declarator: + IDENTIFIER + { + void *ctx = state; + $$ = new(ctx) ast_declaration($1, false, NULL, NULL); + $$->set_location(yylloc); + } + | IDENTIFIER '[' constant_expression ']' + { + void *ctx = state; + $$ = new(ctx) ast_declaration($1, true, $3, NULL); + $$->set_location(yylloc); + } + ; + +initializer: + assignment_expression + ; + +declaration_statement: + declaration + ; + + // Grammar Note: labeled statements for SWITCH only; 'goto' is not + // supported. +statement: + statement_matched + | statement_unmatched + ; + +statement_matched: + compound_statement { $$ = (ast_node *) $1; } + | simple_statement + ; + +statement_unmatched: + selection_statement_unmatched + ; + +simple_statement: + declaration_statement + | expression_statement + | selection_statement_matched + | switch_statement { $$ = NULL; } + | case_label { $$ = NULL; } + | iteration_statement + | jump_statement + ; + +compound_statement: + '{' '}' + { + void *ctx = state; + $$ = new(ctx) ast_compound_statement(true, NULL); + $$->set_location(yylloc); + } + | '{' statement_list '}' + { + void *ctx = state; + $$ = new(ctx) ast_compound_statement(true, $2); + $$->set_location(yylloc); + } + ; + +statement_no_new_scope: + compound_statement_no_new_scope { $$ = (ast_node *) $1; } + | simple_statement + ; + +compound_statement_no_new_scope: + '{' '}' + { + void *ctx = state; + $$ = new(ctx) ast_compound_statement(false, NULL); + $$->set_location(yylloc); + } + | '{' statement_list '}' + { + void *ctx = state; + $$ = new(ctx) ast_compound_statement(false, $2); + $$->set_location(yylloc); + } + ; + +statement_list: + statement + { + if ($1 == NULL) { + _mesa_glsl_error(& @1, state, "<nil> statement\n"); + assert($1 != NULL); + } + + $$ = $1; + $$->link.self_link(); + } + | statement_list statement + { + if ($2 == NULL) { + _mesa_glsl_error(& @2, state, "<nil> statement\n"); + assert($2 != NULL); + } + $$ = $1; + $$->link.insert_before(& $2->link); + } + ; + +expression_statement: + ';' + { + void *ctx = state; + $$ = new(ctx) ast_expression_statement(NULL); + $$->set_location(yylloc); + } + | expression ';' + { + void *ctx = state; + $$ = new(ctx) ast_expression_statement($1); + $$->set_location(yylloc); + } + ; + +selection_statement_matched: + IF '(' expression ')' statement_matched ELSE statement_matched + { + void *ctx = state; + $$ = new(ctx) ast_selection_statement($3, $5, $7); + $$->set_location(yylloc); + } + ; + +selection_statement_unmatched: + IF '(' expression ')' statement_matched + { + void *ctx = state; + $$ = new(ctx) ast_selection_statement($3, $5, NULL); + $$->set_location(yylloc); + } + | IF '(' expression ')' statement_unmatched + { + void *ctx = state; + $$ = new(ctx) ast_selection_statement($3, $5, NULL); + $$->set_location(yylloc); + } + | IF '(' expression ')' statement_matched ELSE statement_unmatched + { + void *ctx = state; + $$ = new(ctx) ast_selection_statement($3, $5, $7); + $$->set_location(yylloc); + } + ; + +condition: + expression + { + $$ = (ast_node *) $1; + } + | fully_specified_type IDENTIFIER '=' initializer + { + void *ctx = state; + ast_declaration *decl = new(ctx) ast_declaration($2, false, NULL, $4); + ast_declarator_list *declarator = new(ctx) ast_declarator_list($1); + decl->set_location(yylloc); + declarator->set_location(yylloc); + + declarator->declarations.push_tail(&decl->link); + $$ = declarator; + } + ; + +switch_statement: + SWITCH '(' expression ')' compound_statement + ; + +case_label: + CASE expression ':' + | DEFAULT ':' + ; + +iteration_statement: + WHILE '(' condition ')' statement_no_new_scope + { + void *ctx = state; + $$ = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_while, + NULL, $3, NULL, $5); + $$->set_location(yylloc); + } + | DO statement WHILE '(' expression ')' ';' + { + void *ctx = state; + $$ = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_do_while, + NULL, $5, NULL, $2); + $$->set_location(yylloc); + } + | FOR '(' for_init_statement for_rest_statement ')' statement_no_new_scope + { + void *ctx = state; + $$ = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_for, + $3, $4.cond, $4.rest, $6); + $$->set_location(yylloc); + } + ; + +for_init_statement: + expression_statement + | declaration_statement + ; + +conditionopt: + condition + | /* empty */ + { + $$ = NULL; + } + ; + +for_rest_statement: + conditionopt ';' + { + $$.cond = $1; + $$.rest = NULL; + } + | conditionopt ';' expression + { + $$.cond = $1; + $$.rest = $3; + } + ; + + // Grammar Note: No 'goto'. Gotos are not supported. +jump_statement: + CONTINUE ';' + { + void *ctx = state; + $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_continue, NULL); + $$->set_location(yylloc); + } + | BREAK ';' + { + void *ctx = state; + $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_break, NULL); + $$->set_location(yylloc); + } + | RETURN ';' + { + void *ctx = state; + $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, NULL); + $$->set_location(yylloc); + } + | RETURN expression ';' + { + void *ctx = state; + $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, $2); + $$->set_location(yylloc); + } + | DISCARD ';' // Fragment shader only. + { + void *ctx = state; + $$ = new(ctx) ast_jump_statement(ast_jump_statement::ast_discard, NULL); + $$->set_location(yylloc); + } + ; + +external_declaration: + function_definition { $$ = $1; } + | declaration { $$ = $1; } + | pragma_statement { $$ = NULL; } + ; + +function_definition: + function_prototype compound_statement_no_new_scope + { + void *ctx = state; + $$ = new(ctx) ast_function_definition(); + $$->set_location(yylloc); + $$->prototype = $1; + $$->body = $2; + } + ; diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp new file mode 100644 index 0000000000..bc56e4fcaf --- /dev/null +++ b/src/glsl/glsl_parser_extras.cpp @@ -0,0 +1,773 @@ +/* + * Copyright © 2008, 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <assert.h> + +extern "C" { +#include <talloc.h> +#include "main/core.h" /* for struct __GLcontextRec */ +} + +#include "ast.h" +#include "glsl_parser_extras.h" +#include "glsl_parser.h" +#include "ir_optimization.h" + +_mesa_glsl_parse_state::_mesa_glsl_parse_state(struct __GLcontextRec *ctx, + GLenum target, void *mem_ctx) +{ + switch (target) { + case GL_VERTEX_SHADER: this->target = vertex_shader; break; + case GL_FRAGMENT_SHADER: this->target = fragment_shader; break; + case GL_GEOMETRY_SHADER: this->target = geometry_shader; break; + } + + this->scanner = NULL; + this->translation_unit.make_empty(); + this->symbols = new(mem_ctx) glsl_symbol_table; + this->info_log = talloc_strdup(mem_ctx, ""); + this->error = false; + this->loop_or_switch_nesting = NULL; + this->ARB_texture_rectangle_enable = true; + + if (ctx != NULL) { + this->extensions = &ctx->Extensions; + + this->Const.MaxLights = ctx->Const.MaxLights; + this->Const.MaxClipPlanes = ctx->Const.MaxClipPlanes; + this->Const.MaxTextureUnits = ctx->Const.MaxTextureUnits; + this->Const.MaxTextureCoords = ctx->Const.MaxTextureCoordUnits; + this->Const.MaxVertexAttribs = ctx->Const.VertexProgram.MaxAttribs; + this->Const.MaxVertexUniformComponents = ctx->Const.VertexProgram.MaxUniformComponents; + this->Const.MaxVaryingFloats = ctx->Const.MaxVarying * 4; + this->Const.MaxVertexTextureImageUnits = ctx->Const.MaxVertexTextureImageUnits; + this->Const.MaxCombinedTextureImageUnits = ctx->Const.MaxCombinedTextureImageUnits; + this->Const.MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits; + this->Const.MaxFragmentUniformComponents = ctx->Const.FragmentProgram.MaxUniformComponents; + + this->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers; + } else { + /* If there is no GL context (standalone compiler), fill in constants + * with the minimum required values. + */ + static struct gl_extensions null_extensions; + + memset(&null_extensions, 0, sizeof(null_extensions)); + null_extensions.ARB_draw_buffers = GL_TRUE; + null_extensions.ARB_fragment_coord_conventions = GL_TRUE; + null_extensions.EXT_texture_array = GL_TRUE; + null_extensions.NV_texture_rectangle = GL_TRUE; + + this->extensions = &null_extensions; + + /* 1.10 minimums. */ + this->Const.MaxLights = 8; + this->Const.MaxClipPlanes = 8; + this->Const.MaxTextureUnits = 2; + + /* More than the 1.10 minimum to appease parser tests taken from + * apps that (hopefully) already checked the number of coords. + */ + this->Const.MaxTextureCoords = 4; + + this->Const.MaxVertexAttribs = 16; + this->Const.MaxVertexUniformComponents = 512; + this->Const.MaxVaryingFloats = 32; + this->Const.MaxVertexTextureImageUnits = 0; + this->Const.MaxCombinedTextureImageUnits = 2; + this->Const.MaxTextureImageUnits = 2; + this->Const.MaxFragmentUniformComponents = 64; + + this->Const.MaxDrawBuffers = 2; + } +} + +const char * +_mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target) +{ + switch (target) { + case vertex_shader: return "vertex"; + case fragment_shader: return "fragment"; + case geometry_shader: return "geometry"; + case ir_shader: break; + } + + assert(!"Should not get here."); + return "unknown"; +} + + +void +_mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state, + const char *fmt, ...) +{ + va_list ap; + + state->error = true; + + assert(state->info_log != NULL); + state->info_log = talloc_asprintf_append(state->info_log, + "%u:%u(%u): error: ", + locp->source, + locp->first_line, + locp->first_column); + va_start(ap, fmt); + state->info_log = talloc_vasprintf_append(state->info_log, fmt, ap); + va_end(ap); + state->info_log = talloc_strdup_append(state->info_log, "\n"); +} + + +void +_mesa_glsl_warning(const YYLTYPE *locp, _mesa_glsl_parse_state *state, + const char *fmt, ...) +{ + va_list ap; + + assert(state->info_log != NULL); + state->info_log = talloc_asprintf_append(state->info_log, + "%u:%u(%u): warning: ", + locp->source, + locp->first_line, + locp->first_column); + va_start(ap, fmt); + state->info_log = talloc_vasprintf_append(state->info_log, fmt, ap); + va_end(ap); + state->info_log = talloc_strdup_append(state->info_log, "\n"); +} + + +bool +_mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp, + const char *behavior, YYLTYPE *behavior_locp, + _mesa_glsl_parse_state *state) +{ + enum { + extension_disable, + extension_enable, + extension_require, + extension_warn + } ext_mode; + + if (strcmp(behavior, "warn") == 0) { + ext_mode = extension_warn; + } else if (strcmp(behavior, "require") == 0) { + ext_mode = extension_require; + } else if (strcmp(behavior, "enable") == 0) { + ext_mode = extension_enable; + } else if (strcmp(behavior, "disable") == 0) { + ext_mode = extension_disable; + } else { + _mesa_glsl_error(behavior_locp, state, + "Unknown extension behavior `%s'", + behavior); + return false; + } + + bool unsupported = false; + + if (strcmp(name, "all") == 0) { + if ((ext_mode == extension_enable) || (ext_mode == extension_require)) { + _mesa_glsl_error(name_locp, state, "Cannot %s all extensions", + (ext_mode == extension_enable) + ? "enable" : "require"); + return false; + } + } else if (strcmp(name, "GL_ARB_draw_buffers") == 0) { + /* This extension is only supported in fragment shaders. + */ + if (state->target != fragment_shader) { + unsupported = true; + } else { + state->ARB_draw_buffers_enable = (ext_mode != extension_disable); + state->ARB_draw_buffers_warn = (ext_mode == extension_warn); + } + } else if (strcmp(name, "GL_ARB_fragment_coord_conventions") == 0) { + state->ARB_fragment_coord_conventions_enable = + (ext_mode != extension_disable); + state->ARB_fragment_coord_conventions_warn = + (ext_mode == extension_warn); + + unsupported = !state->extensions->ARB_fragment_coord_conventions; + } else if (strcmp(name, "GL_ARB_texture_rectangle") == 0) { + state->ARB_texture_rectangle_enable = (ext_mode != extension_disable); + state->ARB_texture_rectangle_warn = (ext_mode == extension_warn); + } else if (strcmp(name, "GL_EXT_texture_array") == 0) { + state->EXT_texture_array_enable = (ext_mode != extension_disable); + state->EXT_texture_array_warn = (ext_mode == extension_warn); + + unsupported = !state->extensions->EXT_texture_array; + } else { + unsupported = true; + } + + if (unsupported) { + static const char *const fmt = "extension `%s' unsupported in %s shader"; + + if (ext_mode == extension_require) { + _mesa_glsl_error(name_locp, state, fmt, + name, _mesa_glsl_shader_target_name(state->target)); + return false; + } else { + _mesa_glsl_warning(name_locp, state, fmt, + name, _mesa_glsl_shader_target_name(state->target)); + } + } + + return true; +} + +void +_mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q) +{ + if (q->constant) + printf("const "); + + if (q->invariant) + printf("invariant "); + + if (q->attribute) + printf("attribute "); + + if (q->varying) + printf("varying "); + + if (q->in && q->out) + printf("inout "); + else { + if (q->in) + printf("in "); + + if (q->out) + printf("out "); + } + + if (q->centroid) + printf("centroid "); + if (q->uniform) + printf("uniform "); + if (q->smooth) + printf("smooth "); + if (q->flat) + printf("flat "); + if (q->noperspective) + printf("noperspective "); +} + + +void +ast_node::print(void) const +{ + printf("unhandled node "); +} + + +ast_node::ast_node(void) +{ + this->location.source = 0; + this->location.line = 0; + this->location.column = 0; +} + + +static void +ast_opt_array_size_print(bool is_array, const ast_expression *array_size) +{ + if (is_array) { + printf("[ "); + + if (array_size) + array_size->print(); + + printf("] "); + } +} + + +void +ast_compound_statement::print(void) const +{ + printf("{\n"); + + foreach_list_const(n, &this->statements) { + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + } + + printf("}\n"); +} + + +ast_compound_statement::ast_compound_statement(int new_scope, + ast_node *statements) +{ + this->new_scope = new_scope; + + if (statements != NULL) { + this->statements.push_degenerate_list_at_head(&statements->link); + } +} + + +void +ast_expression::print(void) const +{ + switch (oper) { + case ast_assign: + case ast_mul_assign: + case ast_div_assign: + case ast_mod_assign: + case ast_add_assign: + case ast_sub_assign: + case ast_ls_assign: + case ast_rs_assign: + case ast_and_assign: + case ast_xor_assign: + case ast_or_assign: + subexpressions[0]->print(); + printf("%s ", operator_string(oper)); + subexpressions[1]->print(); + break; + + case ast_field_selection: + subexpressions[0]->print(); + printf(". %s ", primary_expression.identifier); + break; + + case ast_plus: + case ast_neg: + case ast_bit_not: + case ast_logic_not: + case ast_pre_inc: + case ast_pre_dec: + printf("%s ", operator_string(oper)); + subexpressions[0]->print(); + break; + + case ast_post_inc: + case ast_post_dec: + subexpressions[0]->print(); + printf("%s ", operator_string(oper)); + break; + + case ast_conditional: + subexpressions[0]->print(); + printf("? "); + subexpressions[1]->print(); + printf(": "); + subexpressions[1]->print(); + break; + + case ast_array_index: + subexpressions[0]->print(); + printf("[ "); + subexpressions[1]->print(); + printf("] "); + break; + + case ast_function_call: { + subexpressions[0]->print(); + printf("( "); + + foreach_list_const (n, &this->expressions) { + if (n != this->expressions.get_head()) + printf(", "); + + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + } + + printf(") "); + break; + } + + case ast_identifier: + printf("%s ", primary_expression.identifier); + break; + + case ast_int_constant: + printf("%d ", primary_expression.int_constant); + break; + + case ast_uint_constant: + printf("%u ", primary_expression.uint_constant); + break; + + case ast_float_constant: + printf("%f ", primary_expression.float_constant); + break; + + case ast_bool_constant: + printf("%s ", + primary_expression.bool_constant + ? "true" : "false"); + break; + + case ast_sequence: { + printf("( "); + foreach_list_const(n, & this->expressions) { + if (n != this->expressions.get_head()) + printf(", "); + + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + } + printf(") "); + break; + } + + default: + assert(0); + break; + } +} + +ast_expression::ast_expression(int oper, + ast_expression *ex0, + ast_expression *ex1, + ast_expression *ex2) +{ + this->oper = ast_operators(oper); + this->subexpressions[0] = ex0; + this->subexpressions[1] = ex1; + this->subexpressions[2] = ex2; +} + + +void +ast_expression_statement::print(void) const +{ + if (expression) + expression->print(); + + printf("; "); +} + + +ast_expression_statement::ast_expression_statement(ast_expression *ex) : + expression(ex) +{ + /* empty */ +} + + +void +ast_function::print(void) const +{ + return_type->print(); + printf(" %s (", identifier); + + foreach_list_const(n, & this->parameters) { + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + } + + printf(")"); +} + + +ast_function::ast_function(void) + : is_definition(false), signature(NULL) +{ + /* empty */ +} + + +void +ast_fully_specified_type::print(void) const +{ + _mesa_ast_type_qualifier_print(& qualifier); + specifier->print(); +} + + +void +ast_parameter_declarator::print(void) const +{ + type->print(); + if (identifier) + printf("%s ", identifier); + ast_opt_array_size_print(is_array, array_size); +} + + +void +ast_function_definition::print(void) const +{ + prototype->print(); + body->print(); +} + + +void +ast_declaration::print(void) const +{ + printf("%s ", identifier); + ast_opt_array_size_print(is_array, array_size); + + if (initializer) { + printf("= "); + initializer->print(); + } +} + + +ast_declaration::ast_declaration(char *identifier, int is_array, + ast_expression *array_size, + ast_expression *initializer) +{ + this->identifier = identifier; + this->is_array = is_array; + this->array_size = array_size; + this->initializer = initializer; +} + + +void +ast_declarator_list::print(void) const +{ + assert(type || invariant); + + if (type) + type->print(); + else + printf("invariant "); + + foreach_list_const (ptr, & this->declarations) { + if (ptr != this->declarations.get_head()) + printf(", "); + + ast_node *ast = exec_node_data(ast_node, ptr, link); + ast->print(); + } + + printf("; "); +} + + +ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type) +{ + this->type = type; + this->invariant = false; +} + +void +ast_jump_statement::print(void) const +{ + switch (mode) { + case ast_continue: + printf("continue; "); + break; + case ast_break: + printf("break; "); + break; + case ast_return: + printf("return "); + if (opt_return_value) + opt_return_value->print(); + + printf("; "); + break; + case ast_discard: + printf("discard; "); + break; + } +} + + +ast_jump_statement::ast_jump_statement(int mode, ast_expression *return_value) +{ + this->mode = ast_jump_modes(mode); + + if (mode == ast_return) + opt_return_value = return_value; +} + + +void +ast_selection_statement::print(void) const +{ + printf("if ( "); + condition->print(); + printf(") "); + + then_statement->print(); + + if (else_statement) { + printf("else "); + else_statement->print(); + } + +} + + +ast_selection_statement::ast_selection_statement(ast_expression *condition, + ast_node *then_statement, + ast_node *else_statement) +{ + this->condition = condition; + this->then_statement = then_statement; + this->else_statement = else_statement; +} + + +void +ast_iteration_statement::print(void) const +{ + switch (mode) { + case ast_for: + printf("for( "); + if (init_statement) + init_statement->print(); + printf("; "); + + if (condition) + condition->print(); + printf("; "); + + if (rest_expression) + rest_expression->print(); + printf(") "); + + body->print(); + break; + + case ast_while: + printf("while ( "); + if (condition) + condition->print(); + printf(") "); + body->print(); + break; + + case ast_do_while: + printf("do "); + body->print(); + printf("while ( "); + if (condition) + condition->print(); + printf("); "); + break; + } +} + + +ast_iteration_statement::ast_iteration_statement(int mode, + ast_node *init, + ast_node *condition, + ast_expression *rest_expression, + ast_node *body) +{ + this->mode = ast_iteration_modes(mode); + this->init_statement = init; + this->condition = condition; + this->rest_expression = rest_expression; + this->body = body; +} + + +void +ast_struct_specifier::print(void) const +{ + printf("struct %s { ", name); + foreach_list_const(n, &this->declarations) { + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + } + printf("} "); +} + + +ast_struct_specifier::ast_struct_specifier(char *identifier, + ast_node *declarator_list) +{ + name = identifier; + this->declarations.push_degenerate_list_at_head(&declarator_list->link); +} + +bool +do_common_optimization(exec_list *ir, bool linked) +{ + GLboolean progress = GL_FALSE; + + progress = do_sub_to_add_neg(ir) || progress; + + if (linked) { + progress = do_function_inlining(ir) || progress; + progress = do_dead_functions(ir) || progress; + } + progress = do_structure_splitting(ir) || progress; + progress = do_if_simplification(ir) || progress; + progress = do_copy_propagation(ir) || progress; + if (linked) + progress = do_dead_code(ir) || progress; + else + progress = do_dead_code_unlinked(ir) || progress; + progress = do_dead_code_local(ir) || progress; + progress = do_tree_grafting(ir) || progress; + progress = do_constant_propagation(ir) || progress; + if (linked) + progress = do_constant_variable(ir) || progress; + else + progress = do_constant_variable_unlinked(ir) || progress; + progress = do_constant_folding(ir) || progress; + progress = do_algebraic(ir) || progress; + progress = do_if_return(ir) || progress; + progress = do_vec_index_to_swizzle(ir) || progress; + progress = do_swizzle_swizzle(ir) || progress; + progress = do_noop_swizzle(ir) || progress; + + return progress; +} + +extern "C" { + +/** + * To be called at GL teardown time, this frees compiler datastructures. + * + * After calling this, any previously compiled shaders and shader + * programs would be invalid. So this should happen at approximately + * program exit. + */ +void +_mesa_destroy_shader_compiler(void) +{ + _mesa_destroy_shader_compiler_caches(); + + _mesa_glsl_release_types(); +} + +/** + * Releases compiler caches to trade off performance for memory. + * + * Intended to be used with glReleaseShaderCompiler(). + */ +void +_mesa_destroy_shader_compiler_caches(void) +{ + _mesa_glsl_release_functions(); +} + +} diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h new file mode 100644 index 0000000000..3ccdab4ef2 --- /dev/null +++ b/src/glsl/glsl_parser_extras.h @@ -0,0 +1,235 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef GLSL_PARSER_EXTRAS_H +#define GLSL_PARSER_EXTRAS_H + +/* + * Most of the definitions here only apply to C++ + */ +#ifdef __cplusplus + + +#include <cstdlib> +#include "glsl_symbol_table.h" + +enum _mesa_glsl_parser_targets { + vertex_shader, + geometry_shader, + fragment_shader, + ir_shader +}; + +struct __GLcontextRec; + +struct _mesa_glsl_parse_state { + _mesa_glsl_parse_state(struct __GLcontextRec *ctx, GLenum target, + void *mem_ctx); + + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *mem = talloc_zero_size(ctx, size); + assert(mem != NULL); + + return mem; + } + + /* If the user *does* call delete, that's OK, we will just + * talloc_free in that case. */ + static void operator delete(void *mem) + { + talloc_free(mem); + } + + void *scanner; + exec_list translation_unit; + glsl_symbol_table *symbols; + + unsigned language_version; + enum _mesa_glsl_parser_targets target; + + /** + * Implementation defined limits that affect built-in variables, etc. + * + * \sa struct gl_constants (in mtypes.h) + */ + struct { + /* 1.10 */ + unsigned MaxLights; + unsigned MaxClipPlanes; + unsigned MaxTextureUnits; + unsigned MaxTextureCoords; + unsigned MaxVertexAttribs; + unsigned MaxVertexUniformComponents; + unsigned MaxVaryingFloats; + unsigned MaxVertexTextureImageUnits; + unsigned MaxCombinedTextureImageUnits; + unsigned MaxTextureImageUnits; + unsigned MaxFragmentUniformComponents; + + /* ARB_draw_buffers */ + unsigned MaxDrawBuffers; + } Const; + + /** + * During AST to IR conversion, pointer to current IR function + * + * Will be \c NULL whenever the AST to IR conversion is not inside a + * function definition. + */ + class ir_function_signature *current_function; + + /** Have we found a return statement in this function? */ + bool found_return; + + /** Was there an error during compilation? */ + bool error; + + /** Loop or switch statement containing the current instructions. */ + class ir_instruction *loop_or_switch_nesting; + class ast_iteration_statement *loop_or_switch_nesting_ast; + + /** List of structures defined in user code. */ + const glsl_type **user_structures; + unsigned num_user_structures; + + char *info_log; + + /** + * \name Enable bits for GLSL extensions + */ + /*@{*/ + unsigned ARB_draw_buffers_enable:1; + unsigned ARB_draw_buffers_warn:1; + unsigned ARB_fragment_coord_conventions_enable:1; + unsigned ARB_fragment_coord_conventions_warn:1; + unsigned ARB_texture_rectangle_enable:1; + unsigned ARB_texture_rectangle_warn:1; + unsigned EXT_texture_array_enable:1; + unsigned EXT_texture_array_warn:1; + /*@}*/ + + /** Extensions supported by the OpenGL implementation. */ + const struct gl_extensions *extensions; + + /** Shaders containing built-in functions that are used for linking. */ + struct gl_shader *builtins_to_link[16]; + unsigned num_builtins_to_link; +}; + +typedef struct YYLTYPE { + int first_line; + int first_column; + int last_line; + int last_column; + unsigned source; +} YYLTYPE; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 + +# define YYLLOC_DEFAULT(Current, Rhs, N) \ +do { \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC(Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC(Rhs, 0).last_column; \ + } \ + (Current).source = 0; \ +} while (0) + +extern void _mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state, + const char *fmt, ...); + +/** + * Emit a warning to the shader log + * + * \sa _mesa_glsl_error + */ +extern void _mesa_glsl_warning(const YYLTYPE *locp, + _mesa_glsl_parse_state *state, + const char *fmt, ...); + +extern void _mesa_glsl_lexer_ctor(struct _mesa_glsl_parse_state *state, + const char *string); + +extern void _mesa_glsl_lexer_dtor(struct _mesa_glsl_parse_state *state); + +union YYSTYPE; +extern int _mesa_glsl_lex(union YYSTYPE *yylval, YYLTYPE *yylloc, + void *scanner); + +extern int _mesa_glsl_parse(struct _mesa_glsl_parse_state *); + +/** + * Process elements of the #extension directive + * + * \return + * If \c name and \c behavior are valid, \c true is returned. Otherwise + * \c false is returned. + */ +extern bool _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp, + const char *behavior, + YYLTYPE *behavior_locp, + _mesa_glsl_parse_state *state); + +/** + * Get the textual name of the specified shader target + */ +extern const char * +_mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target); + + +#endif /* __cplusplus */ + + +/* + * These definitions apply to C and C++ + */ +#ifdef __cplusplus +extern "C" { +#endif + +extern int preprocess(void *ctx, const char **shader, char **info_log, + const struct gl_extensions *extensions); + +extern void _mesa_destroy_shader_compiler(); +extern void _mesa_destroy_shader_compiler_caches(); + +#ifdef __cplusplus +} +#endif + + +#endif /* GLSL_PARSER_EXTRAS_H */ diff --git a/src/glsl/glsl_symbol_table.cpp b/src/glsl/glsl_symbol_table.cpp new file mode 100644 index 0000000000..e9bf89b951 --- /dev/null +++ b/src/glsl/glsl_symbol_table.cpp @@ -0,0 +1,160 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "glsl_symbol_table.h" + +class symbol_table_entry { +public: + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *entry = talloc_size(ctx, size); + assert(entry != NULL); + return entry; + } + + /* If the user *does* call delete, that's OK, we will just + * talloc_free in that case. Here, C++ will have already called the + * destructor so tell talloc not to do that again. */ + static void operator delete(void *table) + { + talloc_set_destructor(table, NULL); + talloc_free(table); + } + + symbol_table_entry(ir_variable *v) : v(v), f(0), t(0) {} + symbol_table_entry(ir_function *f) : v(0), f(f), t(0) {} + symbol_table_entry(const glsl_type *t) : v(0), f(0), t(t) {} + + ir_variable *v; + ir_function *f; + const glsl_type *t; +}; + +glsl_symbol_table::glsl_symbol_table() +{ + this->language_version = 120; + this->table = _mesa_symbol_table_ctor(); + this->mem_ctx = talloc_init("symbol table entries"); +} + +glsl_symbol_table::~glsl_symbol_table() +{ + _mesa_symbol_table_dtor(table); + talloc_free(mem_ctx); +} + +void glsl_symbol_table::push_scope() +{ + _mesa_symbol_table_push_scope(table); +} + +void glsl_symbol_table::pop_scope() +{ + _mesa_symbol_table_pop_scope(table); +} + +bool glsl_symbol_table::name_declared_this_scope(const char *name) +{ + return _mesa_symbol_table_symbol_scope(table, -1, name) == 0; +} + +bool glsl_symbol_table::add_variable(const char *name, ir_variable *v) +{ + if (this->language_version == 110) { + /* In 1.10, functions and variables have separate namespaces. */ + symbol_table_entry *existing = get_entry(name); + if (name_declared_this_scope(name)) { + /* If there's already an existing function (not a constructor!) in + * the current scope, just update the existing entry to include 'v'. + */ + if (existing->v == NULL && existing->t == NULL) { + existing->v = v; + return true; + } + } else { + /* If not declared at this scope, add a new entry. But if an existing + * entry includes a function, propagate that to this block - otherwise + * the new variable declaration would shadow the function. + */ + symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(v); + if (existing != NULL) + entry->f = existing->f; + int added = _mesa_symbol_table_add_symbol(table, -1, name, entry); + assert(added == 0); + (void)added; + return true; + } + return false; + } + + /* 1.20+ rules: */ + symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(v); + return _mesa_symbol_table_add_symbol(table, -1, name, entry) == 0; +} + +bool glsl_symbol_table::add_type(const char *name, const glsl_type *t) +{ + symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(t); + return _mesa_symbol_table_add_symbol(table, -1, name, entry) == 0; +} + +bool glsl_symbol_table::add_function(const char *name, ir_function *f) +{ + if (this->language_version == 110 && name_declared_this_scope(name)) { + /* In 1.10, functions and variables have separate namespaces. */ + symbol_table_entry *existing = get_entry(name); + if ((existing->f == NULL) && (existing->t == NULL)) { + existing->f = f; + return true; + } + } + symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(f); + return _mesa_symbol_table_add_symbol(table, -1, name, entry) == 0; +} + +ir_variable *glsl_symbol_table::get_variable(const char *name) +{ + symbol_table_entry *entry = get_entry(name); + return entry != NULL ? entry->v : NULL; +} + +const glsl_type *glsl_symbol_table::get_type(const char *name) +{ + symbol_table_entry *entry = get_entry(name); + return entry != NULL ? entry->t : NULL; +} + +ir_function *glsl_symbol_table::get_function(const char *name) +{ + symbol_table_entry *entry = get_entry(name); + return entry != NULL ? entry->f : NULL; +} + +symbol_table_entry *glsl_symbol_table::get_entry(const char *name) +{ + return (symbol_table_entry *) + _mesa_symbol_table_find_symbol(table, -1, name); +} diff --git a/src/glsl/glsl_symbol_table.h b/src/glsl/glsl_symbol_table.h new file mode 100644 index 0000000000..f26de52432 --- /dev/null +++ b/src/glsl/glsl_symbol_table.h @@ -0,0 +1,121 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef GLSL_SYMBOL_TABLE +#define GLSL_SYMBOL_TABLE + +#include <new> + +extern "C" { +#include "program/symbol_table.h" +} +#include "ir.h" +#include "glsl_types.h" + +class symbol_table_entry; + +/** + * Facade class for _mesa_symbol_table + * + * Wraps the existing \c _mesa_symbol_table data structure to enforce some + * type safe and some symbol table invariants. + */ +struct glsl_symbol_table { +private: + static int + _glsl_symbol_table_destructor (glsl_symbol_table *table) + { + table->~glsl_symbol_table(); + + return 0; + } + +public: + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *table; + + table = talloc_size(ctx, size); + assert(table != NULL); + + talloc_set_destructor(table, (int (*)(void*)) _glsl_symbol_table_destructor); + + return table; + } + + /* If the user *does* call delete, that's OK, we will just + * talloc_free in that case. Here, C++ will have already called the + * destructor so tell talloc not to do that again. */ + static void operator delete(void *table) + { + talloc_set_destructor(table, NULL); + talloc_free(table); + } + + glsl_symbol_table(); + ~glsl_symbol_table(); + + unsigned int language_version; + + void push_scope(); + void pop_scope(); + + /** + * Determine whether a name was declared at the current scope + */ + bool name_declared_this_scope(const char *name); + + /** + * \name Methods to add symbols to the table + * + * There is some temptation to rename all these functions to \c add_symbol + * or similar. However, this breaks symmetry with the getter functions and + * reduces the clarity of the intention of code that uses these methods. + */ + /*@{*/ + bool add_variable(const char *name, ir_variable *v); + bool add_type(const char *name, const glsl_type *t); + bool add_function(const char *name, ir_function *f); + /*@}*/ + + /** + * \name Methods to get symbols from the table + */ + /*@{*/ + ir_variable *get_variable(const char *name); + const glsl_type *get_type(const char *name); + ir_function *get_function(const char *name); + /*@}*/ + +private: + symbol_table_entry *get_entry(const char *name); + + struct _mesa_symbol_table *table; + void *mem_ctx; +}; + +#endif /* GLSL_SYMBOL_TABLE */ diff --git a/src/glsl/glsl_types.cpp b/src/glsl/glsl_types.cpp new file mode 100644 index 0000000000..92ad3efafc --- /dev/null +++ b/src/glsl/glsl_types.cpp @@ -0,0 +1,484 @@ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <cstdio> +#include <stdlib.h> +#include "main/core.h" /* for Elements */ +#include "glsl_symbol_table.h" +#include "glsl_parser_extras.h" +#include "glsl_types.h" +#include "builtin_types.h" +extern "C" { +#include "program/hash_table.h" +} + +hash_table *glsl_type::array_types = NULL; +hash_table *glsl_type::record_types = NULL; +void *glsl_type::mem_ctx = NULL; + +void +glsl_type::init_talloc_type_ctx(void) +{ + if (glsl_type::mem_ctx == NULL) { + glsl_type::mem_ctx = talloc_autofree_context(); + assert(glsl_type::mem_ctx != NULL); + } +} + +glsl_type::glsl_type(GLenum gl_type, + unsigned base_type, unsigned vector_elements, + unsigned matrix_columns, const char *name) : + gl_type(gl_type), + base_type(base_type), + sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), + sampler_type(0), + vector_elements(vector_elements), matrix_columns(matrix_columns), + length(0) +{ + init_talloc_type_ctx(); + this->name = talloc_strdup(this->mem_ctx, name); + /* Neither dimension is zero or both dimensions are zero. + */ + assert((vector_elements == 0) == (matrix_columns == 0)); + memset(& fields, 0, sizeof(fields)); +} + +glsl_type::glsl_type(GLenum gl_type, + enum glsl_sampler_dim dim, bool shadow, bool array, + unsigned type, const char *name) : + gl_type(gl_type), + base_type(GLSL_TYPE_SAMPLER), + sampler_dimensionality(dim), sampler_shadow(shadow), + sampler_array(array), sampler_type(type), + vector_elements(0), matrix_columns(0), + length(0) +{ + init_talloc_type_ctx(); + this->name = talloc_strdup(this->mem_ctx, name); + memset(& fields, 0, sizeof(fields)); +} + +glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, + const char *name) : + base_type(GLSL_TYPE_STRUCT), + sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), + sampler_type(0), + vector_elements(0), matrix_columns(0), + length(num_fields) +{ + unsigned int i; + + init_talloc_type_ctx(); + this->name = talloc_strdup(this->mem_ctx, name); + this->fields.structure = talloc_array(this->mem_ctx, + glsl_struct_field, length); + for (i = 0; i < length; i++) { + this->fields.structure[i].type = fields[i].type; + this->fields.structure[i].name = talloc_strdup(this->fields.structure, + fields[i].name); + } +} + +static void +add_types_to_symbol_table(glsl_symbol_table *symtab, + const struct glsl_type *types, + unsigned num_types, bool warn) +{ + (void) warn; + + for (unsigned i = 0; i < num_types; i++) { + symtab->add_type(types[i].name, & types[i]); + } +} + + +void +glsl_type::generate_110_types(glsl_symbol_table *symtab) +{ + add_types_to_symbol_table(symtab, builtin_core_types, + Elements(builtin_core_types), + false); + add_types_to_symbol_table(symtab, builtin_structure_types, + Elements(builtin_structure_types), + false); + add_types_to_symbol_table(symtab, builtin_110_deprecated_structure_types, + Elements(builtin_110_deprecated_structure_types), + false); + add_types_to_symbol_table(symtab, & void_type, 1, false); +} + + +void +glsl_type::generate_120_types(glsl_symbol_table *symtab) +{ + generate_110_types(symtab); + + add_types_to_symbol_table(symtab, builtin_120_types, + Elements(builtin_120_types), false); +} + + +void +glsl_type::generate_130_types(glsl_symbol_table *symtab) +{ + generate_120_types(symtab); + + add_types_to_symbol_table(symtab, builtin_130_types, + Elements(builtin_130_types), false); + generate_EXT_texture_array_types(symtab, false); +} + + +void +glsl_type::generate_ARB_texture_rectangle_types(glsl_symbol_table *symtab, + bool warn) +{ + add_types_to_symbol_table(symtab, builtin_ARB_texture_rectangle_types, + Elements(builtin_ARB_texture_rectangle_types), + warn); +} + + +void +glsl_type::generate_EXT_texture_array_types(glsl_symbol_table *symtab, + bool warn) +{ + add_types_to_symbol_table(symtab, builtin_EXT_texture_array_types, + Elements(builtin_EXT_texture_array_types), + warn); +} + + +void +_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state) +{ + switch (state->language_version) { + case 110: + glsl_type::generate_110_types(state->symbols); + break; + case 120: + glsl_type::generate_120_types(state->symbols); + break; + case 130: + glsl_type::generate_130_types(state->symbols); + break; + default: + /* error */ + break; + } + + if (state->ARB_texture_rectangle_enable) { + glsl_type::generate_ARB_texture_rectangle_types(state->symbols, + state->ARB_texture_rectangle_warn); + } + + if (state->EXT_texture_array_enable && state->language_version < 130) { + // These are already included in 130; don't create twice. + glsl_type::generate_EXT_texture_array_types(state->symbols, + state->EXT_texture_array_warn); + } +} + + +const glsl_type *glsl_type::get_base_type() const +{ + switch (base_type) { + case GLSL_TYPE_UINT: + return uint_type; + case GLSL_TYPE_INT: + return int_type; + case GLSL_TYPE_FLOAT: + return float_type; + case GLSL_TYPE_BOOL: + return bool_type; + default: + return error_type; + } +} + + +void +_mesa_glsl_release_types(void) +{ + if (glsl_type::array_types != NULL) { + hash_table_dtor(glsl_type::array_types); + glsl_type::array_types = NULL; + } + + if (glsl_type::record_types != NULL) { + hash_table_dtor(glsl_type::record_types); + glsl_type::record_types = NULL; + } +} + + +glsl_type::glsl_type(const glsl_type *array, unsigned length) : + base_type(GLSL_TYPE_ARRAY), + sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), + sampler_type(0), + vector_elements(0), matrix_columns(0), + name(NULL), length(length) +{ + this->fields.array = array; + /* Inherit the gl type of the base. The GL type is used for + * uniform/statevar handling in Mesa and the arrayness of the type + * is represented by the size rather than the type. + */ + this->gl_type = array->gl_type; + + /* Allow a maximum of 10 characters for the array size. This is enough + * for 32-bits of ~0. The extra 3 are for the '[', ']', and terminating + * NUL. + */ + const unsigned name_length = strlen(array->name) + 10 + 3; + char *const n = (char *) talloc_size(this->mem_ctx, name_length); + + if (length == 0) + snprintf(n, name_length, "%s[]", array->name); + else + snprintf(n, name_length, "%s[%u]", array->name, length); + + this->name = n; +} + + +const glsl_type * +glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns) +{ + if (base_type == GLSL_TYPE_VOID) + return &void_type; + + if ((rows < 1) || (rows > 4) || (columns < 1) || (columns > 4)) + return error_type; + + /* Treat GLSL vectors as Nx1 matrices. + */ + if (columns == 1) { + switch (base_type) { + case GLSL_TYPE_UINT: + return uint_type + (rows - 1); + case GLSL_TYPE_INT: + return int_type + (rows - 1); + case GLSL_TYPE_FLOAT: + return float_type + (rows - 1); + case GLSL_TYPE_BOOL: + return bool_type + (rows - 1); + default: + return error_type; + } + } else { + if ((base_type != GLSL_TYPE_FLOAT) || (rows == 1)) + return error_type; + + /* GLSL matrix types are named mat{COLUMNS}x{ROWS}. Only the following + * combinations are valid: + * + * 1 2 3 4 + * 1 + * 2 x x x + * 3 x x x + * 4 x x x + */ +#define IDX(c,r) (((c-1)*3) + (r-1)) + + switch (IDX(columns, rows)) { + case IDX(2,2): return mat2_type; + case IDX(2,3): return mat2x3_type; + case IDX(2,4): return mat2x4_type; + case IDX(3,2): return mat3x2_type; + case IDX(3,3): return mat3_type; + case IDX(3,4): return mat3x4_type; + case IDX(4,2): return mat4x2_type; + case IDX(4,3): return mat4x3_type; + case IDX(4,4): return mat4_type; + default: return error_type; + } + } + + assert(!"Should not get here."); + return error_type; +} + + +const glsl_type * +glsl_type::get_array_instance(const glsl_type *base, unsigned array_size) +{ + + if (array_types == NULL) { + array_types = hash_table_ctor(64, hash_table_string_hash, + hash_table_string_compare); + } + + /* Generate a name using the base type pointer in the key. This is + * done because the name of the base type may not be unique across + * shaders. For example, two shaders may have different record types + * named 'foo'. + */ + char key[128]; + snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size); + + const glsl_type *t = (glsl_type *) hash_table_find(array_types, key); + if (t == NULL) { + t = new glsl_type(base, array_size); + + hash_table_insert(array_types, (void *) t, talloc_strdup(mem_ctx, key)); + } + + assert(t->base_type == GLSL_TYPE_ARRAY); + assert(t->length == array_size); + assert(t->fields.array == base); + + return t; +} + + +int +glsl_type::record_key_compare(const void *a, const void *b) +{ + const glsl_type *const key1 = (glsl_type *) a; + const glsl_type *const key2 = (glsl_type *) b; + + /* Return zero is the types match (there is zero difference) or non-zero + * otherwise. + */ + if (strcmp(key1->name, key2->name) != 0) + return 1; + + if (key1->length != key2->length) + return 1; + + for (unsigned i = 0; i < key1->length; i++) { + if (key1->fields.structure[i].type != key2->fields.structure[i].type) + return 1; + if (strcmp(key1->fields.structure[i].name, + key2->fields.structure[i].name) != 0) + return 1; + } + + return 0; +} + + +unsigned +glsl_type::record_key_hash(const void *a) +{ + const glsl_type *const key = (glsl_type *) a; + char hash_key[128]; + unsigned size = 0; + + size = snprintf(hash_key, sizeof(hash_key), "%08x", key->length); + + for (unsigned i = 0; i < key->length; i++) { + if (size >= sizeof(hash_key)) + break; + + size += snprintf(& hash_key[size], sizeof(hash_key) - size, + "%p", (void *) key->fields.structure[i].type); + } + + return hash_table_string_hash(& hash_key); +} + + +const glsl_type * +glsl_type::get_record_instance(const glsl_struct_field *fields, + unsigned num_fields, + const char *name) +{ + const glsl_type key(fields, num_fields, name); + + if (record_types == NULL) { + record_types = hash_table_ctor(64, record_key_hash, record_key_compare); + } + + const glsl_type *t = (glsl_type *) hash_table_find(record_types, & key); + if (t == NULL) { + t = new glsl_type(fields, num_fields, name); + + hash_table_insert(record_types, (void *) t, t); + } + + assert(t->base_type == GLSL_TYPE_STRUCT); + assert(t->length == num_fields); + assert(strcmp(t->name, name) == 0); + + return t; +} + + +const glsl_type * +glsl_type::field_type(const char *name) const +{ + if (this->base_type != GLSL_TYPE_STRUCT) + return error_type; + + for (unsigned i = 0; i < this->length; i++) { + if (strcmp(name, this->fields.structure[i].name) == 0) + return this->fields.structure[i].type; + } + + return error_type; +} + + +int +glsl_type::field_index(const char *name) const +{ + if (this->base_type != GLSL_TYPE_STRUCT) + return -1; + + for (unsigned i = 0; i < this->length; i++) { + if (strcmp(name, this->fields.structure[i].name) == 0) + return i; + } + + return -1; +} + + +unsigned +glsl_type::component_slots() const +{ + switch (this->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + return this->components(); + + case GLSL_TYPE_STRUCT: { + unsigned size = 0; + + for (unsigned i = 0; i < this->length; i++) + size += this->fields.structure[i].type->component_slots(); + + return size; + } + + case GLSL_TYPE_ARRAY: + return this->length * this->fields.array->component_slots(); + + default: + return 0; + } +} diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h new file mode 100644 index 0000000000..b4e83c9833 --- /dev/null +++ b/src/glsl/glsl_types.h @@ -0,0 +1,476 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef GLSL_TYPES_H +#define GLSL_TYPES_H + +#include <cstring> +#include <cassert> + +extern "C" { +#include "GL/gl.h" +#include <talloc.h> +} + +struct _mesa_glsl_parse_state; +struct glsl_symbol_table; + +extern "C" void +_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state); + +extern "C" void +_mesa_glsl_release_types(void); + +#define GLSL_TYPE_UINT 0 +#define GLSL_TYPE_INT 1 +#define GLSL_TYPE_FLOAT 2 +#define GLSL_TYPE_BOOL 3 +#define GLSL_TYPE_SAMPLER 4 +#define GLSL_TYPE_STRUCT 5 +#define GLSL_TYPE_ARRAY 6 +#define GLSL_TYPE_FUNCTION 7 +#define GLSL_TYPE_VOID 8 +#define GLSL_TYPE_ERROR 9 + +enum glsl_sampler_dim { + GLSL_SAMPLER_DIM_1D = 0, + GLSL_SAMPLER_DIM_2D, + GLSL_SAMPLER_DIM_3D, + GLSL_SAMPLER_DIM_CUBE, + GLSL_SAMPLER_DIM_RECT, + GLSL_SAMPLER_DIM_BUF +}; + + +struct glsl_type { + GLenum gl_type; + unsigned base_type:4; + + unsigned sampler_dimensionality:3; + unsigned sampler_shadow:1; + unsigned sampler_array:1; + unsigned sampler_type:2; /**< Type of data returned using this sampler. + * only \c GLSL_TYPE_FLOAT, \c GLSL_TYPE_INT, + * and \c GLSL_TYPE_UINT are valid. + */ + + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'mem_ctx' (or any of its ancestors). */ + static void* operator new(size_t size) + { + if (glsl_type::mem_ctx == NULL) { + glsl_type::mem_ctx = talloc_init("glsl_type"); + assert(glsl_type::mem_ctx != NULL); + } + + void *type; + + type = talloc_size(glsl_type::mem_ctx, size); + assert(type != NULL); + + return type; + } + + /* If the user *does* call delete, that's OK, we will just + * talloc_free in that case. */ + static void operator delete(void *type) + { + talloc_free(type); + } + + /** + * \name Vector and matrix element counts + * + * For scalars, each of these values will be 1. For non-numeric types + * these will be 0. + */ + /*@{*/ + unsigned vector_elements:3; /**< 1, 2, 3, or 4 vector elements. */ + unsigned matrix_columns:3; /**< 1, 2, 3, or 4 matrix columns. */ + /*@}*/ + + /** + * Name of the data type + * + * This may be \c NULL for anonymous structures, for arrays, or for + * function types. + */ + const char *name; + + /** + * For \c GLSL_TYPE_ARRAY, this is the length of the array. For + * \c GLSL_TYPE_STRUCT, it is the number of elements in the structure and + * the number of values pointed to by \c fields.structure (below). + * + * For \c GLSL_TYPE_FUNCTION, it is the number of parameters to the + * function. The return value from a function is implicitly the first + * parameter. The types of the parameters are stored in + * \c fields.parameters (below). + */ + unsigned length; + + /** + * Subtype of composite data types. + */ + union { + const struct glsl_type *array; /**< Type of array elements. */ + const struct glsl_type *parameters; /**< Parameters to function. */ + struct glsl_struct_field *structure; /**< List of struct fields. */ + } fields; + + + /** + * \name Pointers to various public type singletons + */ + /*@{*/ + static const glsl_type *const error_type; + static const glsl_type *const int_type; + static const glsl_type *const ivec4_type; + static const glsl_type *const uint_type; + static const glsl_type *const uvec4_type; + static const glsl_type *const float_type; + static const glsl_type *const vec2_type; + static const glsl_type *const vec3_type; + static const glsl_type *const vec4_type; + static const glsl_type *const bool_type; + static const glsl_type *const mat2_type; + static const glsl_type *const mat2x3_type; + static const glsl_type *const mat2x4_type; + static const glsl_type *const mat3x2_type; + static const glsl_type *const mat3_type; + static const glsl_type *const mat3x4_type; + static const glsl_type *const mat4x2_type; + static const glsl_type *const mat4x3_type; + static const glsl_type *const mat4_type; + /*@}*/ + + + /** + * For numeric and boolean derrived types returns the basic scalar type + * + * If the type is a numeric or boolean scalar, vector, or matrix type, + * this function gets the scalar type of the individual components. For + * all other types, including arrays of numeric or boolean types, the + * error type is returned. + */ + const glsl_type *get_base_type() const; + + /** + * Query the type of elements in an array + * + * \return + * Pointer to the type of elements in the array for array types, or \c NULL + * for non-array types. + */ + const glsl_type *element_type() const + { + return is_array() ? fields.array : NULL; + } + + /** + * Get the instance of a built-in scalar, vector, or matrix type + */ + static const glsl_type *get_instance(unsigned base_type, unsigned rows, + unsigned columns); + + /** + * Get the instance of an array type + */ + static const glsl_type *get_array_instance(const glsl_type *base, + unsigned elements); + + /** + * Get the instance of a record type + */ + static const glsl_type *get_record_instance(const glsl_struct_field *fields, + unsigned num_fields, + const char *name); + + /** + * Query the total number of scalars that make up a scalar, vector or matrix + */ + unsigned components() const + { + return vector_elements * matrix_columns; + } + + /** + * Calculate the number of components slots required to hold this type + * + * This is used to determine how many uniform or varying locations a type + * might occupy. + */ + unsigned component_slots() const; + + + /** + * Query whether or not a type is a scalar (non-vector and non-matrix). + */ + bool is_scalar() const + { + return (vector_elements == 1) + && (base_type >= GLSL_TYPE_UINT) + && (base_type <= GLSL_TYPE_BOOL); + } + + /** + * Query whether or not a type is a vector + */ + bool is_vector() const + { + return (vector_elements > 1) + && (matrix_columns == 1) + && (base_type >= GLSL_TYPE_UINT) + && (base_type <= GLSL_TYPE_BOOL); + } + + /** + * Query whether or not a type is a matrix + */ + bool is_matrix() const + { + /* GLSL only has float matrices. */ + return (matrix_columns > 1) && (base_type == GLSL_TYPE_FLOAT); + } + + /** + * Query whether or not a type is a non-array numeric type + */ + bool is_numeric() const + { + return (base_type >= GLSL_TYPE_UINT) && (base_type <= GLSL_TYPE_FLOAT); + } + + /** + * Query whether or not a type is an integral type + */ + bool is_integer() const + { + return (base_type == GLSL_TYPE_UINT) || (base_type == GLSL_TYPE_INT); + } + + /** + * Query whether or not a type is a float type + */ + bool is_float() const + { + return base_type == GLSL_TYPE_FLOAT; + } + + /** + * Query whether or not a type is a non-array boolean type + */ + bool is_boolean() const + { + return base_type == GLSL_TYPE_BOOL; + } + + /** + * Query whether or not a type is a sampler + */ + bool is_sampler() const + { + return base_type == GLSL_TYPE_SAMPLER; + } + + /** + * Query whether or not a type is an array + */ + bool is_array() const + { + return base_type == GLSL_TYPE_ARRAY; + } + + /** + * Query whether or not a type is a record + */ + bool is_record() const + { + return base_type == GLSL_TYPE_STRUCT; + } + + /** + * Query whether or not a type is the void type singleton. + */ + bool is_void() const + { + return base_type == GLSL_TYPE_VOID; + } + + /** + * Query whether or not a type is the error type singleton. + */ + bool is_error() const + { + return base_type == GLSL_TYPE_ERROR; + } + + /** + * Query the full type of a matrix row + * + * \return + * If the type is not a matrix, \c glsl_type::error_type is returned. + * Otherwise a type matching the rows of the matrix is returned. + */ + const glsl_type *row_type() const + { + return is_matrix() + ? get_instance(base_type, matrix_columns, 1) + : error_type; + } + + /** + * Query the full type of a matrix column + * + * \return + * If the type is not a matrix, \c glsl_type::error_type is returned. + * Otherwise a type matching the columns of the matrix is returned. + */ + const glsl_type *column_type() const + { + return is_matrix() + ? get_instance(base_type, vector_elements, 1) + : error_type; + } + + + /** + * Get the type of a structure field + * + * \return + * Pointer to the type of the named field. If the type is not a structure + * or the named field does not exist, \c glsl_type::error_type is returned. + */ + const glsl_type *field_type(const char *name) const; + + + /** + * Get the location of a filed within a record type + */ + int field_index(const char *name) const; + + + /** + * Query the number of elements in an array type + * + * \return + * The number of elements in the array for array types or -1 for non-array + * types. If the number of elements in the array has not yet been declared, + * zero is returned. + */ + int array_size() const + { + return is_array() ? length : -1; + } + +private: + /** + * talloc context for all glsl_type allocations + * + * Set on the first call to \c glsl_type::new. + */ + static void *mem_ctx; + + void init_talloc_type_ctx(void); + + /** Constructor for vector and matrix types */ + glsl_type(GLenum gl_type, + unsigned base_type, unsigned vector_elements, + unsigned matrix_columns, const char *name); + + /** Constructor for sampler types */ + glsl_type(GLenum gl_type, + enum glsl_sampler_dim dim, bool shadow, bool array, + unsigned type, const char *name); + + /** Constructor for record types */ + glsl_type(const glsl_struct_field *fields, unsigned num_fields, + const char *name); + + /** Constructor for array types */ + glsl_type(const glsl_type *array, unsigned length); + + /** Hash table containing the known array types. */ + static struct hash_table *array_types; + + /** Hash table containing the known record types. */ + static struct hash_table *record_types; + + static int record_key_compare(const void *a, const void *b); + static unsigned record_key_hash(const void *key); + + /** + * \name Pointers to various type singletons + */ + /*@{*/ + static const glsl_type _error_type; + static const glsl_type void_type; + static const glsl_type builtin_core_types[]; + static const glsl_type builtin_structure_types[]; + static const glsl_type builtin_110_deprecated_structure_types[]; + static const glsl_type builtin_120_types[]; + static const glsl_type builtin_130_types[]; + static const glsl_type builtin_ARB_texture_rectangle_types[]; + static const glsl_type builtin_EXT_texture_array_types[]; + static const glsl_type builtin_EXT_texture_buffer_object_types[]; + /*@}*/ + + /** + * \name Methods to populate a symbol table with built-in types. + * + * \internal + * This is one of the truely annoying things about C++. Methods that are + * completely internal and private to a type still have to be advertised to + * the world in a public header file. + */ + /*@{*/ + static void generate_110_types(glsl_symbol_table *); + static void generate_120_types(glsl_symbol_table *); + static void generate_130_types(glsl_symbol_table *); + static void generate_ARB_texture_rectangle_types(glsl_symbol_table *, + bool); + static void generate_EXT_texture_array_types(glsl_symbol_table *, + bool); + /*@}*/ + + /** + * \name Friend functions. + * + * These functions are friends because they must have C linkage and the + * need to call various private methods or access various private static + * data. + */ + /*@{*/ + friend void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *); + friend void _mesa_glsl_release_types(void); + /*@}*/ +}; + +struct glsl_struct_field { + const struct glsl_type *type; + const char *name; +}; + +#endif /* GLSL_TYPES_H */ diff --git a/src/glsl/hir_field_selection.cpp b/src/glsl/hir_field_selection.cpp new file mode 100644 index 0000000000..3c33127b5f --- /dev/null +++ b/src/glsl/hir_field_selection.cpp @@ -0,0 +1,102 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ir.h" +#include "program/symbol_table.h" +#include "glsl_parser_extras.h" +#include "ast.h" +#include "glsl_types.h" + +ir_rvalue * +_mesa_ast_field_selection_to_hir(const ast_expression *expr, + exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + ir_rvalue *result = NULL; + ir_rvalue *op; + + op = expr->subexpressions[0]->hir(instructions, state); + + /* There are two kinds of field selection. There is the selection of a + * specific field from a structure, and there is the selection of a + * swizzle / mask from a vector. Which is which is determined entirely + * by the base type of the thing to which the field selection operator is + * being applied. + */ + YYLTYPE loc = expr->get_location(); + if (op->type->is_error()) { + /* silently propagate the error */ + } else if (op->type->is_vector()) { + ir_swizzle *swiz = ir_swizzle::create(op, + expr->primary_expression.identifier, + op->type->vector_elements); + if (swiz != NULL) { + result = swiz; + } else { + /* FINISHME: Logging of error messages should be moved into + * FINISHME: ir_swizzle::create. This allows the generation of more + * FINISHME: specific error messages. + */ + _mesa_glsl_error(& loc, state, "Invalid swizzle / mask `%s'", + expr->primary_expression.identifier); + } + } else if (op->type->base_type == GLSL_TYPE_STRUCT) { + result = new(ctx) ir_dereference_record(op, + expr->primary_expression.identifier); + + if (result->type->is_error()) { + _mesa_glsl_error(& loc, state, "Cannot access field `%s' of " + "structure", + expr->primary_expression.identifier); + } + } else if (expr->subexpressions[1] != NULL) { + /* Handle "method calls" in GLSL 1.20 - namely, array.length() */ + if (state->language_version < 120) + _mesa_glsl_error(&loc, state, "Methods not supported in GLSL 1.10."); + + ast_expression *call = expr->subexpressions[1]; + assert(call->oper == ast_function_call); + + const char *method; + method = call->subexpressions[0]->primary_expression.identifier; + + if (op->type->is_array() && strcmp(method, "length") == 0) { + if (!call->expressions.is_empty()) + _mesa_glsl_error(&loc, state, "length method takes no arguments."); + + if (op->type->array_size() == 0) + _mesa_glsl_error(&loc, state, "length called on unsized array."); + + result = new(ctx) ir_constant(op->type->array_size()); + } else { + _mesa_glsl_error(&loc, state, "Unknown method: `%s'.", method); + } + } else { + _mesa_glsl_error(& loc, state, "Cannot access field `%s' of " + "non-structure / non-vector.", + expr->primary_expression.identifier); + } + + return result ? result : ir_call::get_error_instruction(ctx); +} diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp new file mode 100644 index 0000000000..68ad512bf5 --- /dev/null +++ b/src/glsl/ir.cpp @@ -0,0 +1,1175 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <string.h> +#include "main/core.h" /* for MAX2 */ +#include "ir.h" +#include "ir_visitor.h" +#include "glsl_types.h" + +ir_rvalue::ir_rvalue() +{ + this->type = glsl_type::error_type; +} + +/** + * Modify the swizzle make to move one component to another + * + * \param m IR swizzle to be modified + * \param from Component in the RHS that is to be swizzled + * \param to Desired swizzle location of \c from + */ +static void +update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to) +{ + switch (to) { + case 0: m.x = from; break; + case 1: m.y = from; break; + case 2: m.z = from; break; + case 3: m.w = from; break; + default: assert(!"Should not get here."); + } + + m.num_components = MAX2(m.num_components, (to + 1)); +} + +void +ir_assignment::set_lhs(ir_rvalue *lhs) +{ + while (lhs != NULL) { + ir_swizzle *swiz = lhs->as_swizzle(); + + if (swiz == NULL) + break; + + unsigned write_mask = 0; + ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 }; + + for (unsigned i = 0; i < swiz->mask.num_components; i++) { + unsigned c = 0; + + switch (i) { + case 0: c = swiz->mask.x; break; + case 1: c = swiz->mask.y; break; + case 2: c = swiz->mask.z; break; + case 3: c = swiz->mask.w; break; + default: assert(!"Should not get here."); + } + + write_mask |= (((this->write_mask >> i) & 1) << c); + update_rhs_swizzle(rhs_swiz, i, c); + } + + this->write_mask = write_mask; + lhs = swiz->val; + + this->rhs = new(this) ir_swizzle(this->rhs, rhs_swiz); + } + + assert((lhs == NULL) || lhs->as_dereference()); + + this->lhs = (ir_dereference *) lhs; +} + +ir_variable * +ir_assignment::whole_variable_written() +{ + ir_variable *v = this->lhs->whole_variable_referenced(); + + if (v == NULL) + return NULL; + + if (v->type->is_scalar()) + return v; + + if (v->type->is_vector()) { + const unsigned mask = (1U << v->type->vector_elements) - 1; + + if (mask != this->write_mask) + return NULL; + } + + /* Either all the vector components are assigned or the variable is some + * composite type (and the whole thing is assigned. + */ + return v; +} + +ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, + ir_rvalue *condition, unsigned write_mask) +{ + this->ir_type = ir_type_assignment; + this->condition = condition; + this->rhs = rhs; + this->lhs = lhs; + this->write_mask = write_mask; +} + +ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, + ir_rvalue *condition) +{ + this->ir_type = ir_type_assignment; + this->condition = condition; + this->rhs = rhs; + + /* If the RHS is a vector type, assume that all components of the vector + * type are being written to the LHS. The write mask comes from the RHS + * because we can have a case where the LHS is a vec4 and the RHS is a + * vec3. In that case, the assignment is: + * + * (assign (...) (xyz) (var_ref lhs) (var_ref rhs)) + */ + if (rhs->type->is_vector()) + this->write_mask = (1U << rhs->type->vector_elements) - 1; + else if (rhs->type->is_scalar()) + this->write_mask = 1; + else + this->write_mask = 0; + + this->set_lhs(lhs); +} + + +ir_expression::ir_expression(int op, const struct glsl_type *type, + ir_rvalue *op0, ir_rvalue *op1) +{ + this->ir_type = ir_type_expression; + this->type = type; + this->operation = ir_expression_operation(op); + this->operands[0] = op0; + this->operands[1] = op1; +} + +unsigned int +ir_expression::get_num_operands(ir_expression_operation op) +{ +/* Update ir_print_visitor.cpp when updating this list. */ + const int num_operands[] = { + 1, /* ir_unop_bit_not */ + 1, /* ir_unop_logic_not */ + 1, /* ir_unop_neg */ + 1, /* ir_unop_abs */ + 1, /* ir_unop_sign */ + 1, /* ir_unop_rcp */ + 1, /* ir_unop_rsq */ + 1, /* ir_unop_sqrt */ + 1, /* ir_unop_exp */ + 1, /* ir_unop_log */ + 1, /* ir_unop_exp2 */ + 1, /* ir_unop_log2 */ + 1, /* ir_unop_f2i */ + 1, /* ir_unop_i2f */ + 1, /* ir_unop_f2b */ + 1, /* ir_unop_b2f */ + 1, /* ir_unop_i2b */ + 1, /* ir_unop_b2i */ + 1, /* ir_unop_u2f */ + 1, /* ir_unop_any */ + + 1, /* ir_unop_trunc */ + 1, /* ir_unop_ceil */ + 1, /* ir_unop_floor */ + 1, /* ir_unop_fract */ + + 1, /* ir_unop_sin */ + 1, /* ir_unop_cos */ + + 1, /* ir_unop_dFdx */ + 1, /* ir_unop_dFdy */ + + 2, /* ir_binop_add */ + 2, /* ir_binop_sub */ + 2, /* ir_binop_mul */ + 2, /* ir_binop_div */ + 2, /* ir_binop_mod */ + + 2, /* ir_binop_less */ + 2, /* ir_binop_greater */ + 2, /* ir_binop_lequal */ + 2, /* ir_binop_gequal */ + 2, /* ir_binop_equal */ + 2, /* ir_binop_nequal */ + + 2, /* ir_binop_lshift */ + 2, /* ir_binop_rshift */ + 2, /* ir_binop_bit_and */ + 2, /* ir_binop_bit_xor */ + 2, /* ir_binop_bit_or */ + + 2, /* ir_binop_logic_and */ + 2, /* ir_binop_logic_xor */ + 2, /* ir_binop_logic_or */ + + 2, /* ir_binop_dot */ + 2, /* ir_binop_cross */ + 2, /* ir_binop_min */ + 2, /* ir_binop_max */ + + 2, /* ir_binop_pow */ + }; + + assert(sizeof(num_operands) / sizeof(num_operands[0]) == ir_binop_pow + 1); + + return num_operands[op]; +} + +static const char *const operator_strs[] = { + "~", + "!", + "neg", + "abs", + "sign", + "rcp", + "rsq", + "sqrt", + "exp", + "log", + "exp2", + "log2", + "f2i", + "i2f", + "f2b", + "b2f", + "i2b", + "b2i", + "u2f", + "any", + "trunc", + "ceil", + "floor", + "fract", + "sin", + "cos", + "dFdx", + "dFdy", + "+", + "-", + "*", + "/", + "%", + "<", + ">", + "<=", + ">=", + "==", + "!=", + "<<", + ">>", + "&", + "^", + "|", + "&&", + "^^", + "||", + "dot", + "cross", + "min", + "max", + "pow", +}; + +const char *ir_expression::operator_string() +{ + assert((unsigned int) operation <= + sizeof(operator_strs) / sizeof(operator_strs[0])); + return operator_strs[operation]; +} + +ir_expression_operation +ir_expression::get_operator(const char *str) +{ + const int operator_count = sizeof(operator_strs) / sizeof(operator_strs[0]); + for (int op = 0; op < operator_count; op++) { + if (strcmp(str, operator_strs[op]) == 0) + return (ir_expression_operation) op; + } + return (ir_expression_operation) -1; +} + +ir_constant::ir_constant() +{ + this->ir_type = ir_type_constant; +} + +ir_constant::ir_constant(const struct glsl_type *type, + const ir_constant_data *data) +{ + assert((type->base_type >= GLSL_TYPE_UINT) + && (type->base_type <= GLSL_TYPE_BOOL)); + + this->ir_type = ir_type_constant; + this->type = type; + memcpy(& this->value, data, sizeof(this->value)); +} + +ir_constant::ir_constant(float f) +{ + this->ir_type = ir_type_constant; + this->type = glsl_type::float_type; + this->value.f[0] = f; + for (int i = 1; i < 16; i++) { + this->value.f[i] = 0; + } +} + +ir_constant::ir_constant(unsigned int u) +{ + this->ir_type = ir_type_constant; + this->type = glsl_type::uint_type; + this->value.u[0] = u; + for (int i = 1; i < 16; i++) { + this->value.u[i] = 0; + } +} + +ir_constant::ir_constant(int i) +{ + this->ir_type = ir_type_constant; + this->type = glsl_type::int_type; + this->value.i[0] = i; + for (int i = 1; i < 16; i++) { + this->value.i[i] = 0; + } +} + +ir_constant::ir_constant(bool b) +{ + this->ir_type = ir_type_constant; + this->type = glsl_type::bool_type; + this->value.b[0] = b; + for (int i = 1; i < 16; i++) { + this->value.b[i] = false; + } +} + +ir_constant::ir_constant(const ir_constant *c, unsigned i) +{ + this->ir_type = ir_type_constant; + this->type = c->type->get_base_type(); + + switch (this->type->base_type) { + case GLSL_TYPE_UINT: this->value.u[0] = c->value.u[i]; break; + case GLSL_TYPE_INT: this->value.i[0] = c->value.i[i]; break; + case GLSL_TYPE_FLOAT: this->value.f[0] = c->value.f[i]; break; + case GLSL_TYPE_BOOL: this->value.b[0] = c->value.b[i]; break; + default: assert(!"Should not get here."); break; + } +} + +ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list) +{ + this->ir_type = ir_type_constant; + this->type = type; + + assert(type->is_scalar() || type->is_vector() || type->is_matrix() + || type->is_record() || type->is_array()); + + if (type->is_array()) { + this->array_elements = talloc_array(this, ir_constant *, type->length); + unsigned i = 0; + foreach_list(node, value_list) { + ir_constant *value = (ir_constant *) node; + assert(value->as_constant() != NULL); + + this->array_elements[i++] = value; + } + return; + } + + /* If the constant is a record, the types of each of the entries in + * value_list must be a 1-for-1 match with the structure components. Each + * entry must also be a constant. Just move the nodes from the value_list + * to the list in the ir_constant. + */ + /* FINISHME: Should there be some type checking and / or assertions here? */ + /* FINISHME: Should the new constant take ownership of the nodes from + * FINISHME: value_list, or should it make copies? + */ + if (type->is_record()) { + value_list->move_nodes_to(& this->components); + return; + } + + for (unsigned i = 0; i < 16; i++) { + this->value.u[i] = 0; + } + + ir_constant *value = (ir_constant *) (value_list->head); + + /* Constructors with exactly one scalar argument are special for vectors + * and matrices. For vectors, the scalar value is replicated to fill all + * the components. For matrices, the scalar fills the components of the + * diagonal while the rest is filled with 0. + */ + if (value->type->is_scalar() && value->next->is_tail_sentinel()) { + if (type->is_matrix()) { + /* Matrix - fill diagonal (rest is already set to 0) */ + assert(type->base_type == GLSL_TYPE_FLOAT); + for (unsigned i = 0; i < type->matrix_columns; i++) + this->value.f[i * type->vector_elements + i] = value->value.f[0]; + } else { + /* Vector or scalar - fill all components */ + switch (type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + for (unsigned i = 0; i < type->components(); i++) + this->value.u[i] = value->value.u[0]; + break; + case GLSL_TYPE_FLOAT: + for (unsigned i = 0; i < type->components(); i++) + this->value.f[i] = value->value.f[0]; + break; + case GLSL_TYPE_BOOL: + for (unsigned i = 0; i < type->components(); i++) + this->value.b[i] = value->value.b[0]; + break; + default: + assert(!"Should not get here."); + break; + } + } + return; + } + + if (type->is_matrix() && value->type->is_matrix()) { + assert(value->next->is_tail_sentinel()); + + /* From section 5.4.2 of the GLSL 1.20 spec: + * "If a matrix is constructed from a matrix, then each component + * (column i, row j) in the result that has a corresponding component + * (column i, row j) in the argument will be initialized from there." + */ + unsigned cols = MIN2(type->matrix_columns, value->type->matrix_columns); + unsigned rows = MIN2(type->vector_elements, value->type->vector_elements); + for (unsigned i = 0; i < cols; i++) { + for (unsigned j = 0; j < rows; j++) { + const unsigned src = i * value->type->vector_elements + j; + const unsigned dst = i * type->vector_elements + j; + this->value.f[dst] = value->value.f[src]; + } + } + + /* "All other components will be initialized to the identity matrix." */ + for (unsigned i = cols; i < type->matrix_columns; i++) + this->value.f[i * type->vector_elements + i] = 1.0; + + return; + } + + /* Use each component from each entry in the value_list to initialize one + * component of the constant being constructed. + */ + for (unsigned i = 0; i < type->components(); /* empty */) { + assert(value->as_constant() != NULL); + assert(!value->is_tail_sentinel()); + + for (unsigned j = 0; j < value->type->components(); j++) { + switch (type->base_type) { + case GLSL_TYPE_UINT: + this->value.u[i] = value->get_uint_component(j); + break; + case GLSL_TYPE_INT: + this->value.i[i] = value->get_int_component(j); + break; + case GLSL_TYPE_FLOAT: + this->value.f[i] = value->get_float_component(j); + break; + case GLSL_TYPE_BOOL: + this->value.b[i] = value->get_bool_component(j); + break; + default: + /* FINISHME: What to do? Exceptions are not the answer. + */ + break; + } + + i++; + if (i >= type->components()) + break; + } + + value = (ir_constant *) value->next; + } +} + +ir_constant * +ir_constant::zero(void *mem_ctx, const glsl_type *type) +{ + assert(type->is_numeric() || type->is_boolean()); + + ir_constant *c = new(mem_ctx) ir_constant; + c->type = type; + memset(&c->value, 0, sizeof(c->value)); + + return c; +} + +bool +ir_constant::get_bool_component(unsigned i) const +{ + switch (this->type->base_type) { + case GLSL_TYPE_UINT: return this->value.u[i] != 0; + case GLSL_TYPE_INT: return this->value.i[i] != 0; + case GLSL_TYPE_FLOAT: return ((int)this->value.f[i]) != 0; + case GLSL_TYPE_BOOL: return this->value.b[i]; + default: assert(!"Should not get here."); break; + } + + /* Must return something to make the compiler happy. This is clearly an + * error case. + */ + return false; +} + +float +ir_constant::get_float_component(unsigned i) const +{ + switch (this->type->base_type) { + case GLSL_TYPE_UINT: return (float) this->value.u[i]; + case GLSL_TYPE_INT: return (float) this->value.i[i]; + case GLSL_TYPE_FLOAT: return this->value.f[i]; + case GLSL_TYPE_BOOL: return this->value.b[i] ? 1.0 : 0.0; + default: assert(!"Should not get here."); break; + } + + /* Must return something to make the compiler happy. This is clearly an + * error case. + */ + return 0.0; +} + +int +ir_constant::get_int_component(unsigned i) const +{ + switch (this->type->base_type) { + case GLSL_TYPE_UINT: return this->value.u[i]; + case GLSL_TYPE_INT: return this->value.i[i]; + case GLSL_TYPE_FLOAT: return (int) this->value.f[i]; + case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0; + default: assert(!"Should not get here."); break; + } + + /* Must return something to make the compiler happy. This is clearly an + * error case. + */ + return 0; +} + +unsigned +ir_constant::get_uint_component(unsigned i) const +{ + switch (this->type->base_type) { + case GLSL_TYPE_UINT: return this->value.u[i]; + case GLSL_TYPE_INT: return this->value.i[i]; + case GLSL_TYPE_FLOAT: return (unsigned) this->value.f[i]; + case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0; + default: assert(!"Should not get here."); break; + } + + /* Must return something to make the compiler happy. This is clearly an + * error case. + */ + return 0; +} + +ir_constant * +ir_constant::get_array_element(unsigned i) const +{ + assert(this->type->is_array()); + + /* From page 35 (page 41 of the PDF) of the GLSL 1.20 spec: + * + * "Behavior is undefined if a shader subscripts an array with an index + * less than 0 or greater than or equal to the size the array was + * declared with." + * + * Most out-of-bounds accesses are removed before things could get this far. + * There are cases where non-constant array index values can get constant + * folded. + */ + if (int(i) < 0) + i = 0; + else if (i >= this->type->length) + i = this->type->length - 1; + + return array_elements[i]; +} + +ir_constant * +ir_constant::get_record_field(const char *name) +{ + int idx = this->type->field_index(name); + + if (idx < 0) + return NULL; + + if (this->components.is_empty()) + return NULL; + + exec_node *node = this->components.head; + for (int i = 0; i < idx; i++) { + node = node->next; + + /* If the end of the list is encountered before the element matching the + * requested field is found, return NULL. + */ + if (node->is_tail_sentinel()) + return NULL; + } + + return (ir_constant *) node; +} + + +bool +ir_constant::has_value(const ir_constant *c) const +{ + if (this->type != c->type) + return false; + + if (this->type->is_array()) { + for (unsigned i = 0; i < this->type->length; i++) { + if (this->array_elements[i]->has_value(c->array_elements[i])) + return false; + } + return true; + } + + if (this->type->base_type == GLSL_TYPE_STRUCT) { + const exec_node *a_node = this->components.head; + const exec_node *b_node = c->components.head; + + while (!a_node->is_tail_sentinel()) { + assert(!b_node->is_tail_sentinel()); + + const ir_constant *const a_field = (ir_constant *) a_node; + const ir_constant *const b_field = (ir_constant *) b_node; + + if (!a_field->has_value(b_field)) + return false; + + a_node = a_node->next; + b_node = b_node->next; + } + + return true; + } + + for (unsigned i = 0; i < this->type->components(); i++) { + switch (this->type->base_type) { + case GLSL_TYPE_UINT: + if (this->value.u[i] != c->value.u[i]) + return false; + break; + case GLSL_TYPE_INT: + if (this->value.i[i] != c->value.i[i]) + return false; + break; + case GLSL_TYPE_FLOAT: + if (this->value.f[i] != c->value.f[i]) + return false; + break; + case GLSL_TYPE_BOOL: + if (this->value.b[i] != c->value.b[i]) + return false; + break; + default: + assert(!"Should not get here."); + return false; + } + } + + return true; +} + +ir_dereference_variable::ir_dereference_variable(ir_variable *var) +{ + this->ir_type = ir_type_dereference_variable; + this->var = var; + this->type = (var != NULL) ? var->type : glsl_type::error_type; +} + + +ir_dereference_array::ir_dereference_array(ir_rvalue *value, + ir_rvalue *array_index) +{ + this->ir_type = ir_type_dereference_array; + this->array_index = array_index; + this->set_array(value); +} + + +ir_dereference_array::ir_dereference_array(ir_variable *var, + ir_rvalue *array_index) +{ + void *ctx = talloc_parent(var); + + this->ir_type = ir_type_dereference_array; + this->array_index = array_index; + this->set_array(new(ctx) ir_dereference_variable(var)); +} + + +void +ir_dereference_array::set_array(ir_rvalue *value) +{ + this->array = value; + this->type = glsl_type::error_type; + + if (this->array != NULL) { + const glsl_type *const vt = this->array->type; + + if (vt->is_array()) { + type = vt->element_type(); + } else if (vt->is_matrix()) { + type = vt->column_type(); + } else if (vt->is_vector()) { + type = vt->get_base_type(); + } + } +} + + +ir_dereference_record::ir_dereference_record(ir_rvalue *value, + const char *field) +{ + this->ir_type = ir_type_dereference_record; + this->record = value; + this->field = talloc_strdup(this, field); + this->type = (this->record != NULL) + ? this->record->type->field_type(field) : glsl_type::error_type; +} + + +ir_dereference_record::ir_dereference_record(ir_variable *var, + const char *field) +{ + void *ctx = talloc_parent(var); + + this->ir_type = ir_type_dereference_record; + this->record = new(ctx) ir_dereference_variable(var); + this->field = talloc_strdup(this, field); + this->type = (this->record != NULL) + ? this->record->type->field_type(field) : glsl_type::error_type; +} + +bool type_contains_sampler(const glsl_type *type) +{ + if (type->is_array()) { + return type_contains_sampler(type->fields.array); + } else if (type->is_record()) { + for (unsigned int i = 0; i < type->length; i++) { + if (type_contains_sampler(type->fields.structure[i].type)) + return true; + } + return false; + } else { + return type->is_sampler(); + } +} + +bool +ir_dereference::is_lvalue() +{ + ir_variable *var = this->variable_referenced(); + + /* Every l-value derference chain eventually ends in a variable. + */ + if ((var == NULL) || var->read_only) + return false; + + if (this->type->is_array() && !var->array_lvalue) + return false; + + /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec: + * + * "Samplers cannot be treated as l-values; hence cannot be used + * as out or inout function parameters, nor can they be + * assigned into." + */ + if (type_contains_sampler(this->type)) + return false; + + return true; +} + + +const char *tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf" }; + +const char *ir_texture::opcode_string() +{ + assert((unsigned int) op <= + sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0])); + return tex_opcode_strs[op]; +} + +ir_texture_opcode +ir_texture::get_opcode(const char *str) +{ + const int count = sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]); + for (int op = 0; op < count; op++) { + if (strcmp(str, tex_opcode_strs[op]) == 0) + return (ir_texture_opcode) op; + } + return (ir_texture_opcode) -1; +} + + +void +ir_texture::set_sampler(ir_dereference *sampler) +{ + assert(sampler != NULL); + this->sampler = sampler; + + switch (sampler->type->sampler_type) { + case GLSL_TYPE_FLOAT: + this->type = glsl_type::vec4_type; + break; + case GLSL_TYPE_INT: + this->type = glsl_type::ivec4_type; + break; + case GLSL_TYPE_UINT: + this->type = glsl_type::uvec4_type; + break; + } +} + + +void +ir_swizzle::init_mask(const unsigned *comp, unsigned count) +{ + assert((count >= 1) && (count <= 4)); + + memset(&this->mask, 0, sizeof(this->mask)); + this->mask.num_components = count; + + unsigned dup_mask = 0; + switch (count) { + case 4: + assert(comp[3] <= 3); + dup_mask |= (1U << comp[3]) + & ((1U << comp[0]) | (1U << comp[1]) | (1U << comp[2])); + this->mask.w = comp[3]; + + case 3: + assert(comp[2] <= 3); + dup_mask |= (1U << comp[2]) + & ((1U << comp[0]) | (1U << comp[1])); + this->mask.z = comp[2]; + + case 2: + assert(comp[1] <= 3); + dup_mask |= (1U << comp[1]) + & ((1U << comp[0])); + this->mask.y = comp[1]; + + case 1: + assert(comp[0] <= 3); + this->mask.x = comp[0]; + } + + this->mask.has_duplicates = dup_mask != 0; + + /* Based on the number of elements in the swizzle and the base type + * (i.e., float, int, unsigned, or bool) of the vector being swizzled, + * generate the type of the resulting value. + */ + type = glsl_type::get_instance(val->type->base_type, mask.num_components, 1); +} + +ir_swizzle::ir_swizzle(ir_rvalue *val, unsigned x, unsigned y, unsigned z, + unsigned w, unsigned count) + : val(val) +{ + const unsigned components[4] = { x, y, z, w }; + this->ir_type = ir_type_swizzle; + this->init_mask(components, count); +} + +ir_swizzle::ir_swizzle(ir_rvalue *val, const unsigned *comp, + unsigned count) + : val(val) +{ + this->ir_type = ir_type_swizzle; + this->init_mask(comp, count); +} + +ir_swizzle::ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask) +{ + this->ir_type = ir_type_swizzle; + this->val = val; + this->mask = mask; + this->type = glsl_type::get_instance(val->type->base_type, + mask.num_components, 1); +} + +#define X 1 +#define R 5 +#define S 9 +#define I 13 + +ir_swizzle * +ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length) +{ + void *ctx = talloc_parent(val); + + /* For each possible swizzle character, this table encodes the value in + * \c idx_map that represents the 0th element of the vector. For invalid + * swizzle characters (e.g., 'k'), a special value is used that will allow + * detection of errors. + */ + static const unsigned char base_idx[26] = { + /* a b c d e f g h i j k l m */ + R, R, I, I, I, I, R, I, I, I, I, I, I, + /* n o p q r s t u v w x y z */ + I, I, S, S, R, S, S, I, I, X, X, X, X + }; + + /* Each valid swizzle character has an entry in the previous table. This + * table encodes the base index encoded in the previous table plus the actual + * index of the swizzle character. When processing swizzles, the first + * character in the string is indexed in the previous table. Each character + * in the string is indexed in this table, and the value found there has the + * value form the first table subtracted. The result must be on the range + * [0,3]. + * + * For example, the string "wzyx" will get X from the first table. Each of + * the charcaters will get X+3, X+2, X+1, and X+0 from this table. After + * subtraction, the swizzle values are { 3, 2, 1, 0 }. + * + * The string "wzrg" will get X from the first table. Each of the characters + * will get X+3, X+2, R+0, and R+1 from this table. After subtraction, the + * swizzle values are { 3, 2, 4, 5 }. Since 4 and 5 are outside the range + * [0,3], the error is detected. + */ + static const unsigned char idx_map[26] = { + /* a b c d e f g h i j k l m */ + R+3, R+2, 0, 0, 0, 0, R+1, 0, 0, 0, 0, 0, 0, + /* n o p q r s t u v w x y z */ + 0, 0, S+2, S+3, R+0, S+0, S+1, 0, 0, X+3, X+0, X+1, X+2 + }; + + int swiz_idx[4] = { 0, 0, 0, 0 }; + unsigned i; + + + /* Validate the first character in the swizzle string and look up the base + * index value as described above. + */ + if ((str[0] < 'a') || (str[0] > 'z')) + return NULL; + + const unsigned base = base_idx[str[0] - 'a']; + + + for (i = 0; (i < 4) && (str[i] != '\0'); i++) { + /* Validate the next character, and, as described above, convert it to a + * swizzle index. + */ + if ((str[i] < 'a') || (str[i] > 'z')) + return NULL; + + swiz_idx[i] = idx_map[str[i] - 'a'] - base; + if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length)) + return NULL; + } + + if (str[i] != '\0') + return NULL; + + return new(ctx) ir_swizzle(val, swiz_idx[0], swiz_idx[1], swiz_idx[2], + swiz_idx[3], i); +} + +#undef X +#undef R +#undef S +#undef I + +ir_variable * +ir_swizzle::variable_referenced() +{ + return this->val->variable_referenced(); +} + + +ir_variable::ir_variable(const struct glsl_type *type, const char *name, + ir_variable_mode mode) + : max_array_access(0), read_only(false), centroid(false), invariant(false), + mode(mode), interpolation(ir_var_smooth), array_lvalue(false) +{ + this->ir_type = ir_type_variable; + this->type = type; + this->name = talloc_strdup(this, name); + this->location = -1; + this->warn_extension = NULL; + this->constant_value = NULL; + this->origin_upper_left = false; + this->pixel_center_integer = false; + + if (type && type->base_type == GLSL_TYPE_SAMPLER) + this->read_only = true; +} + + +const char * +ir_variable::interpolation_string() const +{ + switch (this->interpolation) { + case ir_var_smooth: return "smooth"; + case ir_var_flat: return "flat"; + case ir_var_noperspective: return "noperspective"; + } + + assert(!"Should not get here."); + return ""; +} + + +unsigned +ir_variable::component_slots() const +{ + /* FINISHME: Sparsely accessed arrays require fewer slots. */ + return this->type->component_slots(); +} + + +ir_function_signature::ir_function_signature(const glsl_type *return_type) + : return_type(return_type), is_defined(false), _function(NULL) +{ + this->ir_type = ir_type_function_signature; +} + + +const char * +ir_function_signature::qualifiers_match(exec_list *params) +{ + exec_list_iterator iter_a = parameters.iterator(); + exec_list_iterator iter_b = params->iterator(); + + /* check that the qualifiers match. */ + while (iter_a.has_next()) { + ir_variable *a = (ir_variable *)iter_a.get(); + ir_variable *b = (ir_variable *)iter_b.get(); + + if (a->read_only != b->read_only || + a->mode != b->mode || + a->interpolation != b->interpolation || + a->centroid != b->centroid) { + + /* parameter a's qualifiers don't match */ + return a->name; + } + + iter_a.next(); + iter_b.next(); + } + return NULL; +} + + +void +ir_function_signature::replace_parameters(exec_list *new_params) +{ + /* Destroy all of the previous parameter information. If the previous + * parameter information comes from the function prototype, it may either + * specify incorrect parameter names or not have names at all. + */ + foreach_iter(exec_list_iterator, iter, parameters) { + assert(((ir_instruction *) iter.get())->as_variable() != NULL); + + iter.remove(); + } + + new_params->move_nodes_to(¶meters); +} + + +ir_function::ir_function(const char *name) +{ + this->ir_type = ir_type_function; + this->name = talloc_strdup(this, name); + this->is_builtin = false; +} + + +ir_call * +ir_call::get_error_instruction(void *ctx) +{ + ir_call *call = new(ctx) ir_call; + + call->type = glsl_type::error_type; + return call; +} + +void +ir_call::set_callee(ir_function_signature *sig) +{ + assert((this->type == NULL) || (this->type == sig->return_type)); + + this->callee = sig; +} + +void +visit_exec_list(exec_list *list, ir_visitor *visitor) +{ + foreach_iter(exec_list_iterator, iter, *list) { + ((ir_instruction *)iter.get())->accept(visitor); + } +} + + +static void +steal_memory(ir_instruction *ir, void *new_ctx) +{ + ir_variable *var = ir->as_variable(); + ir_constant *constant = ir->as_constant(); + if (var != NULL && var->constant_value != NULL) + steal_memory(var->constant_value, ir); + + /* The components of aggregate constants are not visited by the normal + * visitor, so steal their values by hand. + */ + if (constant != NULL) { + if (constant->type->is_record()) { + foreach_iter(exec_list_iterator, iter, constant->components) { + ir_constant *field = (ir_constant *)iter.get(); + steal_memory(field, ir); + } + } else if (constant->type->is_array()) { + for (unsigned int i = 0; i < constant->type->length; i++) { + steal_memory(constant->array_elements[i], ir); + } + } + } + + talloc_steal(new_ctx, ir); +} + + +void +reparent_ir(exec_list *list, void *mem_ctx) +{ + foreach_list(node, list) { + visit_tree((ir_instruction *) node, steal_memory, mem_ctx); + } +} diff --git a/src/glsl/ir.h b/src/glsl/ir.h new file mode 100644 index 0000000000..0f887a9327 --- /dev/null +++ b/src/glsl/ir.h @@ -0,0 +1,1399 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef IR_H +#define IR_H + +#include <cstdio> +#include <cstdlib> + +extern "C" { +#include <talloc.h> +} + +#include "list.h" +#include "ir_visitor.h" +#include "ir_hierarchical_visitor.h" + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +enum ir_node_type { + ir_type_unset, + ir_type_variable, + ir_type_assignment, + ir_type_call, + ir_type_constant, + ir_type_dereference_array, + ir_type_dereference_record, + ir_type_dereference_variable, + ir_type_discard, + ir_type_expression, + ir_type_function, + ir_type_function_signature, + ir_type_if, + ir_type_loop, + ir_type_loop_jump, + ir_type_return, + ir_type_swizzle, + ir_type_texture, + ir_type_max /**< maximum ir_type enum number, for validation */ +}; + +/** + * Base class of all IR instructions + */ +class ir_instruction : public exec_node { +public: + enum ir_node_type ir_type; + const struct glsl_type *type; + + /** ir_print_visitor helper for debugging. */ + void print(void) const; + + virtual void accept(ir_visitor *) = 0; + virtual ir_visitor_status accept(ir_hierarchical_visitor *) = 0; + virtual ir_instruction *clone(void *mem_ctx, + struct hash_table *ht) const = 0; + + /** + * \name IR instruction downcast functions + * + * These functions either cast the object to a derived class or return + * \c NULL if the object's type does not match the specified derived class. + * Additional downcast functions will be added as needed. + */ + /*@{*/ + virtual class ir_variable * as_variable() { return NULL; } + virtual class ir_function * as_function() { return NULL; } + virtual class ir_dereference * as_dereference() { return NULL; } + virtual class ir_dereference_array * as_dereference_array() { return NULL; } + virtual class ir_dereference_variable *as_dereference_variable() { return NULL; } + virtual class ir_expression * as_expression() { return NULL; } + virtual class ir_rvalue * as_rvalue() { return NULL; } + virtual class ir_loop * as_loop() { return NULL; } + virtual class ir_assignment * as_assignment() { return NULL; } + virtual class ir_call * as_call() { return NULL; } + virtual class ir_return * as_return() { return NULL; } + virtual class ir_if * as_if() { return NULL; } + virtual class ir_swizzle * as_swizzle() { return NULL; } + virtual class ir_constant * as_constant() { return NULL; } + /*@}*/ + +protected: + ir_instruction() + { + ir_type = ir_type_unset; + type = NULL; + } +}; + + +class ir_rvalue : public ir_instruction { +public: + virtual ir_rvalue *clone(void *mem_ctx, struct hash_table *) const = 0; + + virtual ir_constant *constant_expression_value() = 0; + + virtual ir_rvalue * as_rvalue() + { + return this; + } + + virtual bool is_lvalue() + { + return false; + } + + /** + * Get the variable that is ultimately referenced by an r-value + */ + virtual ir_variable *variable_referenced() + { + return NULL; + } + + + /** + * If an r-value is a reference to a whole variable, get that variable + * + * \return + * Pointer to a variable that is completely dereferenced by the r-value. If + * the r-value is not a dereference or the dereference does not access the + * entire variable (i.e., it's just one array element, struct field), \c NULL + * is returned. + */ + virtual ir_variable *whole_variable_referenced() + { + return NULL; + } + +protected: + ir_rvalue(); +}; + + +enum ir_variable_mode { + ir_var_auto = 0, + ir_var_uniform, + ir_var_in, + ir_var_out, + ir_var_inout, + ir_var_temporary /**< Temporary variable generated during compilation. */ +}; + +enum ir_variable_interpolation { + ir_var_smooth = 0, + ir_var_flat, + ir_var_noperspective +}; + + +class ir_variable : public ir_instruction { +public: + ir_variable(const struct glsl_type *, const char *, ir_variable_mode); + + virtual ir_variable *clone(void *mem_ctx, struct hash_table *ht) const; + + virtual ir_variable *as_variable() + { + return this; + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + + /** + * Get the string value for the interpolation qualifier + * + * \return The string that would be used in a shader to specify \c + * mode will be returned. + * + * This function should only be used on a shader input or output variable. + */ + const char *interpolation_string() const; + + /** + * Calculate the number of slots required to hold this variable + * + * This is used to determine how many uniform or varying locations a variable + * occupies. The count is in units of floating point components. + */ + unsigned component_slots() const; + + const char *name; + + /** + * Highest element accessed with a constant expression array index + * + * Not used for non-array variables. + */ + unsigned max_array_access; + + unsigned read_only:1; + unsigned centroid:1; + unsigned invariant:1; + + unsigned mode:3; + unsigned interpolation:2; + + /** + * Flag that the whole array is assignable + * + * In GLSL 1.20 and later whole arrays are assignable (and comparable for + * equality). This flag enables this behavior. + */ + unsigned array_lvalue:1; + + /* ARB_fragment_coord_conventions */ + unsigned origin_upper_left:1; + unsigned pixel_center_integer:1; + + /** + * Storage location of the base of this variable + * + * The precise meaning of this field depends on the nature of the variable. + * + * - Vertex shader input: one of the values from \c gl_vert_attrib. + * - Vertex shader output: one of the values from \c gl_vert_result. + * - Fragment shader input: one of the values from \c gl_frag_attrib. + * - Fragment shader output: one of the values from \c gl_frag_result. + * - Uniforms: Per-stage uniform slot number. + * - Other: This field is not currently used. + * + * If the variable is a uniform, shader input, or shader output, and the + * slot has not been assigned, the value will be -1. + */ + int location; + + /** + * Emit a warning if this variable is accessed. + */ + const char *warn_extension; + + /** + * Value assigned in the initializer of a variable declared "const" + */ + ir_constant *constant_value; +}; + + +/*@{*/ +/** + * The representation of a function instance; may be the full definition or + * simply a prototype. + */ +class ir_function_signature : public ir_instruction { + /* An ir_function_signature will be part of the list of signatures in + * an ir_function. + */ +public: + ir_function_signature(const glsl_type *return_type); + + virtual ir_function_signature *clone(void *mem_ctx, + struct hash_table *ht) const; + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + /** + * Get the name of the function for which this is a signature + */ + const char *function_name() const; + + /** + * Get a handle to the function for which this is a signature + * + * There is no setter function, this function returns a \c const pointer, + * and \c ir_function_signature::_function is private for a reason. The + * only way to make a connection between a function and function signature + * is via \c ir_function::add_signature. This helps ensure that certain + * invariants (i.e., a function signature is in the list of signatures for + * its \c _function) are met. + * + * \sa ir_function::add_signature + */ + inline const class ir_function *function() const + { + return this->_function; + } + + /** + * Check whether the qualifiers match between this signature's parameters + * and the supplied parameter list. If not, returns the name of the first + * parameter with mismatched qualifiers (for use in error messages). + */ + const char *qualifiers_match(exec_list *params); + + /** + * Replace the current parameter list with the given one. This is useful + * if the current information came from a prototype, and either has invalid + * or missing parameter names. + */ + void replace_parameters(exec_list *new_params); + + /** + * Function return type. + * + * \note This discards the optional precision qualifier. + */ + const struct glsl_type *return_type; + + /** + * List of ir_variable of function parameters. + * + * This represents the storage. The paramaters passed in a particular + * call will be in ir_call::actual_paramaters. + */ + struct exec_list parameters; + + /** Whether or not this function has a body (which may be empty). */ + unsigned is_defined:1; + + /** Body of instructions in the function. */ + struct exec_list body; + +private: + /** Function of which this signature is one overload. */ + class ir_function *_function; + + friend class ir_function; +}; + + +/** + * Header for tracking multiple overloaded functions with the same name. + * Contains a list of ir_function_signatures representing each of the + * actual functions. + */ +class ir_function : public ir_instruction { +public: + ir_function(const char *name); + + virtual ir_function *clone(void *mem_ctx, struct hash_table *ht) const; + + virtual ir_function *as_function() + { + return this; + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + void add_signature(ir_function_signature *sig) + { + sig->_function = this; + this->signatures.push_tail(sig); + } + + /** + * Get an iterator for the set of function signatures + */ + exec_list_iterator iterator() + { + return signatures.iterator(); + } + + /** + * Find a signature that matches a set of actual parameters, taking implicit + * conversions into account. + */ + ir_function_signature *matching_signature(const exec_list *actual_param); + + /** + * Find a signature that exactly matches a set of actual parameters without + * any implicit type conversions. + */ + ir_function_signature *exact_matching_signature(const exec_list *actual_ps); + + /** + * Name of the function. + */ + const char *name; + + /** Whether or not this function is a built-in. */ + unsigned is_builtin:1; + + /** + * List of ir_function_signature for each overloaded function with this name. + */ + struct exec_list signatures; +}; + +inline const char *ir_function_signature::function_name() const +{ + return this->_function->name; +} +/*@}*/ + + +/** + * IR instruction representing high-level if-statements + */ +class ir_if : public ir_instruction { +public: + ir_if(ir_rvalue *condition) + : condition(condition) + { + ir_type = ir_type_if; + } + + virtual ir_if *clone(void *mem_ctx, struct hash_table *ht) const; + + virtual ir_if *as_if() + { + return this; + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + ir_rvalue *condition; + /** List of ir_instruction for the body of the then branch */ + exec_list then_instructions; + /** List of ir_instruction for the body of the else branch */ + exec_list else_instructions; +}; + + +/** + * IR instruction representing a high-level loop structure. + */ +class ir_loop : public ir_instruction { +public: + ir_loop() : from(NULL), to(NULL), increment(NULL), counter(NULL) + { + ir_type = ir_type_loop; + } + + virtual ir_loop *clone(void *mem_ctx, struct hash_table *ht) const; + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + virtual ir_loop *as_loop() + { + return this; + } + + /** + * Get an iterator for the instructions of the loop body + */ + exec_list_iterator iterator() + { + return body_instructions.iterator(); + } + + /** List of ir_instruction that make up the body of the loop. */ + exec_list body_instructions; + + /** + * \name Loop counter and controls + */ + /*@{*/ + ir_rvalue *from; + ir_rvalue *to; + ir_rvalue *increment; + ir_variable *counter; + /*@}*/ +}; + + +class ir_assignment : public ir_instruction { +public: + ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, ir_rvalue *condition); + + /** + * Construct an assignment with an explicit write mask + * + * \note + * Since a write mask is supplied, the LHS must already be a bare + * \c ir_dereference. The cannot be any swizzles in the LHS. + */ + ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, ir_rvalue *condition, + unsigned write_mask); + + virtual ir_assignment *clone(void *mem_ctx, struct hash_table *ht) const; + + virtual ir_constant *constant_expression_value(); + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + virtual ir_assignment * as_assignment() + { + return this; + } + + /** + * Get a whole variable written by an assignment + * + * If the LHS of the assignment writes a whole variable, the variable is + * returned. Otherwise \c NULL is returned. Examples of whole-variable + * assignment are: + * + * - Assigning to a scalar + * - Assigning to all components of a vector + * - Whole array (or matrix) assignment + * - Whole structure assignment + */ + ir_variable *whole_variable_written(); + + /** + * Set the LHS of an assignment + */ + void set_lhs(ir_rvalue *lhs); + + /** + * Left-hand side of the assignment. + * + * This should be treated as read only. If you need to set the LHS of an + * assignment, use \c ir_assignment::set_lhs. + */ + ir_dereference *lhs; + + /** + * Value being assigned + */ + ir_rvalue *rhs; + + /** + * Optional condition for the assignment. + */ + ir_rvalue *condition; + + + /** + * Component mask written + * + * For non-vector types in the LHS, this field will be zero. For vector + * types, a bit will be set for each component that is written. Note that + * for \c vec2 and \c vec3 types only the lower bits will ever be set. + */ + unsigned write_mask:4; +}; + +/* Update ir_expression::num_operands() and operator_strs when + * updating this list. + */ +enum ir_expression_operation { + ir_unop_bit_not, + ir_unop_logic_not, + ir_unop_neg, + ir_unop_abs, + ir_unop_sign, + ir_unop_rcp, + ir_unop_rsq, + ir_unop_sqrt, + ir_unop_exp, /**< Log base e on gentype */ + ir_unop_log, /**< Natural log on gentype */ + ir_unop_exp2, + ir_unop_log2, + ir_unop_f2i, /**< Float-to-integer conversion. */ + ir_unop_i2f, /**< Integer-to-float conversion. */ + ir_unop_f2b, /**< Float-to-boolean conversion */ + ir_unop_b2f, /**< Boolean-to-float conversion */ + ir_unop_i2b, /**< int-to-boolean conversion */ + ir_unop_b2i, /**< Boolean-to-int conversion */ + ir_unop_u2f, /**< Unsigned-to-float conversion. */ + ir_unop_any, + + /** + * \name Unary floating-point rounding operations. + */ + /*@{*/ + ir_unop_trunc, + ir_unop_ceil, + ir_unop_floor, + ir_unop_fract, + /*@}*/ + + /** + * \name Trigonometric operations. + */ + /*@{*/ + ir_unop_sin, + ir_unop_cos, + /*@}*/ + + /** + * \name Partial derivatives. + */ + /*@{*/ + ir_unop_dFdx, + ir_unop_dFdy, + /*@}*/ + + ir_binop_add, + ir_binop_sub, + ir_binop_mul, + ir_binop_div, + + /** + * Takes one of two combinations of arguments: + * + * - mod(vecN, vecN) + * - mod(vecN, float) + * + * Does not take integer types. + */ + ir_binop_mod, + + /** + * \name Binary comparison operators + */ + /*@{*/ + ir_binop_less, + ir_binop_greater, + ir_binop_lequal, + ir_binop_gequal, + /** + * Returns single boolean for whether all components of operands[0] + * equal the components of operands[1]. + */ + ir_binop_equal, + /** + * Returns single boolean for whether any component of operands[0] + * is not equal to the corresponding component of operands[1]. + */ + ir_binop_nequal, + /*@}*/ + + /** + * \name Bit-wise binary operations. + */ + /*@{*/ + ir_binop_lshift, + ir_binop_rshift, + ir_binop_bit_and, + ir_binop_bit_xor, + ir_binop_bit_or, + /*@}*/ + + ir_binop_logic_and, + ir_binop_logic_xor, + ir_binop_logic_or, + + ir_binop_dot, + ir_binop_cross, + ir_binop_min, + ir_binop_max, + + ir_binop_pow +}; + +class ir_expression : public ir_rvalue { +public: + ir_expression(int op, const struct glsl_type *type, + ir_rvalue *, ir_rvalue *); + + virtual ir_expression *as_expression() + { + return this; + } + + virtual ir_expression *clone(void *mem_ctx, struct hash_table *ht) const; + + virtual ir_constant *constant_expression_value(); + + static unsigned int get_num_operands(ir_expression_operation); + unsigned int get_num_operands() const + { + return get_num_operands(operation); + } + + /** + * Return a string representing this expression's operator. + */ + const char *operator_string(); + + /** + * Do a reverse-lookup to translate the given string into an operator. + */ + static ir_expression_operation get_operator(const char *); + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + ir_expression_operation operation; + ir_rvalue *operands[2]; +}; + + +/** + * IR instruction representing a function call + */ +class ir_call : public ir_rvalue { +public: + ir_call(ir_function_signature *callee, exec_list *actual_parameters) + : callee(callee) + { + ir_type = ir_type_call; + assert(callee->return_type != NULL); + type = callee->return_type; + actual_parameters->move_nodes_to(& this->actual_parameters); + } + + virtual ir_call *clone(void *mem_ctx, struct hash_table *ht) const; + + virtual ir_constant *constant_expression_value(); + + virtual ir_call *as_call() + { + return this; + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + /** + * Get a generic ir_call object when an error occurs + * + * Any allocation will be performed with 'ctx' as talloc owner. + */ + static ir_call *get_error_instruction(void *ctx); + + /** + * Get an iterator for the set of acutal parameters + */ + exec_list_iterator iterator() + { + return actual_parameters.iterator(); + } + + /** + * Get the name of the function being called. + */ + const char *callee_name() const + { + return callee->function_name(); + } + + ir_function_signature *get_callee() + { + return callee; + } + + /** + * Set the function call target + */ + void set_callee(ir_function_signature *sig); + + /** + * Generates an inline version of the function before @ir, + * returning the return value of the function. + */ + ir_rvalue *generate_inline(ir_instruction *ir); + + /* List of ir_rvalue of paramaters passed in this call. */ + exec_list actual_parameters; + +private: + ir_call() + : callee(NULL) + { + this->ir_type = ir_type_call; + } + + ir_function_signature *callee; +}; + + +/** + * \name Jump-like IR instructions. + * + * These include \c break, \c continue, \c return, and \c discard. + */ +/*@{*/ +class ir_jump : public ir_instruction { +protected: + ir_jump() + { + ir_type = ir_type_unset; + } +}; + +class ir_return : public ir_jump { +public: + ir_return() + : value(NULL) + { + this->ir_type = ir_type_return; + } + + ir_return(ir_rvalue *value) + : value(value) + { + this->ir_type = ir_type_return; + } + + virtual ir_return *clone(void *mem_ctx, struct hash_table *) const; + + virtual ir_return *as_return() + { + return this; + } + + ir_rvalue *get_value() const + { + return value; + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + ir_rvalue *value; +}; + + +/** + * Jump instructions used inside loops + * + * These include \c break and \c continue. The \c break within a loop is + * different from the \c break within a switch-statement. + * + * \sa ir_switch_jump + */ +class ir_loop_jump : public ir_jump { +public: + enum jump_mode { + jump_break, + jump_continue + }; + + ir_loop_jump(jump_mode mode) + { + this->ir_type = ir_type_loop_jump; + this->mode = mode; + this->loop = loop; + } + + virtual ir_loop_jump *clone(void *mem_ctx, struct hash_table *) const; + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + bool is_break() const + { + return mode == jump_break; + } + + bool is_continue() const + { + return mode == jump_continue; + } + + /** Mode selector for the jump instruction. */ + enum jump_mode mode; +private: + /** Loop containing this break instruction. */ + ir_loop *loop; +}; + +/** + * IR instruction representing discard statements. + */ +class ir_discard : public ir_jump { +public: + ir_discard() + { + this->ir_type = ir_type_discard; + this->condition = NULL; + } + + ir_discard(ir_rvalue *cond) + { + this->ir_type = ir_type_discard; + this->condition = cond; + } + + virtual ir_discard *clone(void *mem_ctx, struct hash_table *ht) const; + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + ir_rvalue *condition; +}; +/*@}*/ + + +/** + * Texture sampling opcodes used in ir_texture + */ +enum ir_texture_opcode { + ir_tex, /* Regular texture look-up */ + ir_txb, /* Texture look-up with LOD bias */ + ir_txl, /* Texture look-up with explicit LOD */ + ir_txd, /* Texture look-up with partial derivatvies */ + ir_txf /* Texel fetch with explicit LOD */ +}; + + +/** + * IR instruction to sample a texture + * + * The specific form of the IR instruction depends on the \c mode value + * selected from \c ir_texture_opcodes. In the printed IR, these will + * appear as: + * + * Texel offset + * | Projection divisor + * | | Shadow comparitor + * | | | + * v v v + * (tex (sampler) (coordinate) (0 0 0) (1) ( )) + * (txb (sampler) (coordinate) (0 0 0) (1) ( ) (bias)) + * (txl (sampler) (coordinate) (0 0 0) (1) ( ) (lod)) + * (txd (sampler) (coordinate) (0 0 0) (1) ( ) (dPdx dPdy)) + * (txf (sampler) (coordinate) (0 0 0) (lod)) + */ +class ir_texture : public ir_rvalue { +public: + ir_texture(enum ir_texture_opcode op) + : op(op), projector(NULL), shadow_comparitor(NULL) + { + this->ir_type = ir_type_texture; + } + + virtual ir_texture *clone(void *mem_ctx, struct hash_table *) const; + + virtual ir_constant *constant_expression_value(); + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + /** + * Return a string representing the ir_texture_opcode. + */ + const char *opcode_string(); + + /** Set the sampler and infer the type. */ + void set_sampler(ir_dereference *sampler); + + /** + * Do a reverse-lookup to translate a string into an ir_texture_opcode. + */ + static ir_texture_opcode get_opcode(const char *); + + enum ir_texture_opcode op; + + /** Sampler to use for the texture access. */ + ir_dereference *sampler; + + /** Texture coordinate to sample */ + ir_rvalue *coordinate; + + /** + * Value used for projective divide. + * + * If there is no projective divide (the common case), this will be + * \c NULL. Optimization passes should check for this to point to a constant + * of 1.0 and replace that with \c NULL. + */ + ir_rvalue *projector; + + /** + * Coordinate used for comparison on shadow look-ups. + * + * If there is no shadow comparison, this will be \c NULL. For the + * \c ir_txf opcode, this *must* be \c NULL. + */ + ir_rvalue *shadow_comparitor; + + /** Explicit texel offsets. */ + signed char offsets[3]; + + union { + ir_rvalue *lod; /**< Floating point LOD */ + ir_rvalue *bias; /**< Floating point LOD bias */ + struct { + ir_rvalue *dPdx; /**< Partial derivative of coordinate wrt X */ + ir_rvalue *dPdy; /**< Partial derivative of coordinate wrt Y */ + } grad; + } lod_info; +}; + + +struct ir_swizzle_mask { + unsigned x:2; + unsigned y:2; + unsigned z:2; + unsigned w:2; + + /** + * Number of components in the swizzle. + */ + unsigned num_components:3; + + /** + * Does the swizzle contain duplicate components? + * + * L-value swizzles cannot contain duplicate components. + */ + unsigned has_duplicates:1; +}; + + +class ir_swizzle : public ir_rvalue { +public: + ir_swizzle(ir_rvalue *, unsigned x, unsigned y, unsigned z, unsigned w, + unsigned count); + + ir_swizzle(ir_rvalue *val, const unsigned *components, unsigned count); + + ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask); + + virtual ir_swizzle *clone(void *mem_ctx, struct hash_table *) const; + + virtual ir_constant *constant_expression_value(); + + virtual ir_swizzle *as_swizzle() + { + return this; + } + + /** + * Construct an ir_swizzle from the textual representation. Can fail. + */ + static ir_swizzle *create(ir_rvalue *, const char *, unsigned vector_length); + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + bool is_lvalue() + { + return val->is_lvalue() && !mask.has_duplicates; + } + + /** + * Get the variable that is ultimately referenced by an r-value + */ + virtual ir_variable *variable_referenced(); + + ir_rvalue *val; + ir_swizzle_mask mask; + +private: + /** + * Initialize the mask component of a swizzle + * + * This is used by the \c ir_swizzle constructors. + */ + void init_mask(const unsigned *components, unsigned count); +}; + + +class ir_dereference : public ir_rvalue { +public: + virtual ir_dereference *clone(void *mem_ctx, struct hash_table *) const = 0; + + virtual ir_dereference *as_dereference() + { + return this; + } + + bool is_lvalue(); + + /** + * Get the variable that is ultimately referenced by an r-value + */ + virtual ir_variable *variable_referenced() = 0; +}; + + +class ir_dereference_variable : public ir_dereference { +public: + ir_dereference_variable(ir_variable *var); + + virtual ir_dereference_variable *clone(void *mem_ctx, + struct hash_table *) const; + + virtual ir_constant *constant_expression_value(); + + virtual ir_dereference_variable *as_dereference_variable() + { + return this; + } + + /** + * Get the variable that is ultimately referenced by an r-value + */ + virtual ir_variable *variable_referenced() + { + return this->var; + } + + virtual ir_variable *whole_variable_referenced() + { + /* ir_dereference_variable objects always dereference the entire + * variable. However, if this dereference is dereferenced by anything + * else, the complete deferefernce chain is not a whole-variable + * dereference. This method should only be called on the top most + * ir_rvalue in a dereference chain. + */ + return this->var; + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + /** + * Object being dereferenced. + */ + ir_variable *var; +}; + + +class ir_dereference_array : public ir_dereference { +public: + ir_dereference_array(ir_rvalue *value, ir_rvalue *array_index); + + ir_dereference_array(ir_variable *var, ir_rvalue *array_index); + + virtual ir_dereference_array *clone(void *mem_ctx, + struct hash_table *) const; + + virtual ir_constant *constant_expression_value(); + + virtual ir_dereference_array *as_dereference_array() + { + return this; + } + + /** + * Get the variable that is ultimately referenced by an r-value + */ + virtual ir_variable *variable_referenced() + { + return this->array->variable_referenced(); + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + ir_rvalue *array; + ir_rvalue *array_index; + +private: + void set_array(ir_rvalue *value); +}; + + +class ir_dereference_record : public ir_dereference { +public: + ir_dereference_record(ir_rvalue *value, const char *field); + + ir_dereference_record(ir_variable *var, const char *field); + + virtual ir_dereference_record *clone(void *mem_ctx, + struct hash_table *) const; + + virtual ir_constant *constant_expression_value(); + + /** + * Get the variable that is ultimately referenced by an r-value + */ + virtual ir_variable *variable_referenced() + { + return this->record->variable_referenced(); + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + ir_rvalue *record; + const char *field; +}; + + +/** + * Data stored in an ir_constant + */ +union ir_constant_data { + unsigned u[16]; + int i[16]; + float f[16]; + bool b[16]; +}; + + +class ir_constant : public ir_rvalue { +public: + ir_constant(const struct glsl_type *type, const ir_constant_data *data); + ir_constant(bool b); + ir_constant(unsigned int u); + ir_constant(int i); + ir_constant(float f); + + /** + * Construct an ir_constant from a list of ir_constant values + */ + ir_constant(const struct glsl_type *type, exec_list *values); + + /** + * Construct an ir_constant from a scalar component of another ir_constant + * + * The new \c ir_constant inherits the type of the component from the + * source constant. + * + * \note + * In the case of a matrix constant, the new constant is a scalar, \b not + * a vector. + */ + ir_constant(const ir_constant *c, unsigned i); + + /** + * Return a new ir_constant of the specified type containing all zeros. + */ + static ir_constant *zero(void *mem_ctx, const glsl_type *type); + + virtual ir_constant *clone(void *mem_ctx, struct hash_table *) const; + + virtual ir_constant *constant_expression_value(); + + virtual ir_constant *as_constant() + { + return this; + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + /** + * Get a particular component of a constant as a specific type + * + * This is useful, for example, to get a value from an integer constant + * as a float or bool. This appears frequently when constructors are + * called with all constant parameters. + */ + /*@{*/ + bool get_bool_component(unsigned i) const; + float get_float_component(unsigned i) const; + int get_int_component(unsigned i) const; + unsigned get_uint_component(unsigned i) const; + /*@}*/ + + ir_constant *get_array_element(unsigned i) const; + + ir_constant *get_record_field(const char *name); + + /** + * Determine whether a constant has the same value as another constant + */ + bool has_value(const ir_constant *) const; + + /** + * Value of the constant. + * + * The field used to back the values supplied by the constant is determined + * by the type associated with the \c ir_instruction. Constants may be + * scalars, vectors, or matrices. + */ + union ir_constant_data value; + + /* Array elements */ + ir_constant **array_elements; + + /* Structure fields */ + exec_list components; + +private: + /** + * Parameterless constructor only used by the clone method + */ + ir_constant(void); +}; + +void +visit_exec_list(exec_list *list, ir_visitor *visitor); + +void validate_ir_tree(exec_list *instructions); + +/** + * Make a clone of each IR instruction in a list + * + * \param in List of IR instructions that are to be cloned + * \param out List to hold the cloned instructions + */ +void +clone_ir_list(void *mem_ctx, exec_list *out, const exec_list *in); + +extern void +_mesa_glsl_initialize_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + +extern void +_mesa_glsl_initialize_functions(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + +extern void +_mesa_glsl_release_functions(void); + +extern void +reparent_ir(exec_list *list, void *mem_ctx); + +struct glsl_symbol_table; + +extern void +import_prototypes(const exec_list *source, exec_list *dest, + struct glsl_symbol_table *symbols, void *mem_ctx); + +extern bool +ir_has_call(ir_instruction *ir); + +extern void +do_set_program_inouts(exec_list *instructions, struct gl_program *prog); + +#endif /* IR_H */ diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp new file mode 100644 index 0000000000..ff81563f19 --- /dev/null +++ b/src/glsl/ir_algebraic.cpp @@ -0,0 +1,472 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_algebraic.cpp + * + * Takes advantage of association, commutivity, and other algebraic + * properties to simplify expressions. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_rvalue_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +/** + * Visitor class for replacing expressions with ir_constant values. + */ + +class ir_algebraic_visitor : public ir_rvalue_visitor { +public: + ir_algebraic_visitor() + { + this->progress = false; + this->mem_ctx = NULL; + } + + virtual ~ir_algebraic_visitor() + { + } + + ir_rvalue *handle_expression(ir_expression *ir); + void handle_rvalue(ir_rvalue **rvalue); + bool reassociate_constant(ir_expression *ir1, + int const_index, + ir_constant *constant, + ir_expression *ir2); + void reassociate_operands(ir_expression *ir1, + int op1, + ir_expression *ir2, + int op2); + ir_rvalue *swizzle_if_required(ir_expression *expr, + ir_rvalue *operand); + + void *mem_ctx; + + bool progress; +}; + +static bool +is_vec_zero(ir_constant *ir) +{ + int c; + + if (!ir) + return false; + if (!ir->type->is_scalar() && + !ir->type->is_vector()) + return false; + + for (c = 0; c < ir->type->vector_elements; c++) { + switch (ir->type->base_type) { + case GLSL_TYPE_FLOAT: + if (ir->value.f[c] != 0.0) + return false; + break; + case GLSL_TYPE_INT: + if (ir->value.i[c] != 0) + return false; + break; + case GLSL_TYPE_UINT: + if (ir->value.u[c] != 0) + return false; + break; + case GLSL_TYPE_BOOL: + if (ir->value.b[c] != false) + return false; + break; + default: + assert(!"bad base type"); + return false; + } + } + + return true; +} + +static bool +is_vec_one(ir_constant *ir) +{ + int c; + + if (!ir) + return false; + if (!ir->type->is_scalar() && + !ir->type->is_vector()) + return false; + + for (c = 0; c < ir->type->vector_elements; c++) { + switch (ir->type->base_type) { + case GLSL_TYPE_FLOAT: + if (ir->value.f[c] != 1.0) + return false; + break; + case GLSL_TYPE_INT: + if (ir->value.i[c] != 1) + return false; + break; + case GLSL_TYPE_UINT: + if (ir->value.u[c] != 1) + return false; + break; + case GLSL_TYPE_BOOL: + if (ir->value.b[c] != true) + return false; + break; + default: + assert(!"bad base type"); + return false; + } + } + + return true; +} + +static void +update_type(ir_expression *ir) +{ + if (ir->operands[0]->type->is_vector()) + ir->type = ir->operands[0]->type; + else + ir->type = ir->operands[1]->type; +} + +void +ir_algebraic_visitor::reassociate_operands(ir_expression *ir1, + int op1, + ir_expression *ir2, + int op2) +{ + ir_rvalue *temp = ir2->operands[op2]; + ir2->operands[op2] = ir1->operands[op1]; + ir1->operands[op1] = temp; + + /* Update the type of ir2. The type of ir1 won't have changed -- + * base types matched, and at least one of the operands of the 2 + * binops is still a vector if any of them were. + */ + update_type(ir2); + + this->progress = true; +} + +/** + * Reassociates a constant down a tree of adds or multiplies. + * + * Consider (2 * (a * (b * 0.5))). We want to send up with a * b. + */ +bool +ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index, + ir_constant *constant, + ir_expression *ir2) +{ + if (!ir2 || ir1->operation != ir2->operation) + return false; + + /* Don't want to even think about matrices. */ + if (ir1->operands[0]->type->is_matrix() || + ir1->operands[0]->type->is_matrix() || + ir2->operands[1]->type->is_matrix() || + ir2->operands[1]->type->is_matrix()) + return false; + + ir_constant *ir2_const[2]; + ir2_const[0] = ir2->operands[0]->constant_expression_value(); + ir2_const[1] = ir2->operands[1]->constant_expression_value(); + + if (ir2_const[0] && ir2_const[1]) + return false; + + if (ir2_const[0]) { + reassociate_operands(ir1, const_index, ir2, 1); + return true; + } else if (ir2_const[1]) { + reassociate_operands(ir1, const_index, ir2, 0); + return true; + } + + if (reassociate_constant(ir1, const_index, constant, + ir2->operands[0]->as_expression())) { + update_type(ir2); + return true; + } + + if (reassociate_constant(ir1, const_index, constant, + ir2->operands[1]->as_expression())) { + update_type(ir2); + return true; + } + + return false; +} + +/* When eliminating an expression and just returning one of its operands, + * we may need to swizzle that operand out to a vector if the expression was + * vector type. + */ +ir_rvalue * +ir_algebraic_visitor::swizzle_if_required(ir_expression *expr, + ir_rvalue *operand) +{ + if (expr->type->is_vector() && operand->type->is_scalar()) { + return new(mem_ctx) ir_swizzle(operand, 0, 0, 0, 0, + expr->type->vector_elements); + } else + return operand; +} + +ir_rvalue * +ir_algebraic_visitor::handle_expression(ir_expression *ir) +{ + ir_constant *op_const[2] = {NULL, NULL}; + ir_expression *op_expr[2] = {NULL, NULL}; + ir_expression *temp; + unsigned int i; + + for (i = 0; i < ir->get_num_operands(); i++) { + if (ir->operands[i]->type->is_matrix()) + return ir; + + op_const[i] = ir->operands[i]->constant_expression_value(); + op_expr[i] = ir->operands[i]->as_expression(); + } + + if (this->mem_ctx == NULL) + this->mem_ctx = talloc_parent(ir); + + switch (ir->operation) { + case ir_unop_logic_not: { + enum ir_expression_operation new_op = ir_unop_logic_not; + + if (op_expr[0] == NULL) + break; + + switch (op_expr[0]->operation) { + case ir_binop_less: new_op = ir_binop_gequal; break; + case ir_binop_greater: new_op = ir_binop_lequal; break; + case ir_binop_lequal: new_op = ir_binop_greater; break; + case ir_binop_gequal: new_op = ir_binop_less; break; + case ir_binop_equal: new_op = ir_binop_nequal; break; + case ir_binop_nequal: new_op = ir_binop_equal; break; + + default: + /* The default case handler is here to silence a warning from GCC. + */ + break; + } + + if (new_op != ir_unop_logic_not) { + this->progress = true; + return new(mem_ctx) ir_expression(new_op, + ir->type, + op_expr[0]->operands[0], + op_expr[0]->operands[1]); + } + + break; + } + + case ir_binop_add: + if (is_vec_zero(op_const[0])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[1]); + } + if (is_vec_zero(op_const[1])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[0]); + } + + /* Reassociate addition of constants so that we can do constant + * folding. + */ + if (op_const[0] && !op_const[1]) + reassociate_constant(ir, 0, op_const[0], + ir->operands[1]->as_expression()); + if (op_const[1] && !op_const[0]) + reassociate_constant(ir, 1, op_const[1], + ir->operands[0]->as_expression()); + break; + + case ir_binop_sub: + if (is_vec_zero(op_const[0])) { + this->progress = true; + temp = new(mem_ctx) ir_expression(ir_unop_neg, + ir->operands[1]->type, + ir->operands[1], + NULL); + return swizzle_if_required(ir, temp); + } + if (is_vec_zero(op_const[1])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[0]); + } + break; + + case ir_binop_mul: + if (is_vec_one(op_const[0])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[1]); + } + if (is_vec_one(op_const[1])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[0]); + } + + if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) { + this->progress = true; + return ir_constant::zero(ir, ir->type); + } + + /* Reassociate multiplication of constants so that we can do + * constant folding. + */ + if (op_const[0] && !op_const[1]) + reassociate_constant(ir, 0, op_const[0], + ir->operands[1]->as_expression()); + if (op_const[1] && !op_const[0]) + reassociate_constant(ir, 1, op_const[1], + ir->operands[0]->as_expression()); + + break; + + case ir_binop_div: + if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) { + this->progress = true; + temp = new(mem_ctx) ir_expression(ir_unop_rcp, + ir->operands[1]->type, + ir->operands[1], + NULL); + return swizzle_if_required(ir, temp); + } + if (is_vec_one(op_const[1])) { + this->progress = true; + return swizzle_if_required(ir, ir->operands[0]); + } + break; + + case ir_binop_logic_and: + /* FINISHME: Also simplify (a && a) to (a). */ + if (is_vec_one(op_const[0])) { + this->progress = true; + return ir->operands[1]; + } else if (is_vec_one(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } else if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) { + this->progress = true; + return ir_constant::zero(mem_ctx, ir->type); + } + break; + + case ir_binop_logic_xor: + /* FINISHME: Also simplify (a ^^ a) to (false). */ + if (is_vec_zero(op_const[0])) { + this->progress = true; + return ir->operands[1]; + } else if (is_vec_zero(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } else if (is_vec_one(op_const[0])) { + this->progress = true; + return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type, + ir->operands[1], NULL); + } else if (is_vec_one(op_const[1])) { + this->progress = true; + return new(mem_ctx) ir_expression(ir_unop_logic_not, ir->type, + ir->operands[0], NULL); + } + break; + + case ir_binop_logic_or: + /* FINISHME: Also simplify (a || a) to (a). */ + if (is_vec_zero(op_const[0])) { + this->progress = true; + return ir->operands[1]; + } else if (is_vec_zero(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } else if (is_vec_one(op_const[0]) || is_vec_one(op_const[1])) { + ir_constant_data data; + + for (unsigned i = 0; i < 16; i++) + data.b[i] = true; + + this->progress = true; + return new(mem_ctx) ir_constant(ir->type, &data); + } + break; + + case ir_unop_rcp: + if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp) { + this->progress = true; + return op_expr[0]->operands[0]; + } + + /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some + * backends, except that some backends will have done sqrt -> + * rcp(rsq(x)) and we don't want to undo it for them. + */ + + /* As far as we know, all backends are OK with rsq. */ + if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) { + this->progress = true; + temp = new(mem_ctx) ir_expression(ir_unop_rsq, + op_expr[0]->operands[0]->type, + op_expr[0]->operands[0], + NULL); + return swizzle_if_required(ir, temp); + } + + break; + + default: + break; + } + + return ir; +} + +void +ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + ir_expression *expr = (*rvalue)->as_expression(); + if (!expr) + return; + + *rvalue = handle_expression(expr); +} + +bool +do_algebraic(exec_list *instructions) +{ + ir_algebraic_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} diff --git a/src/glsl/ir_basic_block.cpp b/src/glsl/ir_basic_block.cpp new file mode 100644 index 0000000000..a833825962 --- /dev/null +++ b/src/glsl/ir_basic_block.cpp @@ -0,0 +1,149 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_basic_block.cpp + * + * Basic block analysis of instruction streams. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_basic_block.h" +#include "glsl_types.h" + +class ir_has_call_visitor : public ir_hierarchical_visitor { +public: + ir_has_call_visitor() + { + has_call = false; + } + + virtual ir_visitor_status visit_enter(ir_call *ir) + { + (void) ir; + has_call = true; + return visit_stop; + } + + bool has_call; +}; + +bool +ir_has_call(ir_instruction *ir) +{ + ir_has_call_visitor v; + ir->accept(&v); + return v.has_call; +} + +/** + * Calls a user function for every basic block in the instruction stream. + * + * Basic block analysis is pretty easy in our IR thanks to the lack of + * unstructured control flow. We've got: + * + * ir_loop (for () {}, while () {}, do {} while ()) + * ir_loop_jump ( + * ir_if () {} + * ir_return + * ir_call() + * + * Note that the basic blocks returned by this don't encompass all + * operations performed by the program -- for example, if conditions + * don't get returned, nor do the assignments that will be generated + * for ir_call parameters. + */ +void call_for_basic_blocks(exec_list *instructions, + void (*callback)(ir_instruction *first, + ir_instruction *last, + void *data), + void *data) +{ + ir_instruction *leader = NULL; + ir_instruction *last = NULL; + + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + ir_if *ir_if; + ir_loop *ir_loop; + ir_function *ir_function; + + if (!leader) + leader = ir; + + if ((ir_if = ir->as_if())) { + callback(leader, ir, data); + leader = NULL; + + call_for_basic_blocks(&ir_if->then_instructions, callback, data); + call_for_basic_blocks(&ir_if->else_instructions, callback, data); + } else if ((ir_loop = ir->as_loop())) { + callback(leader, ir, data); + leader = NULL; + call_for_basic_blocks(&ir_loop->body_instructions, callback, data); + } else if (ir->as_return() || ir->as_call()) { + callback(leader, ir, data); + leader = NULL; + } else if ((ir_function = ir->as_function())) { + /* A function definition doesn't interrupt our basic block + * since execution doesn't go into it. We should process the + * bodies of its signatures for BBs, though. + * + * Note that we miss an opportunity for producing more + * maximal BBs between the instructions that precede main() + * and the body of main(). Perhaps those instructions ought + * to live inside of main(). + */ + foreach_iter(exec_list_iterator, fun_iter, *ir_function) { + ir_function_signature *ir_sig; + + ir_sig = (ir_function_signature *)fun_iter.get(); + + call_for_basic_blocks(&ir_sig->body, callback, data); + } + } else if (ir->as_assignment()) { + /* If there's a call in the expression tree being assigned, + * then that ends the BB too. + * + * The assumption is that any consumer of the basic block + * walker is fine with the fact that the call is somewhere in + * the tree even if portions of the tree may be evaluated + * after the call. + * + * A consumer that has an issue with this could not process + * the last instruction of the basic block. If doing so, + * expression flattener may be useful before using the basic + * block finder to get more maximal basic blocks out. + */ + if (ir_has_call(ir)) { + callback(leader, ir, data); + leader = NULL; + } + } + last = ir; + } + if (leader) { + callback(leader, last, data); + } +} diff --git a/src/glsl/ir_basic_block.h b/src/glsl/ir_basic_block.h new file mode 100644 index 0000000000..dbd678b5c4 --- /dev/null +++ b/src/glsl/ir_basic_block.h @@ -0,0 +1,28 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +void call_for_basic_blocks(exec_list *instructions, + void (*callback)(ir_instruction *first, + ir_instruction *last, + void *data), + void *data); diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp new file mode 100644 index 0000000000..1d690a4da7 --- /dev/null +++ b/src/glsl/ir_clone.cpp @@ -0,0 +1,402 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <string.h> +#include "ir.h" +#include "glsl_types.h" +extern "C" { +#include "program/hash_table.h" +} + +/** + * Duplicate an IR variable + * + * \note + * This will probably be made \c virtual and moved to the base class + * eventually. + */ +ir_variable * +ir_variable::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_variable *var = new(mem_ctx) ir_variable(this->type, this->name, + (ir_variable_mode) this->mode); + + var->max_array_access = this->max_array_access; + var->read_only = this->read_only; + var->centroid = this->centroid; + var->invariant = this->invariant; + var->interpolation = this->interpolation; + var->array_lvalue = this->array_lvalue; + var->location = this->location; + var->warn_extension = this->warn_extension; + var->origin_upper_left = this->origin_upper_left; + var->pixel_center_integer = this->pixel_center_integer; + + if (this->constant_value) + var->constant_value = this->constant_value->clone(mem_ctx, ht); + + if (ht) { + hash_table_insert(ht, var, (void *)const_cast<ir_variable *>(this)); + } + + return var; +} + +ir_swizzle * +ir_swizzle::clone(void *mem_ctx, struct hash_table *ht) const +{ + return new(mem_ctx) ir_swizzle(this->val->clone(mem_ctx, ht), this->mask); +} + +ir_return * +ir_return::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_rvalue *new_value = NULL; + + if (this->value) + new_value = this->value->clone(mem_ctx, ht); + + return new(mem_ctx) ir_return(new_value); +} + +ir_discard * +ir_discard::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_rvalue *new_condition = NULL; + + if (this->condition != NULL) + new_condition = this->condition->clone(mem_ctx, ht); + + return new(mem_ctx) ir_discard(new_condition); +} + +ir_loop_jump * +ir_loop_jump::clone(void *mem_ctx, struct hash_table *ht) const +{ + (void)ht; + + return new(mem_ctx) ir_loop_jump(this->mode); +} + +ir_if * +ir_if::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_if *new_if = new(mem_ctx) ir_if(this->condition->clone(mem_ctx, ht)); + + foreach_iter(exec_list_iterator, iter, this->then_instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + new_if->then_instructions.push_tail(ir->clone(mem_ctx, ht)); + } + + foreach_iter(exec_list_iterator, iter, this->else_instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + new_if->else_instructions.push_tail(ir->clone(mem_ctx, ht)); + } + + return new_if; +} + +ir_loop * +ir_loop::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_loop *new_loop = new(mem_ctx) ir_loop(); + + if (this->from) + new_loop->from = this->from->clone(mem_ctx, ht); + if (this->to) + new_loop->to = this->to->clone(mem_ctx, ht); + if (this->increment) + new_loop->increment = this->increment->clone(mem_ctx, ht); + new_loop->counter = counter; + + foreach_iter(exec_list_iterator, iter, this->body_instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + new_loop->body_instructions.push_tail(ir->clone(mem_ctx, ht)); + } + + return new_loop; +} + +ir_call * +ir_call::clone(void *mem_ctx, struct hash_table *ht) const +{ + exec_list new_parameters; + + foreach_iter(exec_list_iterator, iter, this->actual_parameters) { + ir_instruction *ir = (ir_instruction *)iter.get(); + new_parameters.push_tail(ir->clone(mem_ctx, ht)); + } + + return new(mem_ctx) ir_call(this->callee, &new_parameters); +} + +ir_expression * +ir_expression::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_rvalue *op[2] = {NULL, NULL}; + unsigned int i; + + for (i = 0; i < get_num_operands(); i++) { + op[i] = this->operands[i]->clone(mem_ctx, ht); + } + + return new(mem_ctx) ir_expression(this->operation, this->type, op[0], op[1]); +} + +ir_dereference_variable * +ir_dereference_variable::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_variable *new_var; + + if (ht) { + new_var = (ir_variable *)hash_table_find(ht, this->var); + if (!new_var) + new_var = this->var; + } else { + new_var = this->var; + } + + return new(mem_ctx) ir_dereference_variable(new_var); +} + +ir_dereference_array * +ir_dereference_array::clone(void *mem_ctx, struct hash_table *ht) const +{ + return new(mem_ctx) ir_dereference_array(this->array->clone(mem_ctx, ht), + this->array_index->clone(mem_ctx, + ht)); +} + +ir_dereference_record * +ir_dereference_record::clone(void *mem_ctx, struct hash_table *ht) const +{ + return new(mem_ctx) ir_dereference_record(this->record->clone(mem_ctx, ht), + this->field); +} + +ir_texture * +ir_texture::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_texture *new_tex = new(mem_ctx) ir_texture(this->op); + new_tex->type = this->type; + + new_tex->sampler = this->sampler->clone(mem_ctx, ht); + new_tex->coordinate = this->coordinate->clone(mem_ctx, ht); + if (this->projector) + new_tex->projector = this->projector->clone(mem_ctx, ht); + if (this->shadow_comparitor) { + new_tex->shadow_comparitor = this->shadow_comparitor->clone(mem_ctx, ht); + } + + for (int i = 0; i < 3; i++) + new_tex->offsets[i] = this->offsets[i]; + + switch (this->op) { + case ir_tex: + break; + case ir_txb: + new_tex->lod_info.bias = this->lod_info.bias->clone(mem_ctx, ht); + break; + case ir_txl: + case ir_txf: + new_tex->lod_info.lod = this->lod_info.lod->clone(mem_ctx, ht); + break; + case ir_txd: + new_tex->lod_info.grad.dPdx = this->lod_info.grad.dPdx->clone(mem_ctx, ht); + new_tex->lod_info.grad.dPdy = this->lod_info.grad.dPdy->clone(mem_ctx, ht); + break; + } + + return new_tex; +} + +ir_assignment * +ir_assignment::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_rvalue *new_condition = NULL; + + if (this->condition) + new_condition = this->condition->clone(mem_ctx, ht); + + return new(mem_ctx) ir_assignment(this->lhs->clone(mem_ctx, ht), + this->rhs->clone(mem_ctx, ht), + new_condition, + this->write_mask); +} + +ir_function * +ir_function::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_function *copy = new(mem_ctx) ir_function(this->name); + + copy->is_builtin = this->is_builtin; + + foreach_list_const(node, &this->signatures) { + const ir_function_signature *const sig = + (const ir_function_signature *const) node; + + ir_function_signature *sig_copy = sig->clone(mem_ctx, ht); + copy->add_signature(sig_copy); + + if (ht != NULL) + hash_table_insert(ht, sig_copy, + (void *)const_cast<ir_function_signature *>(sig)); + } + + return copy; +} + +ir_function_signature * +ir_function_signature::clone(void *mem_ctx, struct hash_table *ht) const +{ + ir_function_signature *copy = + new(mem_ctx) ir_function_signature(this->return_type); + + copy->is_defined = this->is_defined; + + /* Clone the parameter list. + */ + foreach_list_const(node, &this->parameters) { + const ir_variable *const param = (const ir_variable *) node; + + assert(const_cast<ir_variable *>(param)->as_variable() != NULL); + + ir_variable *const param_copy = param->clone(mem_ctx, ht); + copy->parameters.push_tail(param_copy); + } + + /* Clone the instruction list. + */ + foreach_list_const(node, &this->body) { + const ir_instruction *const inst = (const ir_instruction *) node; + + ir_instruction *const inst_copy = inst->clone(mem_ctx, ht); + copy->body.push_tail(inst_copy); + } + + return copy; +} + +ir_constant * +ir_constant::clone(void *mem_ctx, struct hash_table *ht) const +{ + (void)ht; + + switch (this->type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + return new(mem_ctx) ir_constant(this->type, &this->value); + + case GLSL_TYPE_STRUCT: { + ir_constant *c = new(mem_ctx) ir_constant; + + c->type = this->type; + for (exec_node *node = this->components.head + ; !node->is_tail_sentinel() + ; node = node->next) { + ir_constant *const orig = (ir_constant *) node; + + c->components.push_tail(orig->clone(mem_ctx, NULL)); + } + + return c; + } + + case GLSL_TYPE_ARRAY: { + ir_constant *c = new(mem_ctx) ir_constant; + + c->type = this->type; + c->array_elements = talloc_array(c, ir_constant *, this->type->length); + for (unsigned i = 0; i < this->type->length; i++) { + c->array_elements[i] = this->array_elements[i]->clone(mem_ctx, NULL); + } + return c; + } + + default: + assert(!"Should not get here."); + return NULL; + } +} + + +class fixup_ir_call_visitor : public ir_hierarchical_visitor { +public: + fixup_ir_call_visitor(struct hash_table *ht) + { + this->ht = ht; + } + + virtual ir_visitor_status visit_enter(ir_call *ir) + { + /* Try to find the function signature referenced by the ir_call in the + * table. If it is found, replace it with the value from the table. + */ + ir_function_signature *sig = + (ir_function_signature *) hash_table_find(this->ht, ir->get_callee()); + if (sig != NULL) + ir->set_callee(sig); + + /* Since this may be used before function call parameters are flattened, + * the children also need to be processed. + */ + return visit_continue; + } + +private: + struct hash_table *ht; +}; + + +static void +fixup_function_calls(struct hash_table *ht, exec_list *instructions) +{ + fixup_ir_call_visitor v(ht); + v.run(instructions); +} + + +void +clone_ir_list(void *mem_ctx, exec_list *out, const exec_list *in) +{ + struct hash_table *ht = + hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare); + + foreach_list_const(node, in) { + const ir_instruction *const original = (ir_instruction *) node; + ir_instruction *copy = original->clone(mem_ctx, ht); + + out->push_tail(copy); + } + + /* Make a pass over the cloned tree to fix up ir_call nodes to point to the + * cloned ir_function_signature nodes. This cannot be done automatically + * during cloning because the ir_call might be a forward reference (i.e., + * the function signature that it references may not have been cloned yet). + */ + fixup_function_calls(ht, out); + + hash_table_dtor(ht); +} diff --git a/src/glsl/ir_constant_expression.cpp b/src/glsl/ir_constant_expression.cpp new file mode 100644 index 0000000000..458dca7977 --- /dev/null +++ b/src/glsl/ir_constant_expression.cpp @@ -0,0 +1,1159 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_constant_expression.cpp + * Evaluate and process constant valued expressions + * + * In GLSL, constant valued expressions are used in several places. These + * must be processed and evaluated very early in the compilation process. + * + * * Sizes of arrays + * * Initializers for uniforms + * * Initializers for \c const variables + */ + +#include <math.h> +#include "main/core.h" /* for MAX2, MIN2, CLAMP */ +#include "ir.h" +#include "ir_visitor.h" +#include "glsl_types.h" + +static float +dot(ir_constant *op0, ir_constant *op1) +{ + assert(op0->type->is_float() && op1->type->is_float()); + + float result = 0; + for (unsigned c = 0; c < op0->type->components(); c++) + result += op0->value.f[c] * op1->value.f[c]; + + return result; +} + +ir_constant * +ir_expression::constant_expression_value() +{ + ir_constant *op[2] = { NULL, NULL }; + ir_constant_data data; + + memset(&data, 0, sizeof(data)); + + for (unsigned operand = 0; operand < this->get_num_operands(); operand++) { + op[operand] = this->operands[operand]->constant_expression_value(); + if (!op[operand]) + return NULL; + } + + if (op[1] != NULL) + assert(op[0]->type->base_type == op[1]->type->base_type); + + bool op0_scalar = op[0]->type->is_scalar(); + bool op1_scalar = op[1] != NULL && op[1]->type->is_scalar(); + + /* When iterating over a vector or matrix's components, we want to increase + * the loop counter. However, for scalars, we want to stay at 0. + */ + unsigned c0_inc = op0_scalar ? 0 : 1; + unsigned c1_inc = op1_scalar ? 0 : 1; + unsigned components; + if (op1_scalar || !op[1]) { + components = op[0]->type->components(); + } else { + components = op[1]->type->components(); + } + + void *ctx = talloc_parent(this); + + /* Handle array operations here, rather than below. */ + if (op[0]->type->is_array()) { + assert(op[1] != NULL && op[1]->type->is_array()); + switch (this->operation) { + case ir_binop_equal: + return new(ctx) ir_constant(op[0]->has_value(op[1])); + case ir_binop_nequal: + return new(ctx) ir_constant(!op[0]->has_value(op[1])); + default: + break; + } + return NULL; + } + + switch (this->operation) { + case ir_unop_logic_not: + assert(op[0]->type->base_type == GLSL_TYPE_BOOL); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.b[c] = !op[0]->value.b[c]; + break; + + case ir_unop_f2i: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.i[c] = op[0]->value.f[c]; + } + break; + case ir_unop_i2f: + assert(op[0]->type->base_type == GLSL_TYPE_INT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = op[0]->value.i[c]; + } + break; + case ir_unop_u2f: + assert(op[0]->type->base_type == GLSL_TYPE_UINT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = op[0]->value.u[c]; + } + break; + case ir_unop_b2f: + assert(op[0]->type->base_type == GLSL_TYPE_BOOL); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = op[0]->value.b[c] ? 1.0 : 0.0; + } + break; + case ir_unop_f2b: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.b[c] = bool(op[0]->value.f[c]); + } + break; + case ir_unop_b2i: + assert(op[0]->type->base_type == GLSL_TYPE_BOOL); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.u[c] = op[0]->value.b[c] ? 1 : 0; + } + break; + case ir_unop_i2b: + assert(op[0]->type->is_integer()); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.b[c] = bool(op[0]->value.u[c]); + } + break; + + case ir_unop_any: + assert(op[0]->type->is_boolean()); + data.b[0] = false; + for (unsigned c = 0; c < op[0]->type->components(); c++) { + if (op[0]->value.b[c]) + data.b[0] = true; + } + break; + + case ir_unop_trunc: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = truncf(op[0]->value.f[c]); + } + break; + + case ir_unop_ceil: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = ceilf(op[0]->value.f[c]); + } + break; + + case ir_unop_floor: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = floorf(op[0]->value.f[c]); + } + break; + + case ir_unop_fract: + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (this->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = 0; + break; + case GLSL_TYPE_INT: + data.i[c] = 0; + break; + case GLSL_TYPE_FLOAT: + data.f[c] = op[0]->value.f[c] - floor(op[0]->value.f[c]); + break; + default: + assert(0); + } + } + break; + + case ir_unop_sin: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = sinf(op[0]->value.f[c]); + } + break; + + case ir_unop_cos: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = cosf(op[0]->value.f[c]); + } + break; + + case ir_unop_neg: + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (this->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = -op[0]->value.u[c]; + break; + case GLSL_TYPE_INT: + data.i[c] = -op[0]->value.i[c]; + break; + case GLSL_TYPE_FLOAT: + data.f[c] = -op[0]->value.f[c]; + break; + default: + assert(0); + } + } + break; + + case ir_unop_abs: + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (this->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = op[0]->value.u[c]; + break; + case GLSL_TYPE_INT: + data.i[c] = op[0]->value.i[c]; + if (data.i[c] < 0) + data.i[c] = -data.i[c]; + break; + case GLSL_TYPE_FLOAT: + data.f[c] = fabs(op[0]->value.f[c]); + break; + default: + assert(0); + } + } + break; + + case ir_unop_sign: + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (this->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = op[0]->value.i[c] > 0; + break; + case GLSL_TYPE_INT: + data.i[c] = (op[0]->value.i[c] > 0) - (op[0]->value.i[c] < 0); + break; + case GLSL_TYPE_FLOAT: + data.f[c] = float((op[0]->value.f[c] > 0)-(op[0]->value.f[c] < 0)); + break; + default: + assert(0); + } + } + break; + + case ir_unop_rcp: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (this->type->base_type) { + case GLSL_TYPE_UINT: + if (op[0]->value.u[c] != 0.0) + data.u[c] = 1 / op[0]->value.u[c]; + break; + case GLSL_TYPE_INT: + if (op[0]->value.i[c] != 0.0) + data.i[c] = 1 / op[0]->value.i[c]; + break; + case GLSL_TYPE_FLOAT: + if (op[0]->value.f[c] != 0.0) + data.f[c] = 1.0 / op[0]->value.f[c]; + break; + default: + assert(0); + } + } + break; + + case ir_unop_rsq: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = 1.0 / sqrtf(op[0]->value.f[c]); + } + break; + + case ir_unop_sqrt: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = sqrtf(op[0]->value.f[c]); + } + break; + + case ir_unop_exp: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = expf(op[0]->value.f[c]); + } + break; + + case ir_unop_exp2: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = exp2f(op[0]->value.f[c]); + } + break; + + case ir_unop_log: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = logf(op[0]->value.f[c]); + } + break; + + case ir_unop_log2: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = log2f(op[0]->value.f[c]); + } + break; + + case ir_unop_dFdx: + case ir_unop_dFdy: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = 0.0; + } + break; + + case ir_binop_pow: + assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + data.f[c] = powf(op[0]->value.f[c], op[1]->value.f[c]); + } + break; + + case ir_binop_dot: + data.f[0] = dot(op[0], op[1]); + break; + + case ir_binop_min: + assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar); + for (unsigned c = 0, c0 = 0, c1 = 0; + c < components; + c0 += c0_inc, c1 += c1_inc, c++) { + + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = MIN2(op[0]->value.u[c0], op[1]->value.u[c1]); + break; + case GLSL_TYPE_INT: + data.i[c] = MIN2(op[0]->value.i[c0], op[1]->value.i[c1]); + break; + case GLSL_TYPE_FLOAT: + data.f[c] = MIN2(op[0]->value.f[c0], op[1]->value.f[c1]); + break; + default: + assert(0); + } + } + + break; + case ir_binop_max: + assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar); + for (unsigned c = 0, c0 = 0, c1 = 0; + c < components; + c0 += c0_inc, c1 += c1_inc, c++) { + + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = MAX2(op[0]->value.u[c0], op[1]->value.u[c1]); + break; + case GLSL_TYPE_INT: + data.i[c] = MAX2(op[0]->value.i[c0], op[1]->value.i[c1]); + break; + case GLSL_TYPE_FLOAT: + data.f[c] = MAX2(op[0]->value.f[c0], op[1]->value.f[c1]); + break; + default: + assert(0); + } + } + break; + + case ir_binop_cross: + assert(op[0]->type == glsl_type::vec3_type); + assert(op[1]->type == glsl_type::vec3_type); + data.f[0] = (op[0]->value.f[1] * op[1]->value.f[2] - + op[1]->value.f[1] * op[0]->value.f[2]); + data.f[1] = (op[0]->value.f[2] * op[1]->value.f[0] - + op[1]->value.f[2] * op[0]->value.f[0]); + data.f[2] = (op[0]->value.f[0] * op[1]->value.f[1] - + op[1]->value.f[0] * op[0]->value.f[1]); + break; + + case ir_binop_add: + assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar); + for (unsigned c = 0, c0 = 0, c1 = 0; + c < components; + c0 += c0_inc, c1 += c1_inc, c++) { + + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = op[0]->value.u[c0] + op[1]->value.u[c1]; + break; + case GLSL_TYPE_INT: + data.i[c] = op[0]->value.i[c0] + op[1]->value.i[c1]; + break; + case GLSL_TYPE_FLOAT: + data.f[c] = op[0]->value.f[c0] + op[1]->value.f[c1]; + break; + default: + assert(0); + } + } + + break; + case ir_binop_sub: + assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar); + for (unsigned c = 0, c0 = 0, c1 = 0; + c < components; + c0 += c0_inc, c1 += c1_inc, c++) { + + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = op[0]->value.u[c0] - op[1]->value.u[c1]; + break; + case GLSL_TYPE_INT: + data.i[c] = op[0]->value.i[c0] - op[1]->value.i[c1]; + break; + case GLSL_TYPE_FLOAT: + data.f[c] = op[0]->value.f[c0] - op[1]->value.f[c1]; + break; + default: + assert(0); + } + } + + break; + case ir_binop_mul: + /* Check for equal types, or unequal types involving scalars */ + if ((op[0]->type == op[1]->type && !op[0]->type->is_matrix()) + || op0_scalar || op1_scalar) { + for (unsigned c = 0, c0 = 0, c1 = 0; + c < components; + c0 += c0_inc, c1 += c1_inc, c++) { + + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = op[0]->value.u[c0] * op[1]->value.u[c1]; + break; + case GLSL_TYPE_INT: + data.i[c] = op[0]->value.i[c0] * op[1]->value.i[c1]; + break; + case GLSL_TYPE_FLOAT: + data.f[c] = op[0]->value.f[c0] * op[1]->value.f[c1]; + break; + default: + assert(0); + } + } + } else { + assert(op[0]->type->is_matrix() || op[1]->type->is_matrix()); + + /* Multiply an N-by-M matrix with an M-by-P matrix. Since either + * matrix can be a GLSL vector, either N or P can be 1. + * + * For vec*mat, the vector is treated as a row vector. This + * means the vector is a 1-row x M-column matrix. + * + * For mat*vec, the vector is treated as a column vector. Since + * matrix_columns is 1 for vectors, this just works. + */ + const unsigned n = op[0]->type->is_vector() + ? 1 : op[0]->type->vector_elements; + const unsigned m = op[1]->type->vector_elements; + const unsigned p = op[1]->type->matrix_columns; + for (unsigned j = 0; j < p; j++) { + for (unsigned i = 0; i < n; i++) { + for (unsigned k = 0; k < m; k++) { + data.f[i+n*j] += op[0]->value.f[i+n*k]*op[1]->value.f[k+m*j]; + } + } + } + } + + break; + case ir_binop_div: + assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar); + for (unsigned c = 0, c0 = 0, c1 = 0; + c < components; + c0 += c0_inc, c1 += c1_inc, c++) { + + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = op[0]->value.u[c0] / op[1]->value.u[c1]; + break; + case GLSL_TYPE_INT: + data.i[c] = op[0]->value.i[c0] / op[1]->value.i[c1]; + break; + case GLSL_TYPE_FLOAT: + data.f[c] = op[0]->value.f[c0] / op[1]->value.f[c1]; + break; + default: + assert(0); + } + } + + break; + case ir_binop_mod: + assert(op[0]->type == op[1]->type || op0_scalar || op1_scalar); + for (unsigned c = 0, c0 = 0, c1 = 0; + c < components; + c0 += c0_inc, c1 += c1_inc, c++) { + + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = op[0]->value.u[c0] % op[1]->value.u[c1]; + break; + case GLSL_TYPE_INT: + data.i[c] = op[0]->value.i[c0] % op[1]->value.i[c1]; + break; + case GLSL_TYPE_FLOAT: + /* We don't use fmod because it rounds toward zero; GLSL specifies + * the use of floor. + */ + data.f[c] = op[0]->value.f[c0] - op[1]->value.f[c1] + * floorf(op[0]->value.f[c0] / op[1]->value.f[c1]); + break; + default: + assert(0); + } + } + + break; + + case ir_binop_logic_and: + assert(op[0]->type->base_type == GLSL_TYPE_BOOL); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.b[c] = op[0]->value.b[c] && op[1]->value.b[c]; + break; + case ir_binop_logic_xor: + assert(op[0]->type->base_type == GLSL_TYPE_BOOL); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.b[c] = op[0]->value.b[c] ^ op[1]->value.b[c]; + break; + case ir_binop_logic_or: + assert(op[0]->type->base_type == GLSL_TYPE_BOOL); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.b[c] = op[0]->value.b[c] || op[1]->value.b[c]; + break; + + case ir_binop_less: + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[0] = op[0]->value.u[0] < op[1]->value.u[0]; + break; + case GLSL_TYPE_INT: + data.b[0] = op[0]->value.i[0] < op[1]->value.i[0]; + break; + case GLSL_TYPE_FLOAT: + data.b[0] = op[0]->value.f[0] < op[1]->value.f[0]; + break; + default: + assert(0); + } + break; + case ir_binop_greater: + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[0] = op[0]->value.u[0] > op[1]->value.u[0]; + break; + case GLSL_TYPE_INT: + data.b[0] = op[0]->value.i[0] > op[1]->value.i[0]; + break; + case GLSL_TYPE_FLOAT: + data.b[0] = op[0]->value.f[0] > op[1]->value.f[0]; + break; + default: + assert(0); + } + break; + case ir_binop_lequal: + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[0] = op[0]->value.u[0] <= op[1]->value.u[0]; + break; + case GLSL_TYPE_INT: + data.b[0] = op[0]->value.i[0] <= op[1]->value.i[0]; + break; + case GLSL_TYPE_FLOAT: + data.b[0] = op[0]->value.f[0] <= op[1]->value.f[0]; + break; + default: + assert(0); + } + break; + case ir_binop_gequal: + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[0] = op[0]->value.u[0] >= op[1]->value.u[0]; + break; + case GLSL_TYPE_INT: + data.b[0] = op[0]->value.i[0] >= op[1]->value.i[0]; + break; + case GLSL_TYPE_FLOAT: + data.b[0] = op[0]->value.f[0] >= op[1]->value.f[0]; + break; + default: + assert(0); + } + break; + + case ir_binop_equal: + data.b[0] = op[0]->has_value(op[1]); + break; + case ir_binop_nequal: + data.b[0] = !op[0]->has_value(op[1]); + break; + + default: + /* FINISHME: Should handle all expression types. */ + return NULL; + } + + return new(ctx) ir_constant(this->type, &data); +} + + +ir_constant * +ir_texture::constant_expression_value() +{ + /* texture lookups aren't constant expressions */ + return NULL; +} + + +ir_constant * +ir_swizzle::constant_expression_value() +{ + ir_constant *v = this->val->constant_expression_value(); + + if (v != NULL) { + ir_constant_data data = { { 0 } }; + + const unsigned swiz_idx[4] = { + this->mask.x, this->mask.y, this->mask.z, this->mask.w + }; + + for (unsigned i = 0; i < this->mask.num_components; i++) { + switch (v->type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: data.u[i] = v->value.u[swiz_idx[i]]; break; + case GLSL_TYPE_FLOAT: data.f[i] = v->value.f[swiz_idx[i]]; break; + case GLSL_TYPE_BOOL: data.b[i] = v->value.b[swiz_idx[i]]; break; + default: assert(!"Should not get here."); break; + } + } + + void *ctx = talloc_parent(this); + return new(ctx) ir_constant(this->type, &data); + } + return NULL; +} + + +ir_constant * +ir_dereference_variable::constant_expression_value() +{ + /* This may occur during compile and var->type is glsl_type::error_type */ + if (!var) + return NULL; + + /* The constant_value of a uniform variable is its initializer, + * not the lifetime constant value of the uniform. + */ + if (var->mode == ir_var_uniform) + return NULL; + + if (!var->constant_value) + return NULL; + + return var->constant_value->clone(talloc_parent(var), NULL); +} + + +ir_constant * +ir_dereference_array::constant_expression_value() +{ + ir_constant *array = this->array->constant_expression_value(); + ir_constant *idx = this->array_index->constant_expression_value(); + + if ((array != NULL) && (idx != NULL)) { + void *ctx = talloc_parent(this); + if (array->type->is_matrix()) { + /* Array access of a matrix results in a vector. + */ + const unsigned column = idx->value.u[0]; + + const glsl_type *const column_type = array->type->column_type(); + + /* Offset in the constant matrix to the first element of the column + * to be extracted. + */ + const unsigned mat_idx = column * column_type->vector_elements; + + ir_constant_data data; + + switch (column_type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + for (unsigned i = 0; i < column_type->vector_elements; i++) + data.u[i] = array->value.u[mat_idx + i]; + + break; + + case GLSL_TYPE_FLOAT: + for (unsigned i = 0; i < column_type->vector_elements; i++) + data.f[i] = array->value.f[mat_idx + i]; + + break; + + default: + assert(!"Should not get here."); + break; + } + + return new(ctx) ir_constant(column_type, &data); + } else if (array->type->is_vector()) { + const unsigned component = idx->value.u[0]; + + return new(ctx) ir_constant(array, component); + } else { + const unsigned index = idx->value.u[0]; + return array->get_array_element(index)->clone(ctx, NULL); + } + } + return NULL; +} + + +ir_constant * +ir_dereference_record::constant_expression_value() +{ + ir_constant *v = this->record->constant_expression_value(); + + return (v != NULL) ? v->get_record_field(this->field) : NULL; +} + + +ir_constant * +ir_assignment::constant_expression_value() +{ + /* FINISHME: Handle CEs involving assignment (return RHS) */ + return NULL; +} + + +ir_constant * +ir_constant::constant_expression_value() +{ + return this; +} + + +ir_constant * +ir_call::constant_expression_value() +{ + if (this->type == glsl_type::error_type) + return NULL; + + /* From the GLSL 1.20 spec, page 23: + * "Function calls to user-defined functions (non-built-in functions) + * cannot be used to form constant expressions." + */ + if (!this->callee->function()->is_builtin) + return NULL; + + unsigned num_parameters = 0; + + /* Check if all parameters are constant */ + ir_constant *op[3]; + foreach_list(n, &this->actual_parameters) { + ir_constant *constant = ((ir_rvalue *) n)->constant_expression_value(); + if (constant == NULL) + return NULL; + + op[num_parameters] = constant; + + assert(num_parameters < 3); + num_parameters++; + } + + /* Individual cases below can either: + * - Assign "expr" a new ir_expression to evaluate (for basic opcodes) + * - Fill "data" with appopriate constant data + * - Return an ir_constant directly. + */ + void *mem_ctx = talloc_parent(this); + ir_expression *expr = NULL; + + ir_constant_data data; + memset(&data, 0, sizeof(data)); + + const char *callee = this->callee_name(); + if (strcmp(callee, "abs") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_abs, type, op[0], NULL); + } else if (strcmp(callee, "all") == 0) { + assert(op[0]->type->is_boolean()); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + if (!op[0]->value.b[c]) + return new(mem_ctx) ir_constant(false); + } + return new(mem_ctx) ir_constant(true); + } else if (strcmp(callee, "any") == 0) { + assert(op[0]->type->is_boolean()); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + if (op[0]->value.b[c]) + return new(mem_ctx) ir_constant(true); + } + return new(mem_ctx) ir_constant(false); + } else if (strcmp(callee, "acos") == 0) { + assert(op[0]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = acosf(op[0]->value.f[c]); + } else if (strcmp(callee, "asin") == 0) { + assert(op[0]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = asinf(op[0]->value.f[c]); + } else if (strcmp(callee, "atan") == 0) { + assert(op[0]->type->is_float()); + if (num_parameters == 2) { + assert(op[1]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = atan2f(op[0]->value.f[c], op[1]->value.f[c]); + } else { + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = atanf(op[0]->value.f[c]); + } + } else if (strcmp(callee, "dFdx") == 0 || strcmp(callee, "dFdy") == 0) { + return ir_constant::zero(mem_ctx, this->type); + } else if (strcmp(callee, "ceil") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_ceil, type, op[0], NULL); + } else if (strcmp(callee, "clamp") == 0) { + assert(num_parameters == 3); + unsigned c1_inc = op[1]->type->is_scalar() ? 0 : 1; + unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1; + for (unsigned c = 0, c1 = 0, c2 = 0; + c < op[0]->type->components(); + c1 += c1_inc, c2 += c2_inc, c++) { + + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.u[c] = CLAMP(op[0]->value.u[c], op[1]->value.u[c1], + op[2]->value.u[c2]); + break; + case GLSL_TYPE_INT: + data.i[c] = CLAMP(op[0]->value.i[c], op[1]->value.i[c1], + op[2]->value.i[c2]); + break; + case GLSL_TYPE_FLOAT: + data.f[c] = CLAMP(op[0]->value.f[c], op[1]->value.f[c1], + op[2]->value.f[c2]); + break; + default: + assert(!"Should not get here."); + } + } + } else if (strcmp(callee, "cos") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_cos, type, op[0], NULL); + } else if (strcmp(callee, "cosh") == 0) { + assert(op[0]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = coshf(op[0]->value.f[c]); + } else if (strcmp(callee, "cross") == 0) { + expr = new(mem_ctx) ir_expression(ir_binop_cross, type, op[0], op[1]); + } else if (strcmp(callee, "degrees") == 0) { + assert(op[0]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = 180.0/M_PI * op[0]->value.f[c]; + } else if (strcmp(callee, "distance") == 0) { + assert(op[0]->type->is_float() && op[1]->type->is_float()); + float length_squared = 0.0; + for (unsigned c = 0; c < op[0]->type->components(); c++) { + float t = op[0]->value.f[c] - op[1]->value.f[c]; + length_squared += t * t; + } + return new(mem_ctx) ir_constant(sqrtf(length_squared)); + } else if (strcmp(callee, "dot") == 0) { + return new(mem_ctx) ir_constant(dot(op[0], op[1])); + } else if (strcmp(callee, "equal") == 0) { + assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector()); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[c] = op[0]->value.u[c] == op[1]->value.u[c]; + break; + case GLSL_TYPE_INT: + data.b[c] = op[0]->value.i[c] == op[1]->value.i[c]; + break; + case GLSL_TYPE_FLOAT: + data.b[c] = op[0]->value.f[c] == op[1]->value.f[c]; + break; + case GLSL_TYPE_BOOL: + data.b[c] = op[0]->value.b[c] == op[1]->value.b[c]; + break; + default: + assert(!"Should not get here."); + } + } + } else if (strcmp(callee, "exp") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_exp, type, op[0], NULL); + } else if (strcmp(callee, "exp2") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_exp2, type, op[0], NULL); + } else if (strcmp(callee, "faceforward") == 0) { + if (dot(op[2], op[1]) < 0) + return op[0]; + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = -op[0]->value.f[c]; + } else if (strcmp(callee, "floor") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_floor, type, op[0], NULL); + } else if (strcmp(callee, "fract") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_fract, type, op[0], NULL); + } else if (strcmp(callee, "fwidth") == 0) { + return ir_constant::zero(mem_ctx, this->type); + } else if (strcmp(callee, "greaterThan") == 0) { + assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector()); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[c] = op[0]->value.u[c] > op[1]->value.u[c]; + break; + case GLSL_TYPE_INT: + data.b[c] = op[0]->value.i[c] > op[1]->value.i[c]; + break; + case GLSL_TYPE_FLOAT: + data.b[c] = op[0]->value.f[c] > op[1]->value.f[c]; + break; + default: + assert(!"Should not get here."); + } + } + } else if (strcmp(callee, "greaterThanEqual") == 0) { + assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector()); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[c] = op[0]->value.u[c] >= op[1]->value.u[c]; + break; + case GLSL_TYPE_INT: + data.b[c] = op[0]->value.i[c] >= op[1]->value.i[c]; + break; + case GLSL_TYPE_FLOAT: + data.b[c] = op[0]->value.f[c] >= op[1]->value.f[c]; + break; + default: + assert(!"Should not get here."); + } + } + } else if (strcmp(callee, "inversesqrt") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_rsq, type, op[0], NULL); + } else if (strcmp(callee, "length") == 0) { + return new(mem_ctx) ir_constant(sqrtf(dot(op[0], op[0]))); + } else if (strcmp(callee, "lessThan") == 0) { + assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector()); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[c] = op[0]->value.u[c] < op[1]->value.u[c]; + break; + case GLSL_TYPE_INT: + data.b[c] = op[0]->value.i[c] < op[1]->value.i[c]; + break; + case GLSL_TYPE_FLOAT: + data.b[c] = op[0]->value.f[c] < op[1]->value.f[c]; + break; + default: + assert(!"Should not get here."); + } + } + } else if (strcmp(callee, "lessThanEqual") == 0) { + assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector()); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[c] = op[0]->value.u[c] <= op[1]->value.u[c]; + break; + case GLSL_TYPE_INT: + data.b[c] = op[0]->value.i[c] <= op[1]->value.i[c]; + break; + case GLSL_TYPE_FLOAT: + data.b[c] = op[0]->value.f[c] <= op[1]->value.f[c]; + break; + default: + assert(!"Should not get here."); + } + } + } else if (strcmp(callee, "log") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_log, type, op[0], NULL); + } else if (strcmp(callee, "log2") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_log2, type, op[0], NULL); + } else if (strcmp(callee, "matrixCompMult") == 0) { + assert(op[0]->type->is_float() && op[1]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = op[0]->value.f[c] * op[1]->value.f[c]; + } else if (strcmp(callee, "max") == 0) { + expr = new(mem_ctx) ir_expression(ir_binop_max, type, op[0], op[1]); + } else if (strcmp(callee, "min") == 0) { + expr = new(mem_ctx) ir_expression(ir_binop_min, type, op[0], op[1]); + } else if (strcmp(callee, "mix") == 0) { + assert(op[0]->type->is_float() && op[1]->type->is_float()); + if (op[2]->type->is_float()) { + unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1; + unsigned components = op[0]->type->components(); + for (unsigned c = 0, c2 = 0; c < components; c2 += c2_inc, c++) { + data.f[c] = op[0]->value.f[c] * (1 - op[2]->value.f[c2]) + + op[1]->value.f[c] * op[2]->value.f[c2]; + } + } else { + assert(op[2]->type->is_boolean()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = op[op[2]->value.b[c] ? 1 : 0]->value.f[c]; + } + } else if (strcmp(callee, "mod") == 0) { + expr = new(mem_ctx) ir_expression(ir_binop_mod, type, op[0], op[1]); + } else if (strcmp(callee, "normalize") == 0) { + assert(op[0]->type->is_float()); + float length = sqrtf(dot(op[0], op[0])); + + if (length == 0) + return ir_constant::zero(mem_ctx, this->type); + + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = op[0]->value.f[c] / length; + } else if (strcmp(callee, "not") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_logic_not, type, op[0], NULL); + } else if (strcmp(callee, "notEqual") == 0) { + assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector()); + for (unsigned c = 0; c < op[0]->type->components(); c++) { + switch (op[0]->type->base_type) { + case GLSL_TYPE_UINT: + data.b[c] = op[0]->value.u[c] != op[1]->value.u[c]; + break; + case GLSL_TYPE_INT: + data.b[c] = op[0]->value.i[c] != op[1]->value.i[c]; + break; + case GLSL_TYPE_FLOAT: + data.b[c] = op[0]->value.f[c] != op[1]->value.f[c]; + break; + case GLSL_TYPE_BOOL: + data.b[c] = op[0]->value.b[c] != op[1]->value.b[c]; + break; + default: + assert(!"Should not get here."); + } + } + } else if (strcmp(callee, "outerProduct") == 0) { + assert(op[0]->type->is_vector() && op[1]->type->is_vector()); + const unsigned m = op[0]->type->vector_elements; + const unsigned n = op[1]->type->vector_elements; + for (unsigned j = 0; j < n; j++) { + for (unsigned i = 0; i < m; i++) { + data.f[i+m*j] = op[0]->value.f[i] * op[1]->value.f[j]; + } + } + } else if (strcmp(callee, "pow") == 0) { + expr = new(mem_ctx) ir_expression(ir_binop_pow, type, op[0], op[1]); + } else if (strcmp(callee, "radians") == 0) { + assert(op[0]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = M_PI/180.0 * op[0]->value.f[c]; + } else if (strcmp(callee, "reflect") == 0) { + assert(op[0]->type->is_float()); + float dot_NI = dot(op[1], op[0]); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = op[0]->value.f[c] - 2 * dot_NI * op[1]->value.f[c]; + } else if (strcmp(callee, "refract") == 0) { + const float eta = op[2]->value.f[0]; + const float dot_NI = dot(op[1], op[0]); + const float k = 1.0 - eta * eta * (1.0 - dot_NI * dot_NI); + if (k < 0.0) { + return ir_constant::zero(mem_ctx, this->type); + } else { + for (unsigned c = 0; c < type->components(); c++) { + data.f[c] = eta * op[0]->value.f[c] - (eta * dot_NI + sqrtf(k)) + * op[1]->value.f[c]; + } + } + } else if (strcmp(callee, "sign") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_sign, type, op[0], NULL); + } else if (strcmp(callee, "sin") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_sin, type, op[0], NULL); + } else if (strcmp(callee, "sinh") == 0) { + assert(op[0]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = sinhf(op[0]->value.f[c]); + } else if (strcmp(callee, "smoothstep") == 0) { + assert(num_parameters == 3); + assert(op[1]->type == op[0]->type); + unsigned edge_inc = op[0]->type->is_scalar() ? 0 : 1; + for (unsigned c = 0, e = 0; c < type->components(); e += edge_inc, c++) { + const float edge0 = op[0]->value.f[e]; + const float edge1 = op[1]->value.f[e]; + if (edge0 == edge1) { + data.f[c] = 0.0; /* Avoid a crash - results are undefined anyway */ + } else { + const float numerator = op[2]->value.f[c] - edge0; + const float denominator = edge1 - edge0; + const float t = CLAMP(numerator/denominator, 0, 1); + data.f[c] = t * t * (3 - 2 * t); + } + } + } else if (strcmp(callee, "sqrt") == 0) { + expr = new(mem_ctx) ir_expression(ir_unop_sqrt, type, op[0], NULL); + } else if (strcmp(callee, "step") == 0) { + assert(op[0]->type->is_float() && op[1]->type->is_float()); + /* op[0] (edge) may be either a scalar or a vector */ + const unsigned c0_inc = op[0]->type->is_scalar() ? 0 : 1; + for (unsigned c = 0, c0 = 0; c < type->components(); c0 += c0_inc, c++) + data.f[c] = (op[1]->value.f[c] < op[0]->value.f[c0]) ? 0.0 : 1.0; + } else if (strcmp(callee, "tan") == 0) { + assert(op[0]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = tanf(op[0]->value.f[c]); + } else if (strcmp(callee, "tanh") == 0) { + assert(op[0]->type->is_float()); + for (unsigned c = 0; c < op[0]->type->components(); c++) + data.f[c] = tanhf(op[0]->value.f[c]); + } else if (strcmp(callee, "transpose") == 0) { + assert(op[0]->type->is_matrix()); + const unsigned n = op[0]->type->vector_elements; + const unsigned m = op[0]->type->matrix_columns; + for (unsigned j = 0; j < m; j++) { + for (unsigned i = 0; i < n; i++) { + data.f[m*i+j] += op[0]->value.f[i+n*j]; + } + } + } else { + /* Unsupported builtin - some are not allowed in constant expressions. */ + return NULL; + } + + if (expr != NULL) + return expr->constant_expression_value(); + + return new(mem_ctx) ir_constant(this->type, &data); +} diff --git a/src/glsl/ir_constant_folding.cpp b/src/glsl/ir_constant_folding.cpp new file mode 100644 index 0000000000..554c54fae3 --- /dev/null +++ b/src/glsl/ir_constant_folding.cpp @@ -0,0 +1,147 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_constant_folding.cpp + * Replace constant-valued expressions with references to constant values. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_rvalue_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +/** + * Visitor class for replacing expressions with ir_constant values. + */ + +class ir_constant_folding_visitor : public ir_rvalue_visitor { +public: + ir_constant_folding_visitor() + { + this->progress = false; + } + + virtual ~ir_constant_folding_visitor() + { + /* empty */ + } + + virtual ir_visitor_status visit_enter(ir_assignment *ir); + virtual ir_visitor_status visit_enter(ir_call *ir); + + virtual void handle_rvalue(ir_rvalue **rvalue); + + bool progress; +}; + +void +ir_constant_folding_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (*rvalue == NULL || (*rvalue)->ir_type == ir_type_constant) + return; + + /* Note that we do rvalue visitoring on leaving. So if an + * expression has a non-constant operand, no need to go looking + * down it to find if it's constant. This cuts the time of this + * pass down drastically. + */ + ir_expression *expr = (*rvalue)->as_expression(); + if (expr) { + for (unsigned int i = 0; i < expr->get_num_operands(); i++) { + if (!expr->operands[i]->as_constant()) + return; + } + } + + ir_constant *constant = (*rvalue)->constant_expression_value(); + if (constant) { + *rvalue = constant; + this->progress = true; + } else { + (*rvalue)->accept(this); + } +} + +ir_visitor_status +ir_constant_folding_visitor::visit_enter(ir_assignment *ir) +{ + ir->rhs->accept(this); + handle_rvalue(&ir->rhs); + + if (ir->condition) { + ir->condition->accept(this); + handle_rvalue(&ir->condition); + + ir_constant *const_val = ir->condition->as_constant(); + /* If the condition is constant, either remove the condition or + * remove the never-executed assignment. + */ + if (const_val) { + if (const_val->value.b[0]) + ir->condition = NULL; + else + ir->remove(); + this->progress = true; + } + } + + /* Don't descend into the LHS because we want it to stay as a + * variable dereference. FINISHME: We probably should to get array + * indices though. + */ + return visit_continue_with_parent; +} + +ir_visitor_status +ir_constant_folding_visitor::visit_enter(ir_call *ir) +{ + exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator(); + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param_rval = (ir_rvalue *)iter.get(); + ir_variable *sig_param = (ir_variable *)sig_iter.get(); + + if (sig_param->mode == ir_var_in) { + ir_rvalue *new_param = param_rval; + + handle_rvalue(&new_param); + if (new_param != param_rval) { + param_rval->replace_with(new_param); + } + } + sig_iter.next(); + } + + return visit_continue_with_parent; +} + +bool +do_constant_folding(exec_list *instructions) +{ + ir_constant_folding_visitor constant_folding; + + visit_list_elements(&constant_folding, instructions); + + return constant_folding.progress; +} diff --git a/src/glsl/ir_constant_propagation.cpp b/src/glsl/ir_constant_propagation.cpp new file mode 100644 index 0000000000..76c1ce7013 --- /dev/null +++ b/src/glsl/ir_constant_propagation.cpp @@ -0,0 +1,435 @@ +/* + * Constantright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * constant of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, constant, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above constantright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR CONSTANTRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_constant_propagation.cpp + * + * Tracks assignments of constants to channels of variables, and + * usage of those constant channels with direct usage of the constants. + * + * This can lead to constant folding and algebraic optimizations in + * those later expressions, while causing no increase in instruction + * count (due to constants being generally free to load from a + * constant push buffer or as instruction immediate values) and + * possibly reducing register pressure. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_rvalue_visitor.h" +#include "ir_basic_block.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +class acp_entry : public exec_node +{ +public: + acp_entry(ir_variable *var, unsigned write_mask, ir_constant *constant) + { + assert(var); + assert(constant); + this->var = var; + this->write_mask = write_mask; + this->constant = constant; + } + + ir_variable *var; + ir_constant *constant; + unsigned write_mask; +}; + + +class kill_entry : public exec_node +{ +public: + kill_entry(ir_variable *var, unsigned write_mask) + { + assert(var); + this->var = var; + this->write_mask = write_mask; + } + + ir_variable *var; + unsigned write_mask; +}; + +class ir_constant_propagation_visitor : public ir_rvalue_visitor { +public: + ir_constant_propagation_visitor() + { + progress = false; + mem_ctx = talloc_new(0); + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + } + ~ir_constant_propagation_visitor() + { + talloc_free(mem_ctx); + } + + virtual ir_visitor_status visit_enter(class ir_loop *); + virtual ir_visitor_status visit_enter(class ir_function_signature *); + virtual ir_visitor_status visit_enter(class ir_function *); + virtual ir_visitor_status visit_enter(class ir_assignment *); + virtual ir_visitor_status visit_enter(class ir_call *); + virtual ir_visitor_status visit_enter(class ir_if *); + + void add_constant(ir_assignment *ir); + void kill(ir_variable *ir, unsigned write_mask); + void handle_if_block(exec_list *instructions); + void handle_rvalue(ir_rvalue **rvalue); + + /** List of acp_entry: The available constants to propagate */ + exec_list *acp; + + /** + * List of kill_entry: The masks of variables whose values were + * killed in this block. + */ + exec_list *kills; + + bool progress; + + bool killed_all; + + void *mem_ctx; +}; + + +void +ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + const glsl_type *type = (*rvalue)->type; + if (!type->is_scalar() && !type->is_vector()) + return; + + ir_swizzle *swiz = NULL; + ir_dereference_variable *deref = (*rvalue)->as_dereference_variable(); + if (!deref) { + swiz = (*rvalue)->as_swizzle(); + if (!swiz) + return; + + deref = swiz->val->as_dereference_variable(); + if (!deref) + return; + } + + ir_constant_data data; + memset(&data, 0, sizeof(data)); + + for (unsigned int i = 0; i < type->components(); i++) { + int channel; + acp_entry *found = NULL; + + if (swiz) { + switch (i) { + case 0: channel = swiz->mask.x; break; + case 1: channel = swiz->mask.y; break; + case 2: channel = swiz->mask.z; break; + case 3: channel = swiz->mask.w; break; + default: assert(!"shouldn't be reached"); channel = 0; break; + } + } else { + channel = i; + } + + foreach_iter(exec_list_iterator, iter, *this->acp) { + acp_entry *entry = (acp_entry *)iter.get(); + if (entry->var == deref->var && entry->write_mask & (1 << channel)) { + found = entry; + break; + } + } + + if (!found) + return; + + switch (type->base_type) { + case GLSL_TYPE_FLOAT: + data.f[i] = found->constant->value.f[channel]; + break; + case GLSL_TYPE_INT: + data.i[i] = found->constant->value.i[channel]; + break; + case GLSL_TYPE_UINT: + data.u[i] = found->constant->value.u[channel]; + break; + case GLSL_TYPE_BOOL: + data.b[i] = found->constant->value.b[channel]; + break; + default: + assert(!"not reached"); + break; + } + } + + *rvalue = new(talloc_parent(deref)) ir_constant(type, &data); + this->progress = true; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir) +{ + /* Treat entry into a function signature as a completely separate + * block. Any instructions at global scope will be shuffled into + * main() at link time, so they're irrelevant to us. + */ + exec_list *orig_acp = this->acp; + exec_list *orig_kills = this->kills; + bool orig_killed_all = this->killed_all; + + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + this->killed_all = false; + + visit_list_elements(this, &ir->body); + + this->kills = orig_kills; + this->acp = orig_acp; + this->killed_all = orig_killed_all; + + return visit_continue_with_parent; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_assignment *ir) +{ + /* Inline accepting children, skipping the LHS. */ + ir->rhs->accept(this); + handle_rvalue(&ir->rhs); + + if (ir->condition) { + ir->condition->accept(this); + handle_rvalue(&ir->condition); + } + + kill(ir->lhs->variable_referenced(), ir->write_mask); + + add_constant(ir); + + return visit_continue_with_parent; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_function *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_call *ir) +{ + /* Do constant propagation on call parameters, but skip any out params */ + exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator(); + foreach_iter(exec_list_iterator, iter, ir->actual_parameters) { + ir_variable *sig_param = (ir_variable *)sig_param_iter.get(); + ir_rvalue *param = (ir_rvalue *)iter.get(); + if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) { + ir_rvalue *new_param = param; + handle_rvalue(&new_param); + if (new_param != param) + param->replace_with(new_param); + else + param->accept(this); + } + sig_param_iter.next(); + } + + /* Since we're unlinked, we don't (necssarily) know the side effects of + * this call. So kill all copies. + */ + acp->make_empty(); + this->killed_all = true; + + return visit_continue_with_parent; +} + +void +ir_constant_propagation_visitor::handle_if_block(exec_list *instructions) +{ + exec_list *orig_acp = this->acp; + exec_list *orig_kills = this->kills; + bool orig_killed_all = this->killed_all; + + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + this->killed_all = false; + + /* Populate the initial acp with a constant of the original */ + foreach_iter(exec_list_iterator, iter, *orig_acp) { + acp_entry *a = (acp_entry *)iter.get(); + this->acp->push_tail(new(this->mem_ctx) acp_entry(a->var, a->write_mask, + a->constant)); + } + + visit_list_elements(this, instructions); + + if (this->killed_all) { + orig_acp->make_empty(); + } + + exec_list *new_kills = this->kills; + this->kills = orig_kills; + this->acp = orig_acp; + this->killed_all = this->killed_all || orig_killed_all; + + foreach_iter(exec_list_iterator, iter, *new_kills) { + kill_entry *k = (kill_entry *)iter.get(); + kill(k->var, k->write_mask); + } +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_if *ir) +{ + ir->condition->accept(this); + handle_rvalue(&ir->condition); + + handle_if_block(&ir->then_instructions); + handle_if_block(&ir->else_instructions); + + /* handle_if_block() already descended into the children. */ + return visit_continue_with_parent; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_loop *ir) +{ + exec_list *orig_acp = this->acp; + exec_list *orig_kills = this->kills; + bool orig_killed_all = this->killed_all; + + /* FINISHME: For now, the initial acp for loops is totally empty. + * We could go through once, then go through again with the acp + * cloned minus the killed entries after the first run through. + */ + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + this->killed_all = false; + + visit_list_elements(this, &ir->body_instructions); + + if (this->killed_all) { + orig_acp->make_empty(); + } + + exec_list *new_kills = this->kills; + this->kills = orig_kills; + this->acp = orig_acp; + this->killed_all = this->killed_all || orig_killed_all; + + foreach_iter(exec_list_iterator, iter, *new_kills) { + kill_entry *k = (kill_entry *)iter.get(); + kill(k->var, k->write_mask); + } + + /* already descended into the children. */ + return visit_continue_with_parent; +} + +void +ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask) +{ + assert(var != NULL); + + /* We don't track non-vectors. */ + if (!var->type->is_vector() && !var->type->is_scalar()) + return; + + /* Remove any entries currently in the ACP for this kill. */ + foreach_iter(exec_list_iterator, iter, *this->acp) { + acp_entry *entry = (acp_entry *)iter.get(); + + if (entry->var == var) { + entry->write_mask &= ~write_mask; + if (entry->write_mask == 0) + entry->remove(); + } + } + + /* Add this writemask of the variable to the list of killed + * variables in this block. + */ + foreach_iter(exec_list_iterator, iter, *this->kills) { + kill_entry *entry = (kill_entry *)iter.get(); + + if (entry->var == var) { + entry->write_mask |= write_mask; + return; + } + } + /* Not already in the list. Make new entry. */ + this->kills->push_tail(new(this->mem_ctx) kill_entry(var, write_mask)); +} + +/** + * Adds an entry to the available constant list if it's a plain assignment + * of a variable to a variable. + */ +void +ir_constant_propagation_visitor::add_constant(ir_assignment *ir) +{ + acp_entry *entry; + + if (ir->condition) { + ir_constant *condition = ir->condition->as_constant(); + if (!condition || !condition->value.b[0]) + return; + } + + if (!ir->write_mask) + return; + + ir_dereference_variable *deref = ir->lhs->as_dereference_variable(); + ir_constant *constant = ir->rhs->as_constant(); + + if (!deref || !constant) + return; + + /* Only do constant propagation on vectors. Constant matrices, + * arrays, or structures would require more work elsewhere. + */ + if (!deref->var->type->is_vector() && !deref->var->type->is_scalar()) + return; + + entry = new(this->mem_ctx) acp_entry(deref->var, ir->write_mask, constant); + this->acp->push_tail(entry); +} + +/** + * Does a constant propagation pass on the code present in the instruction stream. + */ +bool +do_constant_propagation(exec_list *instructions) +{ + ir_constant_propagation_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} diff --git a/src/glsl/ir_constant_variable.cpp b/src/glsl/ir_constant_variable.cpp new file mode 100644 index 0000000000..1fb73e765e --- /dev/null +++ b/src/glsl/ir_constant_variable.cpp @@ -0,0 +1,198 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_constant_variable.cpp + * + * Marks variables assigned a single constant value over the course + * of the program as constant. + * + * The goal here is to trigger further constant folding and then dead + * code elimination. This is common with vector/matrix constructors + * and calls to builtin functions. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +struct assignment_entry { + exec_node link; + int assignment_count; + ir_variable *var; + ir_constant *constval; + bool our_scope; +}; + +class ir_constant_variable_visitor : public ir_hierarchical_visitor { +public: + virtual ir_visitor_status visit_enter(ir_dereference_variable *); + virtual ir_visitor_status visit(ir_variable *); + virtual ir_visitor_status visit_enter(ir_assignment *); + virtual ir_visitor_status visit_enter(ir_call *); + + exec_list list; +}; + +static struct assignment_entry * +get_assignment_entry(ir_variable *var, exec_list *list) +{ + struct assignment_entry *entry; + + foreach_list_typed(struct assignment_entry, entry, link, list) { + if (entry->var == var) + return entry; + } + + entry = (struct assignment_entry *)calloc(1, sizeof(*entry)); + entry->var = var; + list->push_head(&entry->link); + return entry; +} + +ir_visitor_status +ir_constant_variable_visitor::visit(ir_variable *ir) +{ + struct assignment_entry *entry = get_assignment_entry(ir, &this->list); + entry->our_scope = true; + return visit_continue; +} + +/* Skip derefs of variables so that we can detect declarations. */ +ir_visitor_status +ir_constant_variable_visitor::visit_enter(ir_dereference_variable *ir) +{ + (void)ir; + return visit_continue_with_parent; +} + +ir_visitor_status +ir_constant_variable_visitor::visit_enter(ir_assignment *ir) +{ + ir_constant *constval; + struct assignment_entry *entry; + + entry = get_assignment_entry(ir->lhs->variable_referenced(), &this->list); + assert(entry); + entry->assignment_count++; + + /* If it's already constant, don't do the work. */ + if (entry->var->constant_value) + return visit_continue; + + /* OK, now find if we actually have all the right conditions for + * this to be a constant value assigned to the var. + */ + if (ir->condition) { + constval = ir->condition->constant_expression_value(); + if (!constval || !constval->value.b[0]) + return visit_continue; + } + + ir_variable *var = ir->whole_variable_written(); + if (!var) + return visit_continue; + + constval = ir->rhs->constant_expression_value(); + if (!constval) + return visit_continue; + + /* Mark this entry as having a constant assignment (if the + * assignment count doesn't go >1). do_constant_variable will fix + * up the variable with the constant value later. + */ + entry->constval = constval; + + return visit_continue; +} + +ir_visitor_status +ir_constant_variable_visitor::visit_enter(ir_call *ir) +{ + exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator(); + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param_rval = (ir_rvalue *)iter.get(); + ir_variable *param = (ir_variable *)sig_iter.get(); + + if (param->mode == ir_var_out || + param->mode == ir_var_inout) { + ir_variable *var = param_rval->variable_referenced(); + struct assignment_entry *entry; + + assert(var); + entry = get_assignment_entry(var, &this->list); + entry->assignment_count++; + } + sig_iter.next(); + } + return visit_continue; +} + +/** + * Does a copy propagation pass on the code present in the instruction stream. + */ +bool +do_constant_variable(exec_list *instructions) +{ + bool progress = false; + ir_constant_variable_visitor v; + + v.run(instructions); + + while (!v.list.is_empty()) { + + struct assignment_entry *entry; + entry = exec_node_data(struct assignment_entry, v.list.head, link); + + if (entry->assignment_count == 1 && entry->constval && entry->our_scope) { + entry->var->constant_value = entry->constval; + progress = true; + } + entry->link.remove(); + free(entry); + } + + return progress; +} + +bool +do_constant_variable_unlinked(exec_list *instructions) +{ + bool progress = false; + + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + ir_function *f = ir->as_function(); + if (f) { + foreach_iter(exec_list_iterator, sigiter, *f) { + ir_function_signature *sig = + (ir_function_signature *) sigiter.get(); + if (do_constant_variable(&sig->body)) + progress = true; + } + } + } + + return progress; +} diff --git a/src/glsl/ir_copy_propagation.cpp b/src/glsl/ir_copy_propagation.cpp new file mode 100644 index 0000000000..6c211f0e70 --- /dev/null +++ b/src/glsl/ir_copy_propagation.cpp @@ -0,0 +1,362 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_copy_propagation.cpp + * + * Moves usage of recently-copied variables to the previous copy of + * the variable. + * + * This should reduce the number of MOV instructions in the generated + * programs unless copy propagation is also done on the LIR, and may + * help anyway by triggering other optimizations that live in the HIR. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_basic_block.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +class acp_entry : public exec_node +{ +public: + acp_entry(ir_variable *lhs, ir_variable *rhs) + { + assert(lhs); + assert(rhs); + this->lhs = lhs; + this->rhs = rhs; + } + + ir_variable *lhs; + ir_variable *rhs; +}; + + +class kill_entry : public exec_node +{ +public: + kill_entry(ir_variable *var) + { + assert(var); + this->var = var; + } + + ir_variable *var; +}; + +class ir_copy_propagation_visitor : public ir_hierarchical_visitor { +public: + ir_copy_propagation_visitor() + { + progress = false; + mem_ctx = talloc_new(0); + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + } + ~ir_copy_propagation_visitor() + { + talloc_free(mem_ctx); + } + + virtual ir_visitor_status visit(class ir_dereference_variable *); + virtual ir_visitor_status visit_enter(class ir_loop *); + virtual ir_visitor_status visit_enter(class ir_function_signature *); + virtual ir_visitor_status visit_enter(class ir_function *); + virtual ir_visitor_status visit_enter(class ir_assignment *); + virtual ir_visitor_status visit_enter(class ir_call *); + virtual ir_visitor_status visit_enter(class ir_if *); + + void add_copy(ir_assignment *ir); + void kill(ir_variable *ir); + void handle_if_block(exec_list *instructions); + + /** List of acp_entry: The available copies to propagate */ + exec_list *acp; + /** + * List of kill_entry: The variables whose values were killed in this + * block. + */ + exec_list *kills; + + bool progress; + + bool killed_all; + + void *mem_ctx; +}; + +ir_visitor_status +ir_copy_propagation_visitor::visit_enter(ir_function_signature *ir) +{ + /* Treat entry into a function signature as a completely separate + * block. Any instructions at global scope will be shuffled into + * main() at link time, so they're irrelevant to us. + */ + exec_list *orig_acp = this->acp; + exec_list *orig_kills = this->kills; + bool orig_killed_all = this->killed_all; + + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + this->killed_all = false; + + visit_list_elements(this, &ir->body); + + this->kills = orig_kills; + this->acp = orig_acp; + this->killed_all = orig_killed_all; + + return visit_continue_with_parent; +} + +ir_visitor_status +ir_copy_propagation_visitor::visit_enter(ir_assignment *ir) +{ + ir_visitor_status s; + + /* ir_assignment::accept(ir_hv *v), skipping the LHS so that we can + * avoid copy propagating into the LHS. + * + * Note that this means we won't copy propagate into the derefs of + * an array index. Oh well. + */ + + s = ir->rhs->accept(this); + assert(s == visit_continue); + + if (ir->condition) { + s = ir->condition->accept(this); + assert(s == visit_continue); + } + + kill(ir->lhs->variable_referenced()); + + add_copy(ir); + + return visit_continue_with_parent; +} + +ir_visitor_status +ir_copy_propagation_visitor::visit_enter(ir_function *ir) +{ + (void) ir; + return visit_continue; +} + +/** + * Replaces dereferences of ACP RHS variables with ACP LHS variables. + * + * This is where the actual copy propagation occurs. Note that the + * rewriting of ir_dereference means that the ir_dereference instance + * must not be shared by multiple IR operations! + */ +ir_visitor_status +ir_copy_propagation_visitor::visit(ir_dereference_variable *ir) +{ + ir_variable *var = ir->var; + + foreach_iter(exec_list_iterator, iter, *this->acp) { + acp_entry *entry = (acp_entry *)iter.get(); + + if (var == entry->lhs) { + ir->var = entry->rhs; + this->progress = true; + break; + } + } + + return visit_continue; +} + + +ir_visitor_status +ir_copy_propagation_visitor::visit_enter(ir_call *ir) +{ + /* Do copy propagation on call parameters, but skip any out params */ + exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator(); + foreach_iter(exec_list_iterator, iter, ir->actual_parameters) { + ir_variable *sig_param = (ir_variable *)sig_param_iter.get(); + ir_instruction *ir = (ir_instruction *)iter.get(); + if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) { + ir->accept(this); + } + sig_param_iter.next(); + } + + /* Since we're unlinked, we don't (necssarily) know the side effects of + * this call. So kill all copies. + */ + acp->make_empty(); + this->killed_all = true; + + return visit_continue_with_parent; +} + +void +ir_copy_propagation_visitor::handle_if_block(exec_list *instructions) +{ + exec_list *orig_acp = this->acp; + exec_list *orig_kills = this->kills; + bool orig_killed_all = this->killed_all; + + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + this->killed_all = false; + + /* Populate the initial acp with a copy of the original */ + foreach_iter(exec_list_iterator, iter, *orig_acp) { + acp_entry *a = (acp_entry *)iter.get(); + this->acp->push_tail(new(this->mem_ctx) acp_entry(a->lhs, a->rhs)); + } + + visit_list_elements(this, instructions); + + if (this->killed_all) { + orig_acp->make_empty(); + } + + exec_list *new_kills = this->kills; + this->kills = orig_kills; + this->acp = orig_acp; + this->killed_all = this->killed_all || orig_killed_all; + + foreach_iter(exec_list_iterator, iter, *new_kills) { + kill_entry *k = (kill_entry *)iter.get(); + kill(k->var); + } +} + +ir_visitor_status +ir_copy_propagation_visitor::visit_enter(ir_if *ir) +{ + ir->condition->accept(this); + + handle_if_block(&ir->then_instructions); + handle_if_block(&ir->else_instructions); + + /* handle_if_block() already descended into the children. */ + return visit_continue_with_parent; +} + +ir_visitor_status +ir_copy_propagation_visitor::visit_enter(ir_loop *ir) +{ + exec_list *orig_acp = this->acp; + exec_list *orig_kills = this->kills; + bool orig_killed_all = this->killed_all; + + /* FINISHME: For now, the initial acp for loops is totally empty. + * We could go through once, then go through again with the acp + * cloned minus the killed entries after the first run through. + */ + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + this->killed_all = false; + + visit_list_elements(this, &ir->body_instructions); + + if (this->killed_all) { + orig_acp->make_empty(); + } + + exec_list *new_kills = this->kills; + this->kills = orig_kills; + this->acp = orig_acp; + this->killed_all = this->killed_all || orig_killed_all; + + foreach_iter(exec_list_iterator, iter, *new_kills) { + kill_entry *k = (kill_entry *)iter.get(); + kill(k->var); + } + + /* already descended into the children. */ + return visit_continue_with_parent; +} + +void +ir_copy_propagation_visitor::kill(ir_variable *var) +{ + assert(var != NULL); + + /* Remove any entries currently in the ACP for this kill. */ + foreach_iter(exec_list_iterator, iter, *acp) { + acp_entry *entry = (acp_entry *)iter.get(); + + if (entry->lhs == var || entry->rhs == var) { + entry->remove(); + } + } + + /* Add the LHS variable to the list of killed variables in this block. + */ + this->kills->push_tail(new(this->mem_ctx) kill_entry(var)); +} + +/** + * Adds an entry to the available copy list if it's a plain assignment + * of a variable to a variable. + */ +void +ir_copy_propagation_visitor::add_copy(ir_assignment *ir) +{ + acp_entry *entry; + + if (ir->condition) { + ir_constant *condition = ir->condition->as_constant(); + if (!condition || !condition->value.b[0]) + return; + } + + ir_variable *lhs_var = ir->whole_variable_written(); + ir_variable *rhs_var = ir->rhs->whole_variable_referenced(); + + if ((lhs_var != NULL) && (rhs_var != NULL)) { + if (lhs_var == rhs_var) { + /* This is a dumb assignment, but we've conveniently noticed + * it here. Removing it now would mess up the loop iteration + * calling us. Just flag it to not execute, and someone else + * will clean up the mess. + */ + ir->condition = new(talloc_parent(ir)) ir_constant(false); + this->progress = true; + } else { + entry = new(this->mem_ctx) acp_entry(lhs_var, rhs_var); + this->acp->push_tail(entry); + } + } +} + +/** + * Does a copy propagation pass on the code present in the instruction stream. + */ +bool +do_copy_propagation(exec_list *instructions) +{ + ir_copy_propagation_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} diff --git a/src/glsl/ir_dead_code.cpp b/src/glsl/ir_dead_code.cpp new file mode 100644 index 0000000000..5cf5e99add --- /dev/null +++ b/src/glsl/ir_dead_code.cpp @@ -0,0 +1,142 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_dead_code.cpp + * + * Eliminates dead assignments and variable declarations from the code. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_variable_refcount.h" +#include "glsl_types.h" + +static bool debug = false; + +/** + * Do a dead code pass over instructions and everything that instructions + * references. + * + * Note that this will remove assignments to globals, so it is not suitable + * for usage on an unlinked instruction stream. + */ +bool +do_dead_code(exec_list *instructions) +{ + ir_variable_refcount_visitor v; + bool progress = false; + + v.run(instructions); + + foreach_iter(exec_list_iterator, iter, v.variable_list) { + variable_entry *entry = (variable_entry *)iter.get(); + + /* Since each assignment is a reference, the refereneced count must be + * greater than or equal to the assignment count. If they are equal, + * then all of the references are assignments, and the variable is + * dead. + * + * Note that if the variable is neither assigned nor referenced, both + * counts will be zero and will be caught by the equality test. + */ + assert(entry->referenced_count >= entry->assigned_count); + + if (debug) { + printf("%s@%p: %d refs, %d assigns, %sdeclared in our scope\n", + entry->var->name, (void *) entry->var, + entry->referenced_count, entry->assigned_count, + entry->declaration ? "" : "not "); + } + + if ((entry->referenced_count > entry->assigned_count) + || !entry->declaration) + continue; + + if (entry->assign) { + /* Remove a single dead assignment to the variable we found. + * Don't do so if it's a shader output, though. + */ + if (entry->var->mode != ir_var_out && + entry->var->mode != ir_var_inout && + !ir_has_call(entry->assign)) { + entry->assign->remove(); + progress = true; + + if (debug) { + printf("Removed assignment to %s@%p\n", + entry->var->name, (void *) entry->var); + } + } + } else { + /* If there are no assignments or references to the variable left, + * then we can remove its declaration. + */ + + /* uniform initializers are precious, and could get used by another + * stage. + */ + if (entry->var->mode == ir_var_uniform && + entry->var->constant_value) + continue; + + entry->var->remove(); + progress = true; + + if (debug) { + printf("Removed declaration of %s@%p\n", + entry->var->name, (void *) entry->var); + } + } + } + + return progress; +} + +/** + * Does a dead code pass on the functions present in the instruction stream. + * + * This is suitable for use while the program is not linked, as it will + * ignore variable declarations (and the assignments to them) for variables + * with global scope. + */ +bool +do_dead_code_unlinked(exec_list *instructions) +{ + bool progress = false; + + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + ir_function *f = ir->as_function(); + if (f) { + foreach_iter(exec_list_iterator, sigiter, *f) { + ir_function_signature *sig = + (ir_function_signature *) sigiter.get(); + if (do_dead_code(&sig->body)) + progress = true; + } + } + } + + return progress; +} diff --git a/src/glsl/ir_dead_code_local.cpp b/src/glsl/ir_dead_code_local.cpp new file mode 100644 index 0000000000..4bbedf0ff9 --- /dev/null +++ b/src/glsl/ir_dead_code_local.cpp @@ -0,0 +1,229 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_dead_code_local.cpp + * + * Eliminates local dead assignments from the code. + * + * This operates on basic blocks, tracking assignments and finding if + * they're used before the variable is completely reassigned. + * + * Compare this to ir_dead_code.cpp, which operates globally looking + * for assignments to variables that are never read. + */ + +#include "ir.h" +#include "ir_basic_block.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +static bool debug = false; + +class assignment_entry : public exec_node +{ +public: + assignment_entry(ir_variable *lhs, ir_instruction *ir) + { + assert(lhs); + assert(ir); + this->lhs = lhs; + this->ir = ir; + } + + ir_variable *lhs; + ir_instruction *ir; +}; + +class kill_for_derefs_visitor : public ir_hierarchical_visitor { +public: + kill_for_derefs_visitor(exec_list *assignments) + { + this->assignments = assignments; + } + + virtual ir_visitor_status visit(ir_dereference_variable *ir) + { + ir_variable *const var = ir->variable_referenced(); + + foreach_iter(exec_list_iterator, iter, *this->assignments) { + assignment_entry *entry = (assignment_entry *)iter.get(); + + if (entry->lhs == var) { + if (debug) + printf("kill %s\n", entry->lhs->name); + entry->remove(); + } + } + + return visit_continue; + } + +private: + exec_list *assignments; +}; + +class array_index_visit : public ir_hierarchical_visitor { +public: + array_index_visit(ir_hierarchical_visitor *v) + { + this->visitor = v; + } + + virtual ir_visitor_status visit_enter(class ir_dereference_array *ir) + { + ir->array_index->accept(visitor); + return visit_continue; + } + + static void run(ir_instruction *ir, ir_hierarchical_visitor *v) + { + array_index_visit top_visit(v); + ir->accept(& top_visit); + } + + ir_hierarchical_visitor *visitor; +}; + + +/** + * Adds an entry to the available copy list if it's a plain assignment + * of a variable to a variable. + */ +static bool +process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments) +{ + ir_variable *var = NULL; + bool progress = false; + kill_for_derefs_visitor v(assignments); + + /* Kill assignment entries for things used to produce this assignment. */ + ir->rhs->accept(&v); + if (ir->condition) { + ir->condition->accept(&v); + } + + /* Kill assignment enties used as array indices. + */ + array_index_visit::run(ir->lhs, &v); + var = ir->lhs->variable_referenced(); + assert(var); + + bool always_assign = true; + if (ir->condition) { + ir_constant *condition = ir->condition->as_constant(); + if (!condition || !condition->value.b[0]) + always_assign = false; + } + + /* Now, check if we did a whole-variable assignment. */ + if (always_assign && (ir->whole_variable_written() != NULL)) { + /* We did a whole-variable assignment. So, any instruction in + * the assignment list with the same LHS is dead. + */ + if (debug) + printf("looking for %s to remove\n", var->name); + foreach_iter(exec_list_iterator, iter, *assignments) { + assignment_entry *entry = (assignment_entry *)iter.get(); + + if (entry->lhs == var) { + if (debug) + printf("removing %s\n", var->name); + entry->ir->remove(); + entry->remove(); + progress = true; + } + } + } + + /* Add this instruction to the assignment list available to be removed. + * But not if the assignment has other side effects. + */ + if (ir_has_call(ir)) + return progress; + + assignment_entry *entry = new(ctx) assignment_entry(var, ir); + assignments->push_tail(entry); + + if (debug) { + printf("add %s\n", var->name); + + printf("current entries\n"); + foreach_iter(exec_list_iterator, iter, *assignments) { + assignment_entry *entry = (assignment_entry *)iter.get(); + + printf(" %s\n", entry->lhs->name); + } + } + + return progress; +} + +static void +dead_code_local_basic_block(ir_instruction *first, + ir_instruction *last, + void *data) +{ + ir_instruction *ir, *ir_next; + /* List of avaialble_copy */ + exec_list assignments; + bool *out_progress = (bool *)data; + bool progress = false; + + void *ctx = talloc_new(NULL); + /* Safe looping, since process_assignment */ + for (ir = first, ir_next = (ir_instruction *)first->next;; + ir = ir_next, ir_next = (ir_instruction *)ir->next) { + ir_assignment *ir_assign = ir->as_assignment(); + + if (debug) { + ir->print(); + printf("\n"); + } + + if (ir_assign) { + progress = process_assignment(ctx, ir_assign, &assignments) || progress; + } else { + kill_for_derefs_visitor kill(&assignments); + ir->accept(&kill); + } + + if (ir == last) + break; + } + *out_progress = progress; + talloc_free(ctx); +} + +/** + * Does a copy propagation pass on the code present in the instruction stream. + */ +bool +do_dead_code_local(exec_list *instructions) +{ + bool progress = false; + + call_for_basic_blocks(instructions, dead_code_local_basic_block, &progress); + + return progress; +} diff --git a/src/glsl/ir_dead_functions.cpp b/src/glsl/ir_dead_functions.cpp new file mode 100644 index 0000000000..26554441d3 --- /dev/null +++ b/src/glsl/ir_dead_functions.cpp @@ -0,0 +1,151 @@ + /* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + /** + * \file ir_dead_functions.cpp + * + * Eliminates unused functions from the linked program. + */ + + #include "ir.h" + #include "ir_visitor.h" + #include "ir_expression_flattening.h" + #include "glsl_types.h" + + class signature_entry : public exec_node + { + public: + signature_entry(ir_function_signature *sig) + { + this->signature = sig; + this->used = false; + } + + ir_function_signature *signature; + bool used; + }; + + class ir_dead_functions_visitor : public ir_hierarchical_visitor { + public: + ir_dead_functions_visitor() + { + this->mem_ctx = talloc_new(NULL); + } + + ~ir_dead_functions_visitor() + { + talloc_free(this->mem_ctx); + } + + virtual ir_visitor_status visit_enter(ir_function_signature *); + virtual ir_visitor_status visit_enter(ir_call *); + + signature_entry *get_signature_entry(ir_function_signature *var); + + bool (*predicate)(ir_instruction *ir); + + /* List of signature_entry */ + exec_list signature_list; + void *mem_ctx; + }; + + + signature_entry * + ir_dead_functions_visitor::get_signature_entry(ir_function_signature *sig) + { + foreach_iter(exec_list_iterator, iter, this->signature_list) { + signature_entry *entry = (signature_entry *)iter.get(); + if (entry->signature == sig) + return entry; + } + + signature_entry *entry = new(mem_ctx) signature_entry(sig); + this->signature_list.push_tail(entry); + return entry; + } + + + ir_visitor_status + ir_dead_functions_visitor::visit_enter(ir_function_signature *ir) + { + signature_entry *entry = this->get_signature_entry(ir); + + if (strcmp(ir->function_name(), "main") == 0) { + entry->used = true; + } + + return visit_continue; + } + + + ir_visitor_status + ir_dead_functions_visitor::visit_enter(ir_call *ir) + { + signature_entry *entry = this->get_signature_entry(ir->get_callee()); + + entry->used = true; + + return visit_continue; +} + +bool +do_dead_functions(exec_list *instructions) +{ + ir_dead_functions_visitor v; + bool progress = false; + + visit_list_elements(&v, instructions); + + /* Now that we've figured out which function signatures are used, remove + * the unused ones, and remove function definitions that have no more + * signatures. + */ + foreach_iter(exec_list_iterator, iter, v.signature_list) { + signature_entry *entry = (signature_entry *)iter.get(); + + if (!entry->used) { + entry->signature->remove(); + progress = true; + } + delete(entry); + } + + /* We don't just do this above when we nuked a signature because of + * const pointers. + */ + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + ir_function *func = ir->as_function(); + + if (func && func->signatures.is_empty()) { + /* At this point (post-linking), the symbol table is no + * longer in use, so not removing the function from the + * symbol table should be OK. + */ + func->remove(); + progress = true; + } + } + + return progress; +} diff --git a/src/glsl/ir_div_to_mul_rcp.cpp b/src/glsl/ir_div_to_mul_rcp.cpp new file mode 100644 index 0000000000..640d5d64f9 --- /dev/null +++ b/src/glsl/ir_div_to_mul_rcp.cpp @@ -0,0 +1,115 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_div_to_mul_rcp.cpp + * + * Breaks an ir_unop_div expression down to op0 * (rcp(op1)). + * + * Many GPUs don't have a divide instruction (945 and 965 included), + * but they do have an RCP instruction to compute an approximate + * reciprocal. By breaking the operation down, constant reciprocals + * can get constant folded. + */ + +#include "ir.h" +#include "glsl_types.h" + +class ir_div_to_mul_rcp_visitor : public ir_hierarchical_visitor { +public: + ir_div_to_mul_rcp_visitor() + { + this->made_progress = false; + } + + ir_visitor_status visit_leave(ir_expression *); + + bool made_progress; +}; + +bool +do_div_to_mul_rcp(exec_list *instructions) +{ + ir_div_to_mul_rcp_visitor v; + + visit_list_elements(&v, instructions); + return v.made_progress; +} + +ir_visitor_status +ir_div_to_mul_rcp_visitor::visit_leave(ir_expression *ir) +{ + if (ir->operation != ir_binop_div) + return visit_continue; + + if (ir->operands[1]->type->base_type != GLSL_TYPE_INT && + ir->operands[1]->type->base_type != GLSL_TYPE_UINT) { + /* New expression for the 1.0 / op1 */ + ir_rvalue *expr; + expr = new(ir) ir_expression(ir_unop_rcp, + ir->operands[1]->type, + ir->operands[1], + NULL); + + /* op0 / op1 -> op0 * (1.0 / op1) */ + ir->operation = ir_binop_mul; + ir->operands[1] = expr; + } else { + /* Be careful with integer division -- we need to do it as a + * float and re-truncate, since rcp(n > 1) of an integer would + * just be 0. + */ + ir_rvalue *op0, *op1; + const struct glsl_type *vec_type; + + vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, + ir->operands[1]->type->vector_elements, + ir->operands[1]->type->matrix_columns); + + if (ir->operands[1]->type->base_type == GLSL_TYPE_INT) + op1 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[1], NULL); + else + op1 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[1], NULL); + + op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL); + + vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, + ir->operands[0]->type->vector_elements, + ir->operands[0]->type->matrix_columns); + + if (ir->operands[0]->type->base_type == GLSL_TYPE_INT) + op0 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[0], NULL); + else + op0 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[0], NULL); + + op0 = new(ir) ir_expression(ir_binop_mul, vec_type, op0, op1); + + ir->operation = ir_unop_f2i; + ir->operands[0] = op0; + ir->operands[1] = NULL; + } + + this->made_progress = true; + + return visit_continue; +} diff --git a/src/glsl/ir_explog_to_explog2.cpp b/src/glsl/ir_explog_to_explog2.cpp new file mode 100644 index 0000000000..78694a2029 --- /dev/null +++ b/src/glsl/ir_explog_to_explog2.cpp @@ -0,0 +1,85 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_explog_to_explog2.cpp + * + * Many GPUs don't have a base e log or exponent instruction, but they + * do have base 2 versions, so this pass converts exp and log to exp2 + * and log2 operations. + */ + +#include "main/core.h" /* for log2f on MSVC */ +#include "ir.h" +#include "glsl_types.h" + +class ir_explog_to_explog2_visitor : public ir_hierarchical_visitor { +public: + ir_explog_to_explog2_visitor() + { + this->progress = false; + } + + ir_visitor_status visit_leave(ir_expression *); + + bool progress; +}; + +bool +do_explog_to_explog2(exec_list *instructions) +{ + ir_explog_to_explog2_visitor v; + + visit_list_elements(&v, instructions); + return v.progress; +} + +ir_visitor_status +ir_explog_to_explog2_visitor::visit_leave(ir_expression *ir) +{ + if (ir->operation == ir_unop_exp) { + void *mem_ctx = talloc_parent(ir); + ir_constant *log2_e = new(mem_ctx) ir_constant(log2f(M_E)); + + ir->operation = ir_unop_exp2; + ir->operands[0] = new(mem_ctx) ir_expression(ir_binop_mul, + ir->operands[0]->type, + ir->operands[0], + log2_e); + this->progress = true; + } + + if (ir->operation == ir_unop_log) { + void *mem_ctx = talloc_parent(ir); + + ir->operation = ir_binop_mul; + ir->operands[0] = new(mem_ctx) ir_expression(ir_unop_log2, + ir->operands[0]->type, + ir->operands[0], + NULL); + ir->operands[1] = new(mem_ctx) ir_constant(1.0f / log2f(M_E)); + this->progress = true; + } + + return visit_continue; +} diff --git a/src/glsl/ir_expression_flattening.cpp b/src/glsl/ir_expression_flattening.cpp new file mode 100644 index 0000000000..7b1b8dbfef --- /dev/null +++ b/src/glsl/ir_expression_flattening.cpp @@ -0,0 +1,92 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_expression_flattening.cpp + * + * Takes the leaves of expression trees and makes them dereferences of + * assignments of the leaves to temporaries, according to a predicate. + * + * This is used for automatic function inlining, where we want to take + * an expression containing a call and move the call out to its own + * assignment so that we can inline it at the appropriate place in the + * instruction stream. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_rvalue_visitor.h" +#include "ir_expression_flattening.h" +#include "glsl_types.h" + +class ir_expression_flattening_visitor : public ir_rvalue_visitor { +public: + ir_expression_flattening_visitor(bool (*predicate)(ir_instruction *ir)) + { + this->predicate = predicate; + } + + virtual ~ir_expression_flattening_visitor() + { + /* empty */ + } + + void handle_rvalue(ir_rvalue **rvalue); + bool (*predicate)(ir_instruction *ir); +}; + +void +do_expression_flattening(exec_list *instructions, + bool (*predicate)(ir_instruction *ir)) +{ + ir_expression_flattening_visitor v(predicate); + + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + + ir->accept(&v); + } +} + +void +ir_expression_flattening_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + ir_variable *var; + ir_assignment *assign; + ir_rvalue *ir = *rvalue; + + if (!ir || !this->predicate(ir)) + return; + + void *ctx = talloc_parent(ir); + + var = new(ctx) ir_variable(ir->type, "flattening_tmp", ir_var_temporary); + base_ir->insert_before(var); + + assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var), + ir, + NULL); + base_ir->insert_before(assign); + + *rvalue = new(ctx) ir_dereference_variable(var); +} diff --git a/src/glsl/ir_expression_flattening.h b/src/glsl/ir_expression_flattening.h new file mode 100644 index 0000000000..2eda159000 --- /dev/null +++ b/src/glsl/ir_expression_flattening.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + +/** + * \file ir_expression_flattening.h + * + * Takes the leaves of expression trees and makes them dereferences of + * assignments of the leaves to temporaries, according to a predicate. + * + * This is used for automatic function inlining, where we want to take + * an expression containing a call and move the call out to its own + * assignment so that we can inline it at the appropriate place in the + * instruction stream. + */ + +void do_expression_flattening(exec_list *instructions, + bool (*predicate)(ir_instruction *ir)); diff --git a/src/glsl/ir_function.cpp b/src/glsl/ir_function.cpp new file mode 100644 index 0000000000..dfdec144b2 --- /dev/null +++ b/src/glsl/ir_function.cpp @@ -0,0 +1,227 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "glsl_types.h" +#include "ir.h" + +int +type_compare(const glsl_type *a, const glsl_type *b) +{ + /* If the types are the same, they trivially match. + */ + if (a == b) + return 0; + + switch (a->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_BOOL: + /* There is no implicit conversion to or from integer types or bool. + */ + if ((a->is_integer() != b->is_integer()) + || (a->is_boolean() != b->is_boolean())) + return -1; + + /* FALLTHROUGH */ + + case GLSL_TYPE_FLOAT: + if ((a->vector_elements != b->vector_elements) + || (a->matrix_columns != b->matrix_columns)) + return -1; + + return 1; + + case GLSL_TYPE_SAMPLER: + case GLSL_TYPE_STRUCT: + /* Samplers and structures must match exactly. + */ + return -1; + + case GLSL_TYPE_ARRAY: + if ((b->base_type != GLSL_TYPE_ARRAY) + || (a->length != b->length)) + return -1; + + /* From GLSL 1.50 spec, page 27 (page 33 of the PDF): + * "There are no implicit array or structure conversions." + * + * If the comparison of the array element types detects that a conversion + * would be required, the array types do not match. + */ + return (type_compare(a->fields.array, b->fields.array) == 0) ? 0 : -1; + + case GLSL_TYPE_FUNCTION: + case GLSL_TYPE_VOID: + case GLSL_TYPE_ERROR: + default: + /* These are all error conditions. It is invalid for a parameter to + * a function to be declared as error, void, or a function. + */ + return -1; + } + + /* This point should be unreachable. + */ + assert(0); +} + + +static int +parameter_lists_match(const exec_list *list_a, const exec_list *list_b) +{ + const exec_node *node_a = list_a->head; + const exec_node *node_b = list_b->head; + int total_score = 0; + + for (/* empty */ + ; !node_a->is_tail_sentinel() + ; node_a = node_a->next, node_b = node_b->next) { + /* If all of the parameters from the other parameter list have been + * exhausted, the lists have different length and, by definition, + * do not match. + */ + if (node_b->is_tail_sentinel()) + return -1; + + + const ir_variable *const param = (ir_variable *) node_a; + const ir_instruction *const actual = (ir_instruction *) node_b; + + /* Determine whether or not the types match. If the types are an + * exact match, the match score is zero. If the types don't match + * but the actual parameter can be coerced to the type of the declared + * parameter, the match score is one. + */ + int score; + switch ((enum ir_variable_mode)(param->mode)) { + case ir_var_auto: + case ir_var_uniform: + case ir_var_temporary: + /* These are all error conditions. It is invalid for a parameter to + * a function to be declared as auto (not in, out, or inout) or + * as uniform. + */ + assert(0); + return -1; + + case ir_var_in: + score = type_compare(param->type, actual->type); + break; + + case ir_var_out: + score = type_compare(actual->type, param->type); + break; + + case ir_var_inout: + /* Since there are no bi-directional automatic conversions (e.g., + * there is int -> float but no float -> int), inout parameters must + * be exact matches. + */ + score = (type_compare(actual->type, param->type) == 0) ? 0 : -1; + break; + + default: + assert(false); + } + + if (score < 0) + return -1; + + total_score += score; + } + + /* If all of the parameters from the other parameter list have been + * exhausted, the lists have different length and, by definition, do not + * match. + */ + if (!node_b->is_tail_sentinel()) + return -1; + + return total_score; +} + + +ir_function_signature * +ir_function::matching_signature(const exec_list *actual_parameters) +{ + ir_function_signature *match = NULL; + + foreach_iter(exec_list_iterator, iter, signatures) { + ir_function_signature *const sig = + (ir_function_signature *) iter.get(); + + const int score = parameter_lists_match(& sig->parameters, + actual_parameters); + + if (score == 0) + return sig; + + if (score > 0) { + if (match != NULL) + return NULL; + + match = sig; + } + } + + return match; +} + + +static bool +parameter_lists_match_exact(const exec_list *list_a, const exec_list *list_b) +{ + const exec_node *node_a = list_a->head; + const exec_node *node_b = list_b->head; + + for (/* empty */ + ; !node_a->is_tail_sentinel() && !node_b->is_tail_sentinel() + ; node_a = node_a->next, node_b = node_b->next) { + ir_variable *a = (ir_variable *) node_a; + ir_variable *b = (ir_variable *) node_b; + + /* If the types of the parameters do not match, the parameters lists + * are different. + */ + if (a->type != b->type) + return false; + } + + /* Unless both lists are exhausted, they differ in length and, by + * definition, do not match. + */ + return (node_a->is_tail_sentinel() == node_b->is_tail_sentinel()); +} + +ir_function_signature * +ir_function::exact_matching_signature(const exec_list *actual_parameters) +{ + foreach_iter(exec_list_iterator, iter, signatures) { + ir_function_signature *const sig = + (ir_function_signature *) iter.get(); + + if (parameter_lists_match_exact(&sig->parameters, actual_parameters)) + return sig; + } + return NULL; +} diff --git a/src/glsl/ir_function_can_inline.cpp b/src/glsl/ir_function_can_inline.cpp new file mode 100644 index 0000000000..8bb8e0d9ed --- /dev/null +++ b/src/glsl/ir_function_can_inline.cpp @@ -0,0 +1,71 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_function_can_inline.cpp + * + * Determines if we can inline a function call using ir_function_inlining.cpp. + * + * The primary restriction is that we can't return from the function + * other than as the last instruction. We could potentially work + * around this for some constructs by flattening control flow and + * moving the return to the end, or by using breaks from a do {} while + * (0) loop surrounding the function body. + */ + +#include "ir.h" + +class ir_function_can_inline_visitor : public ir_hierarchical_visitor { +public: + ir_function_can_inline_visitor() + { + this->num_returns = 0; + } + + virtual ir_visitor_status visit_enter(ir_return *); + + int num_returns; +}; + +ir_visitor_status +ir_function_can_inline_visitor::visit_enter(ir_return *ir) +{ + (void) ir; + this->num_returns++; + return visit_continue; +} + +bool +can_inline(ir_call *call) +{ + ir_function_can_inline_visitor v; + const ir_function_signature *callee = call->get_callee(); + + v.run((exec_list *) &callee->body); + + ir_instruction *last = (ir_instruction *)callee->body.get_tail(); + if (last && !last->as_return()) + v.num_returns++; + + return v.num_returns == 1; +} diff --git a/src/glsl/ir_function_inlining.cpp b/src/glsl/ir_function_inlining.cpp new file mode 100644 index 0000000000..874602c84f --- /dev/null +++ b/src/glsl/ir_function_inlining.cpp @@ -0,0 +1,417 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_function_inlining.cpp + * + * Replaces calls to functions with the body of the function. + */ + +#include <inttypes.h> +#include "ir.h" +#include "ir_visitor.h" +#include "ir_function_inlining.h" +#include "ir_expression_flattening.h" +#include "glsl_types.h" +#include "program/hash_table.h" + +static void +do_sampler_replacement(exec_list *instructions, + ir_variable *sampler, + ir_dereference *deref); + +class ir_function_inlining_visitor : public ir_hierarchical_visitor { +public: + ir_function_inlining_visitor() + { + progress = false; + } + + virtual ~ir_function_inlining_visitor() + { + /* empty */ + } + + virtual ir_visitor_status visit_enter(ir_expression *); + virtual ir_visitor_status visit_enter(ir_call *); + virtual ir_visitor_status visit_enter(ir_assignment *); + virtual ir_visitor_status visit_enter(ir_return *); + virtual ir_visitor_status visit_enter(ir_texture *); + virtual ir_visitor_status visit_enter(ir_swizzle *); + + bool progress; +}; + + +bool +automatic_inlining_predicate(ir_instruction *ir) +{ + ir_call *call = ir->as_call(); + + if (call && can_inline(call)) + return true; + + return false; +} + +bool +do_function_inlining(exec_list *instructions) +{ + ir_function_inlining_visitor v; + + do_expression_flattening(instructions, automatic_inlining_predicate); + + v.run(instructions); + + return v.progress; +} + +static void +replace_return_with_assignment(ir_instruction *ir, void *data) +{ + void *ctx = talloc_parent(ir); + ir_variable *retval = (ir_variable *)data; + ir_return *ret = ir->as_return(); + + if (ret) { + if (ret->value) { + ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval); + ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL)); + } else { + /* un-valued return has to be the last return, or we shouldn't + * have reached here. (see can_inline()). + */ + assert(ret->next->is_tail_sentinel()); + ret->remove(); + } + } +} + +ir_rvalue * +ir_call::generate_inline(ir_instruction *next_ir) +{ + void *ctx = talloc_parent(this); + ir_variable **parameters; + int num_parameters; + int i; + ir_variable *retval = NULL; + struct hash_table *ht; + + ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare); + + num_parameters = 0; + foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters) + num_parameters++; + + parameters = new ir_variable *[num_parameters]; + + /* Generate storage for the return value. */ + if (this->callee->return_type) { + retval = new(ctx) ir_variable(this->callee->return_type, "_ret_val", + ir_var_auto); + next_ir->insert_before(retval); + } + + /* Generate the declarations for the parameters to our inlined code, + * and set up the mapping of real function body variables to ours. + */ + i = 0; + exec_list_iterator sig_param_iter = this->callee->parameters.iterator(); + exec_list_iterator param_iter = this->actual_parameters.iterator(); + for (i = 0; i < num_parameters; i++) { + ir_variable *sig_param = (ir_variable *) sig_param_iter.get(); + ir_rvalue *param = (ir_rvalue *) param_iter.get(); + + /* Generate a new variable for the parameter. */ + if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) { + /* For samplers, we want the inlined sampler references + * referencing the passed in sampler variable, since that + * will have the location information, which an assignment of + * a sampler wouldn't. Fix it up below. + */ + parameters[i] = NULL; + } else { + parameters[i] = sig_param->clone(ctx, ht); + parameters[i]->mode = ir_var_auto; + next_ir->insert_before(parameters[i]); + } + + /* Move the actual param into our param variable if it's an 'in' type. */ + if (parameters[i] && (sig_param->mode == ir_var_in || + sig_param->mode == ir_var_inout)) { + ir_assignment *assign; + + assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(parameters[i]), + param, NULL); + next_ir->insert_before(assign); + } + + sig_param_iter.next(); + param_iter.next(); + } + + exec_list new_instructions; + + /* Generate the inlined body of the function to a new list */ + foreach_iter(exec_list_iterator, iter, callee->body) { + ir_instruction *ir = (ir_instruction *)iter.get(); + ir_instruction *new_ir = ir->clone(ctx, ht); + + new_instructions.push_tail(new_ir); + visit_tree(new_ir, replace_return_with_assignment, retval); + } + + /* If any samplers were passed in, replace any deref of the sampler + * with a deref of the sampler argument. + */ + param_iter = this->actual_parameters.iterator(); + sig_param_iter = this->callee->parameters.iterator(); + for (i = 0; i < num_parameters; i++) { + ir_instruction *const param = (ir_instruction *) param_iter.get(); + ir_variable *sig_param = (ir_variable *) sig_param_iter.get(); + + if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) { + ir_dereference *deref = param->as_dereference(); + + assert(deref); + do_sampler_replacement(&new_instructions, sig_param, deref); + } + param_iter.next(); + sig_param_iter.next(); + } + + /* Now push those new instructions in. */ + foreach_iter(exec_list_iterator, iter, new_instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + next_ir->insert_before(ir); + } + + /* Copy back the value of any 'out' parameters from the function body + * variables to our own. + */ + i = 0; + param_iter = this->actual_parameters.iterator(); + sig_param_iter = this->callee->parameters.iterator(); + for (i = 0; i < num_parameters; i++) { + ir_instruction *const param = (ir_instruction *) param_iter.get(); + const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get(); + + /* Move our param variable into the actual param if it's an 'out' type. */ + if (parameters[i] && (sig_param->mode == ir_var_out || + sig_param->mode == ir_var_inout)) { + ir_assignment *assign; + + assign = new(ctx) ir_assignment(param->clone(ctx, NULL)->as_rvalue(), + new(ctx) ir_dereference_variable(parameters[i]), + NULL); + next_ir->insert_before(assign); + } + + param_iter.next(); + sig_param_iter.next(); + } + + delete [] parameters; + + hash_table_dtor(ht); + + if (retval) + return new(ctx) ir_dereference_variable(retval); + else + return NULL; +} + + +ir_visitor_status +ir_function_inlining_visitor::visit_enter(ir_expression *ir) +{ + (void) ir; + return visit_continue_with_parent; +} + + +ir_visitor_status +ir_function_inlining_visitor::visit_enter(ir_return *ir) +{ + (void) ir; + return visit_continue_with_parent; +} + + +ir_visitor_status +ir_function_inlining_visitor::visit_enter(ir_texture *ir) +{ + (void) ir; + return visit_continue_with_parent; +} + + +ir_visitor_status +ir_function_inlining_visitor::visit_enter(ir_swizzle *ir) +{ + (void) ir; + return visit_continue_with_parent; +} + + +ir_visitor_status +ir_function_inlining_visitor::visit_enter(ir_call *ir) +{ + if (can_inline(ir)) { + /* If the call was part of some tree, then it should have been + * flattened out or we shouldn't have seen it because of a + * visit_continue_with_parent in this visitor. + */ + assert(ir == base_ir); + + (void) ir->generate_inline(ir); + ir->remove(); + this->progress = true; + } + + return visit_continue; +} + + +ir_visitor_status +ir_function_inlining_visitor::visit_enter(ir_assignment *ir) +{ + ir_call *call = ir->rhs->as_call(); + if (!call || !can_inline(call)) + return visit_continue; + + /* generates the parameter setup, function body, and returns the return + * value of the function + */ + ir_rvalue *rhs = call->generate_inline(ir); + assert(rhs); + + ir->rhs = rhs; + this->progress = true; + + return visit_continue; +} + +/** + * Replaces references to the "sampler" variable with a clone of "deref." + * + * From the spec, samplers can appear in the tree as function + * (non-out) parameters and as the result of array indexing and + * structure field selection. In our builtin implementation, they + * also appear in the sampler field of an ir_tex instruction. + */ + +class ir_sampler_replacement_visitor : public ir_hierarchical_visitor { +public: + ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref) + { + this->sampler = sampler; + this->deref = deref; + } + + virtual ~ir_sampler_replacement_visitor() + { + } + + virtual ir_visitor_status visit_leave(ir_call *); + virtual ir_visitor_status visit_leave(ir_dereference_array *); + virtual ir_visitor_status visit_leave(ir_dereference_record *); + virtual ir_visitor_status visit_leave(ir_texture *); + + void replace_deref(ir_dereference **deref); + void replace_rvalue(ir_rvalue **rvalue); + + ir_variable *sampler; + ir_dereference *deref; +}; + +void +ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref) +{ + ir_dereference_variable *deref_var = (*deref)->as_dereference_variable(); + if (deref_var && deref_var->var == this->sampler) { + *deref = this->deref->clone(talloc_parent(*deref), NULL); + } +} + +void +ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + ir_dereference *deref = (*rvalue)->as_dereference(); + + if (!deref) + return; + + replace_deref(&deref); + *rvalue = deref; +} + +ir_visitor_status +ir_sampler_replacement_visitor::visit_leave(ir_texture *ir) +{ + replace_deref(&ir->sampler); + + return visit_continue; +} + +ir_visitor_status +ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir) +{ + replace_rvalue(&ir->array); + return visit_continue; +} + +ir_visitor_status +ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir) +{ + replace_rvalue(&ir->record); + return visit_continue; +} + +ir_visitor_status +ir_sampler_replacement_visitor::visit_leave(ir_call *ir) +{ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param = (ir_rvalue *)iter.get(); + ir_rvalue *new_param = param; + replace_rvalue(&new_param); + + if (new_param != param) { + param->replace_with(new_param); + } + } + return visit_continue; +} + +static void +do_sampler_replacement(exec_list *instructions, + ir_variable *sampler, + ir_dereference *deref) +{ + ir_sampler_replacement_visitor v(sampler, deref); + + visit_list_elements(&v, instructions); +} diff --git a/src/glsl/ir_function_inlining.h b/src/glsl/ir_function_inlining.h new file mode 100644 index 0000000000..6db011bbca --- /dev/null +++ b/src/glsl/ir_function_inlining.h @@ -0,0 +1,30 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_function_inlining.h + * + * Replaces calls to functions with the body of the function. + */ + +bool can_inline(ir_call *call); diff --git a/src/glsl/ir_hierarchical_visitor.cpp b/src/glsl/ir_hierarchical_visitor.cpp new file mode 100644 index 0000000000..809b08ee62 --- /dev/null +++ b/src/glsl/ir_hierarchical_visitor.cpp @@ -0,0 +1,296 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ir.h" +#include "ir_hierarchical_visitor.h" + +ir_hierarchical_visitor::ir_hierarchical_visitor() +{ + this->base_ir = NULL; + this->callback = NULL; + this->data = NULL; +} + +ir_visitor_status +ir_hierarchical_visitor::visit(ir_variable *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit(ir_constant *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit(ir_loop_jump *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit(ir_dereference_variable *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_loop *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_loop *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_function_signature *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_function_signature *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_function *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_function *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_expression *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_expression *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_texture *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_texture *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_swizzle *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_swizzle *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_dereference_array *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_dereference_array *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_dereference_record *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_dereference_record *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_assignment *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_assignment *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_call *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_call *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_return *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_return *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_discard *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_discard *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_enter(ir_if *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit_leave(ir_if *ir) +{ + (void) ir; + return visit_continue; +} + +void +ir_hierarchical_visitor::run(exec_list *instructions) +{ + visit_list_elements(this, instructions); +} + + +void +visit_tree(ir_instruction *ir, + void (*callback)(class ir_instruction *ir, void *data), + void *data) +{ + ir_hierarchical_visitor v; + + v.callback = callback; + v.data = data; + + ir->accept(&v); +} diff --git a/src/glsl/ir_hierarchical_visitor.h b/src/glsl/ir_hierarchical_visitor.h new file mode 100644 index 0000000000..afa780dc91 --- /dev/null +++ b/src/glsl/ir_hierarchical_visitor.h @@ -0,0 +1,176 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef IR_HIERARCHICAL_VISITOR_H +#define IR_HIERARCHICAL_VISITOR_H + +/** + * Enumeration values returned by visit methods to guide processing + */ +enum ir_visitor_status { + visit_continue, /**< Continue visiting as normal. */ + visit_continue_with_parent, /**< Don't visit siblings, continue w/parent. */ + visit_stop /**< Stop visiting immediately. */ +}; + + +/** + * Base class of hierarchical visitors of IR instruction trees + * + * Hierarchical visitors differ from traditional visitors in a couple of + * important ways. Rather than having a single \c visit method for each + * subclass in the composite, there are three kinds of visit methods. + * Leaf-node classes have a traditional \c visit method. Internal-node + * classes have a \c visit_enter method, which is invoked just before + * processing child nodes, and a \c visit_leave method which is invoked just + * after processing child nodes. + * + * In addition, each visit method and the \c accept methods in the composite + * have a return value which guides the navigation. Any of the visit methods + * can choose to continue visiting the tree as normal (by returning \c + * visit_continue), terminate visiting any further nodes immediately (by + * returning \c visit_stop), or stop visiting sibling nodes (by returning \c + * visit_continue_with_parent). + * + * These two changes combine to allow nagivation of children to be implemented + * in the composite's \c accept method. The \c accept method for a leaf-node + * class will simply call the \c visit method, as usual, and pass its return + * value on. The \c accept method for internal-node classes will call the \c + * visit_enter method, call the \c accpet method of each child node, and, + * finally, call the \c visit_leave method. If any of these return a value + * other that \c visit_continue, the correct action must be taken. + * + * The final benefit is that the hierarchical visitor base class need not be + * abstract. Default implementations of every \c visit, \c visit_enter, and + * \c visit_leave method can be provided. By default each of these methods + * simply returns \c visit_continue. This allows a significant reduction in + * derived class code. + * + * For more information about hierarchical visitors, see: + * + * http://c2.com/cgi/wiki?HierarchicalVisitorPattern + * http://c2.com/cgi/wiki?HierarchicalVisitorDiscussion + */ + +class ir_hierarchical_visitor { +public: + ir_hierarchical_visitor(); + + /** + * \name Visit methods for leaf-node classes + */ + /*@{*/ + virtual ir_visitor_status visit(class ir_variable *); + virtual ir_visitor_status visit(class ir_constant *); + virtual ir_visitor_status visit(class ir_loop_jump *); + + /** + * ir_dereference_variable isn't technically a leaf, but it is treated as a + * leaf here for a couple reasons. By not automatically visiting the one + * child ir_variable node from the ir_dereference_variable, ir_variable + * nodes can always be handled as variable declarations. Code that used + * non-hierarchical visitors had to set an "in a dereference" flag to + * determine how to handle an ir_variable. By forcing the visitor to + * handle the ir_variable within the ir_dereference_variable visitor, this + * kludge can be avoided. + * + * In addition, I can envision no use for having separate enter and leave + * methods. Anything that could be done in the enter and leave methods + * that couldn't just be done in the visit method. + */ + virtual ir_visitor_status visit(class ir_dereference_variable *); + /*@}*/ + + /** + * \name Visit methods for internal-node classes + */ + /*@{*/ + virtual ir_visitor_status visit_enter(class ir_loop *); + virtual ir_visitor_status visit_leave(class ir_loop *); + virtual ir_visitor_status visit_enter(class ir_function_signature *); + virtual ir_visitor_status visit_leave(class ir_function_signature *); + virtual ir_visitor_status visit_enter(class ir_function *); + virtual ir_visitor_status visit_leave(class ir_function *); + virtual ir_visitor_status visit_enter(class ir_expression *); + virtual ir_visitor_status visit_leave(class ir_expression *); + virtual ir_visitor_status visit_enter(class ir_texture *); + virtual ir_visitor_status visit_leave(class ir_texture *); + virtual ir_visitor_status visit_enter(class ir_swizzle *); + virtual ir_visitor_status visit_leave(class ir_swizzle *); + virtual ir_visitor_status visit_enter(class ir_dereference_array *); + virtual ir_visitor_status visit_leave(class ir_dereference_array *); + virtual ir_visitor_status visit_enter(class ir_dereference_record *); + virtual ir_visitor_status visit_leave(class ir_dereference_record *); + virtual ir_visitor_status visit_enter(class ir_assignment *); + virtual ir_visitor_status visit_leave(class ir_assignment *); + virtual ir_visitor_status visit_enter(class ir_call *); + virtual ir_visitor_status visit_leave(class ir_call *); + virtual ir_visitor_status visit_enter(class ir_return *); + virtual ir_visitor_status visit_leave(class ir_return *); + virtual ir_visitor_status visit_enter(class ir_discard *); + virtual ir_visitor_status visit_leave(class ir_discard *); + virtual ir_visitor_status visit_enter(class ir_if *); + virtual ir_visitor_status visit_leave(class ir_if *); + /*@}*/ + + + /** + * Utility function to process a linked list of instructions with a visitor + */ + void run(struct exec_list *instructions); + + /* Some visitors may need to insert new variable declarations and + * assignments for portions of a subtree, which means they need a + * pointer to the current instruction in the stream, not just their + * node in the tree rooted at that instruction. + * + * This is implemented by visit_list_elements -- if the visitor is + * not called by it, nothing good will happen. + */ + class ir_instruction *base_ir; + + /** + * Callback function that is invoked on entry to each node visited. + * + * \warning + * Visitor classes derived from \c ir_hierarchical_visitor \b may \b not + * invoke this function. This can be used, for example, to cause the + * callback to be invoked on every node type execpt one. + */ + void (*callback)(class ir_instruction *ir, void *data); + + /** + * Extra data parameter passed to the per-node callback function + */ + void *data; +}; + +void visit_tree(ir_instruction *ir, + void (*callback)(class ir_instruction *ir, void *data), + void *data); + +ir_visitor_status visit_list_elements(ir_hierarchical_visitor *v, exec_list *l); + +#endif /* IR_HIERARCHICAL_VISITOR_H */ diff --git a/src/glsl/ir_hv_accept.cpp b/src/glsl/ir_hv_accept.cpp new file mode 100644 index 0000000000..6dae4ed2f3 --- /dev/null +++ b/src/glsl/ir_hv_accept.cpp @@ -0,0 +1,369 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ir.h" + +/** + * \file ir_hv_accept.cpp + * Implementations of all hierarchical visitor accept methods for IR + * instructions. + */ + +/** + * Process a list of nodes using a hierarchical vistor + * + * \warning + * This function will operate correctly if a node being processed is removed + * from the list. However, if nodes are added to the list after the node being + * processed, some of the added nodes may not be processed. + */ +ir_visitor_status +visit_list_elements(ir_hierarchical_visitor *v, exec_list *l) +{ + ir_instruction *prev_base_ir = v->base_ir; + + foreach_list_safe(n, l) { + ir_instruction *const ir = (ir_instruction *) n; + v->base_ir = ir; + ir_visitor_status s = ir->accept(v); + + if (s != visit_continue) + return s; + } + v->base_ir = prev_base_ir; + + return visit_continue; +} + + +ir_visitor_status +ir_variable::accept(ir_hierarchical_visitor *v) +{ + return v->visit(this); +} + + +ir_visitor_status +ir_loop::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = visit_list_elements(v, &this->body_instructions); + if (s == visit_stop) + return s; + + if (s != visit_continue_with_parent) { + if (this->from) { + s = this->from->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + } + + if (this->to) { + s = this->to->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + } + + if (this->increment) { + s = this->increment->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + } + } + + return v->visit_leave(this); +} + + +ir_visitor_status +ir_loop_jump::accept(ir_hierarchical_visitor *v) +{ + return v->visit(this); +} + + +ir_visitor_status +ir_function_signature::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = visit_list_elements(v, &this->parameters); + if (s == visit_stop) + return s; + + s = visit_list_elements(v, &this->body); + return (s == visit_stop) ? s : v->visit_leave(this); +} + + +ir_visitor_status +ir_function::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = visit_list_elements(v, &this->signatures); + return (s == visit_stop) ? s : v->visit_leave(this); +} + + +ir_visitor_status +ir_expression::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + for (unsigned i = 0; i < this->get_num_operands(); i++) { + switch (this->operands[i]->accept(v)) { + case visit_continue: + break; + + case visit_continue_with_parent: + // I wish for Java's labeled break-statement here. + goto done; + + case visit_stop: + return s; + } + } + +done: + return v->visit_leave(this); +} + +ir_visitor_status +ir_texture::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->sampler->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->coordinate->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + if (this->projector) { + s = this->projector->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + } + + if (this->shadow_comparitor) { + s = this->shadow_comparitor->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + } + + switch (this->op) { + case ir_tex: + break; + case ir_txb: + s = this->lod_info.bias->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + break; + case ir_txl: + case ir_txf: + s = this->lod_info.lod->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + break; + case ir_txd: + s = this->lod_info.grad.dPdx->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->lod_info.grad.dPdy->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + break; + } + + return (s == visit_stop) ? s : v->visit_leave(this); +} + + +ir_visitor_status +ir_swizzle::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->val->accept(v); + return (s == visit_stop) ? s : v->visit_leave(this); +} + + +ir_visitor_status +ir_dereference_variable::accept(ir_hierarchical_visitor *v) +{ + return v->visit(this); +} + + +ir_visitor_status +ir_dereference_array::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->array_index->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->array->accept(v); + return (s == visit_stop) ? s : v->visit_leave(this); +} + + +ir_visitor_status +ir_dereference_record::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->record->accept(v); + return (s == visit_stop) ? s : v->visit_leave(this); +} + + +ir_visitor_status +ir_assignment::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->lhs->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->rhs->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + if (this->condition) + s = this->condition->accept(v); + + return (s == visit_stop) ? s : v->visit_leave(this); +} + + +ir_visitor_status +ir_constant::accept(ir_hierarchical_visitor *v) +{ + return v->visit(this); +} + + +ir_visitor_status +ir_call::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = visit_list_elements(v, &this->actual_parameters); + if (s == visit_stop) + return s; + + return v->visit_leave(this); +} + + +ir_visitor_status +ir_return::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + ir_rvalue *val = this->get_value(); + if (val) { + s = val->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + } + + return v->visit_leave(this); +} + + +ir_visitor_status +ir_discard::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + if (this->condition != NULL) { + s = this->condition->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + } + + return v->visit_leave(this); +} + + +ir_visitor_status +ir_if::accept(ir_hierarchical_visitor *v) +{ + ir_visitor_status s = v->visit_enter(this); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + s = this->condition->accept(v); + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + + if (s != visit_continue_with_parent) { + s = visit_list_elements(v, &this->then_instructions); + if (s == visit_stop) + return s; + } + + if (s != visit_continue_with_parent) { + s = visit_list_elements(v, &this->else_instructions); + if (s == visit_stop) + return s; + } + + return v->visit_leave(this); +} diff --git a/src/glsl/ir_if_return.cpp b/src/glsl/ir_if_return.cpp new file mode 100644 index 0000000000..5ab8759958 --- /dev/null +++ b/src/glsl/ir_if_return.cpp @@ -0,0 +1,246 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_if_return.cpp + * + * This pass tries to normalize functions to always return from one + * place by moving around blocks of code in if statements. + * + * This helps on hardware with no branching support, and may even be a + * useful transform on hardware supporting control flow by turning + * masked returns into normal returns. + */ + +#include <string.h> +#include "glsl_types.h" +#include "ir.h" + +class ir_if_return_visitor : public ir_hierarchical_visitor { +public: + ir_if_return_visitor() + { + this->progress = false; + } + + ir_visitor_status visit_enter(ir_function_signature *); + ir_visitor_status visit_leave(ir_if *); + + ir_visitor_status move_outer_block_inside(ir_instruction *ir, + exec_list *inner_block); + void move_returns_after_block(ir_instruction *ir, + ir_return *then_return, + ir_return *else_return); + bool progress; +}; + +bool +do_if_return(exec_list *instructions) +{ + ir_if_return_visitor v; + + do { + v.progress = false; + visit_list_elements(&v, instructions); + } while (v.progress); + + return v.progress; +} + +/** + * Removes any instructions after a (unconditional) return, since they will + * never be executed. + */ +static void +truncate_after_instruction(ir_instruction *ir) +{ + if (!ir) + return; + + while (!ir->get_next()->is_tail_sentinel()) + ((ir_instruction *)ir->get_next())->remove(); +} + +/** + * Returns an ir_instruction of the first ir_return in the exec_list, or NULL. + */ +static ir_return * +find_return_in_block(exec_list *instructions) +{ + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + if (ir->ir_type == ir_type_return) + return (ir_return *)ir; + } + + return NULL; +} + +void +ir_if_return_visitor::move_returns_after_block(ir_instruction *ir, + ir_return *then_return, + ir_return *else_return) +{ + + if (!then_return->value) { + then_return->remove(); + else_return->remove(); + ir->insert_after(new(ir) ir_return(NULL)); + } else { + ir_assignment *assign; + ir_variable *new_var = new(ir) ir_variable(then_return->value->type, + "if_return_tmp", + ir_var_temporary); + ir->insert_before(new_var); + + assign = new(ir) ir_assignment(new(ir) ir_dereference_variable(new_var), + then_return->value, NULL); + then_return->replace_with(assign); + + assign = new(ir) ir_assignment(new(ir) ir_dereference_variable(new_var), + else_return->value, NULL); + else_return->replace_with(assign); + + ir_dereference_variable *deref = new(ir) ir_dereference_variable(new_var); + ir->insert_after(new(ir) ir_return(deref)); + } + this->progress = true; +} + +ir_visitor_status +ir_if_return_visitor::move_outer_block_inside(ir_instruction *ir, + exec_list *inner_block) +{ + if (!ir->get_next()->is_tail_sentinel()) { + while (!ir->get_next()->is_tail_sentinel()) { + ir_instruction *move_ir = (ir_instruction *)ir->get_next(); + + move_ir->remove(); + inner_block->push_tail(move_ir); + } + + /* If we move the instructions following ir inside the block, it + * will confuse the exec_list iteration in the parent that visited + * us. So stop the visit at this point. + */ + return visit_stop; + } else { + return visit_continue; + } +} + +/* Normalize a function to always have a return statement at the end. + * + * This avoids the ir_if handler needing to know whether it is at the + * top level of the function to know if there's an implicit return at + * the end of the outer block. + */ +ir_visitor_status +ir_if_return_visitor::visit_enter(ir_function_signature *ir) +{ + ir_return *ret; + + if (!ir->is_defined) + return visit_continue_with_parent; + if (strcmp(ir->function_name(), "main") == 0) + return visit_continue_with_parent; + + ret = find_return_in_block(&ir->body); + + if (ret) { + truncate_after_instruction(ret); + } else { + if (ir->return_type->is_void()) { + ir->body.push_tail(new(ir) ir_return(NULL)); + } else { + /* Probably, if we've got a function with a return value + * hitting this point, it's something like: + * + * float reduce_below_half(float val) + * { + * while () { + * if (val >= 0.5) + * val /= 2.0; + * else + * return val; + * } + * } + * + * So we gain a junk return statement of an undefined value + * at the end that never gets executed. However, a backend + * using this pass is probably desperate to get rid of + * function calls, so go ahead and do it for their sake in + * case it fixes apps. + */ + ir_variable *undef = new(ir) ir_variable(ir->return_type, + "if_return_undef", + ir_var_temporary); + ir->body.push_tail(undef); + + ir_dereference_variable *deref = new(ir) ir_dereference_variable(undef); + ir->body.push_tail(new(ir) ir_return(deref)); + } + } + + return visit_continue; +} + +ir_visitor_status +ir_if_return_visitor::visit_leave(ir_if *ir) +{ + ir_return *then_return; + ir_return *else_return; + + then_return = find_return_in_block(&ir->then_instructions); + else_return = find_return_in_block(&ir->else_instructions); + if (!then_return && !else_return) + return visit_continue; + + /* Trim off any trailing instructions after the return statements + * on both sides. + */ + truncate_after_instruction(then_return); + truncate_after_instruction(else_return); + + /* If both sides return, then we can move the returns to a single + * one outside the if statement. + */ + if (then_return && else_return) { + move_returns_after_block(ir, then_return, else_return); + return visit_continue; + } + + /* If only one side returns, then the block of code after the "if" + * is only executed by the other side, so those instructions don't + * need to be anywhere but that other side. + * + * This will usually pull a return statement up into the other + * side, so we'll trigger the above case on the next pass. + */ + if (then_return) { + return move_outer_block_inside(ir, &ir->else_instructions); + } else { + assert(else_return); + return move_outer_block_inside(ir, &ir->then_instructions); + } +} diff --git a/src/glsl/ir_if_simplification.cpp b/src/glsl/ir_if_simplification.cpp new file mode 100644 index 0000000000..6882ef72b9 --- /dev/null +++ b/src/glsl/ir_if_simplification.cpp @@ -0,0 +1,84 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_function_inlining.cpp + * + * Moves constant branches of if statements out to the surrounding + * instruction stream. + */ + +#include "ir.h" + +class ir_if_simplification_visitor : public ir_hierarchical_visitor { +public: + ir_if_simplification_visitor() + { + this->made_progress = false; + } + + ir_visitor_status visit_leave(ir_if *); + + bool made_progress; +}; + +bool +do_if_simplification(exec_list *instructions) +{ + ir_if_simplification_visitor v; + + v.run(instructions); + return v.made_progress; +} + + +ir_visitor_status +ir_if_simplification_visitor::visit_leave(ir_if *ir) +{ + /* FINISHME: Ideally there would be a way to note that the condition results + * FINISHME: in a constant before processing both of the other subtrees. + * FINISHME: This can probably be done with some flags, but it would take + * FINISHME: some work to get right. + */ + ir_constant *condition_constant = ir->condition->constant_expression_value(); + if (condition_constant) { + /* Move the contents of the one branch of the conditional + * that matters out. + */ + if (condition_constant->value.b[0]) { + foreach_iter(exec_list_iterator, then_iter, ir->then_instructions) { + ir_instruction *then_ir = (ir_instruction *)then_iter.get(); + ir->insert_before(then_ir); + } + } else { + foreach_iter(exec_list_iterator, else_iter, ir->else_instructions) { + ir_instruction *else_ir = (ir_instruction *)else_iter.get(); + ir->insert_before(else_ir); + } + } + ir->remove(); + this->made_progress = true; + } + + return visit_continue; +} diff --git a/src/glsl/ir_if_to_cond_assign.cpp b/src/glsl/ir_if_to_cond_assign.cpp new file mode 100644 index 0000000000..0b87413941 --- /dev/null +++ b/src/glsl/ir_if_to_cond_assign.cpp @@ -0,0 +1,168 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_if_to_cond_assign.cpp + * + * This attempts to flatten all if statements to conditional + * assignments for GPUs that don't do control flow. + * + * It can't handle other control flow being inside of its block, such + * as calls or loops. Hopefully loop unrolling and inlining will take + * care of those. + */ + +#include "glsl_types.h" +#include "ir.h" + +class ir_if_to_cond_assign_visitor : public ir_hierarchical_visitor { +public: + ir_if_to_cond_assign_visitor() + { + this->progress = false; + } + + ir_visitor_status visit_leave(ir_if *); + + bool progress; +}; + +bool +do_if_to_cond_assign(exec_list *instructions) +{ + ir_if_to_cond_assign_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} + +void +check_control_flow(ir_instruction *ir, void *data) +{ + bool *found_control_flow = (bool *)data; + switch (ir->ir_type) { + case ir_type_call: + case ir_type_discard: + case ir_type_loop: + case ir_type_loop_jump: + case ir_type_return: + *found_control_flow = true; + break; + default: + break; + } +} + +void +move_block_to_cond_assign(void *mem_ctx, + ir_if *if_ir, ir_variable *cond_var, bool then) +{ + exec_list *instructions; + + if (then) { + instructions = &if_ir->then_instructions; + } else { + instructions = &if_ir->else_instructions; + } + + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + + if (ir->ir_type == ir_type_assignment) { + ir_assignment *assign = (ir_assignment *)ir; + ir_rvalue *cond_expr; + ir_dereference *deref = new(mem_ctx) ir_dereference_variable(cond_var); + + if (then) { + cond_expr = deref; + } else { + cond_expr = new(mem_ctx) ir_expression(ir_unop_logic_not, + glsl_type::bool_type, + deref, + NULL); + } + + if (!assign->condition) { + assign->condition = cond_expr; + } else { + assign->condition = new(mem_ctx) ir_expression(ir_binop_logic_and, + glsl_type::bool_type, + cond_expr, + assign->condition); + } + } + + /* Now, move from the if block to the block surrounding it. */ + ir->remove(); + if_ir->insert_before(ir); + } +} + +ir_visitor_status +ir_if_to_cond_assign_visitor::visit_leave(ir_if *ir) +{ + bool found_control_flow = false; + ir_variable *cond_var; + ir_assignment *assign; + ir_dereference_variable *deref; + + /* Check that both blocks don't contain anything we can't support. */ + foreach_iter(exec_list_iterator, then_iter, ir->then_instructions) { + ir_instruction *then_ir = (ir_instruction *)then_iter.get(); + visit_tree(then_ir, check_control_flow, &found_control_flow); + } + foreach_iter(exec_list_iterator, else_iter, ir->else_instructions) { + ir_instruction *else_ir = (ir_instruction *)else_iter.get(); + visit_tree(else_ir, check_control_flow, &found_control_flow); + } + if (found_control_flow) + return visit_continue; + + void *mem_ctx = talloc_parent(ir); + + /* Store the condition to a variable so the assignment conditions are + * simpler. + */ + cond_var = new(mem_ctx) ir_variable(glsl_type::bool_type, + "if_to_cond_assign_condition", + ir_var_temporary); + ir->insert_before(cond_var); + + deref = new(mem_ctx) ir_dereference_variable(cond_var); + assign = new(mem_ctx) ir_assignment(deref, + ir->condition, NULL); + ir->insert_before(assign); + + /* Now, move all of the instructions out of the if blocks, putting + * conditions on assignments. + */ + move_block_to_cond_assign(mem_ctx, ir, cond_var, true); + move_block_to_cond_assign(mem_ctx, ir, cond_var, false); + + ir->remove(); + + this->progress = true; + + return visit_continue; +} diff --git a/src/glsl/ir_import_prototypes.cpp b/src/glsl/ir_import_prototypes.cpp new file mode 100644 index 0000000000..a39b384071 --- /dev/null +++ b/src/glsl/ir_import_prototypes.cpp @@ -0,0 +1,138 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_import_prototypes.cpp + * Import function prototypes from one IR tree into another. + * + * \author Ian Romanick + */ +#include <cstdio> +#include "ir.h" +#include "glsl_symbol_table.h" + +/** + * Visitor used to import function prototypes + * + * Normally the \c clone method of either \c ir_function or + * \c ir_function_signature could be used. However, we don't want a complete + * clone of the \c ir_function_signature. We want everything \b except the + * body of the function. + */ +class import_prototype_visitor : public ir_hierarchical_visitor { +public: + /** + */ + import_prototype_visitor(exec_list *list, glsl_symbol_table *symbols, + void *mem_ctx) + { + this->mem_ctx = mem_ctx; + this->list = list; + this->symbols = symbols; + this->function = NULL; + } + + virtual ir_visitor_status visit_enter(ir_function *ir) + { + assert(this->function == NULL); + + this->function = this->symbols->get_function(ir->name); + if (!this->function) { + this->function = new(this->mem_ctx) ir_function(ir->name); + this->function->is_builtin = ir->is_builtin; + + list->push_tail(this->function); + + /* Add the new function to the symbol table. + */ + this->symbols->add_function(this->function->name, this->function); + } + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_function *ir) + { + (void) ir; + assert(this->function != NULL); + + this->function = NULL; + return visit_continue; + } + + ir_visitor_status visit_enter(ir_function_signature *ir) + { + assert(this->function != NULL); + + ir_function_signature *copy = + new(mem_ctx) ir_function_signature(ir->return_type); + + copy->is_defined = false; + + /* Clone the parameter list, but NOT the body. + */ + foreach_list_const(node, &ir->parameters) { + const ir_variable *const param = (const ir_variable *) node; + + assert(const_cast<ir_variable *>(param)->as_variable() != NULL); + + ir_variable *const param_copy = param->clone(mem_ctx, NULL); + copy->parameters.push_tail(param_copy); + } + + this->function->add_signature(copy); + + /* Do not process child nodes of the ir_function_signature. There can + * never be any nodes inside the ir_function_signature that we care + * about. Instead continue with the next sibling. + */ + return visit_continue_with_parent; + } + +private: + exec_list *list; + ir_function *function; + glsl_symbol_table *symbols; + void *mem_ctx; +}; + + +/** + * Import function prototypes from one IR tree into another + * + * \param source Source instruction stream containing functions whose + * prototypes are to be imported + * \param dest Destination instruction stream where new \c ir_function and + * \c ir_function_signature nodes will be stored + * \param symbols Symbol table where new functions will be stored + * \param mem_ctx talloc memory context used for new allocations + */ +void +import_prototypes(const exec_list *source, exec_list *dest, + glsl_symbol_table *symbols, void *mem_ctx) +{ + import_prototype_visitor v(dest, symbols, mem_ctx); + + /* Making source be const is just extra documentation. + */ + v.run(const_cast<exec_list *>(source)); +} diff --git a/src/glsl/ir_mat_op_to_vec.cpp b/src/glsl/ir_mat_op_to_vec.cpp new file mode 100644 index 0000000000..da6de9492b --- /dev/null +++ b/src/glsl/ir_mat_op_to_vec.cpp @@ -0,0 +1,491 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_mat_op_to_vec.cpp + * + * Breaks matrix operation expressions down to a series of vector operations. + * + * Generally this is how we have to codegen matrix operations for a + * GPU, so this gives us the chance to constant fold operations on a + * column or row. + */ + +#include "ir.h" +#include "ir_expression_flattening.h" +#include "glsl_types.h" + +class ir_mat_op_to_vec_visitor : public ir_hierarchical_visitor { +public: + ir_mat_op_to_vec_visitor() + { + this->made_progress = false; + this->mem_ctx = NULL; + } + + ir_visitor_status visit_leave(ir_assignment *); + + ir_dereference *get_column(ir_variable *var, int col); + ir_rvalue *get_element(ir_variable *var, int col, int row); + + void do_mul_mat_mat(ir_variable *result_var, + ir_variable *a_var, ir_variable *b_var); + void do_mul_mat_vec(ir_variable *result_var, + ir_variable *a_var, ir_variable *b_var); + void do_mul_vec_mat(ir_variable *result_var, + ir_variable *a_var, ir_variable *b_var); + void do_mul_mat_scalar(ir_variable *result_var, + ir_variable *a_var, ir_variable *b_var); + void do_equal_mat_mat(ir_variable *result_var, ir_variable *a_var, + ir_variable *b_var, bool test_equal); + + void *mem_ctx; + bool made_progress; +}; + +static bool +mat_op_to_vec_predicate(ir_instruction *ir) +{ + ir_expression *expr = ir->as_expression(); + unsigned int i; + + if (!expr) + return false; + + for (i = 0; i < expr->get_num_operands(); i++) { + if (expr->operands[i]->type->is_matrix()) + return true; + } + + return false; +} + +bool +do_mat_op_to_vec(exec_list *instructions) +{ + ir_mat_op_to_vec_visitor v; + + /* Pull out any matrix expression to a separate assignment to a + * temp. This will make our handling of the breakdown to + * operations on the matrix's vector components much easier. + */ + do_expression_flattening(instructions, mat_op_to_vec_predicate); + + visit_list_elements(&v, instructions); + + return v.made_progress; +} + +ir_rvalue * +ir_mat_op_to_vec_visitor::get_element(ir_variable *var, int col, int row) +{ + ir_dereference *deref; + + deref = new(mem_ctx) ir_dereference_variable(var); + + if (var->type->is_matrix()) { + deref = new(mem_ctx) ir_dereference_array(var, + new(mem_ctx) ir_constant(col)); + } else { + assert(col == 0); + } + + return new(mem_ctx) ir_swizzle(deref, row, 0, 0, 0, 1); +} + +ir_dereference * +ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int row) +{ + ir_dereference *deref; + + if (!var->type->is_matrix()) { + deref = new(mem_ctx) ir_dereference_variable(var); + } else { + deref = new(mem_ctx) ir_dereference_variable(var); + deref = new(mem_ctx) ir_dereference_array(deref, + new(mem_ctx) ir_constant(row)); + } + + return deref; +} + +void +ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_variable *result_var, + ir_variable *a_var, + ir_variable *b_var) +{ + int b_col, i; + ir_assignment *assign; + ir_expression *expr; + + for (b_col = 0; b_col < b_var->type->matrix_columns; b_col++) { + ir_rvalue *a = get_column(a_var, 0); + ir_rvalue *b = get_element(b_var, b_col, 0); + + /* first column */ + expr = new(mem_ctx) ir_expression(ir_binop_mul, + a->type, + a, + b); + + /* following columns */ + for (i = 1; i < a_var->type->matrix_columns; i++) { + ir_expression *mul_expr; + + a = get_column(a_var, i); + b = get_element(b_var, b_col, i); + + mul_expr = new(mem_ctx) ir_expression(ir_binop_mul, + a->type, + a, + b); + expr = new(mem_ctx) ir_expression(ir_binop_add, + a->type, + expr, + mul_expr); + } + + ir_rvalue *result = get_column(result_var, b_col); + assign = new(mem_ctx) ir_assignment(result, + expr, + NULL); + base_ir->insert_before(assign); + } +} + +void +ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_variable *result_var, + ir_variable *a_var, + ir_variable *b_var) +{ + int i; + ir_rvalue *a = get_column(a_var, 0); + ir_rvalue *b = get_element(b_var, 0, 0); + ir_assignment *assign; + ir_expression *expr; + + /* first column */ + expr = new(mem_ctx) ir_expression(ir_binop_mul, + result_var->type, + a, + b); + + /* following columns */ + for (i = 1; i < a_var->type->matrix_columns; i++) { + ir_expression *mul_expr; + + a = get_column(a_var, i); + b = get_element(b_var, 0, i); + + mul_expr = new(mem_ctx) ir_expression(ir_binop_mul, + result_var->type, + a, + b); + expr = new(mem_ctx) ir_expression(ir_binop_add, + result_var->type, + expr, + mul_expr); + } + + ir_rvalue *result = new(mem_ctx) ir_dereference_variable(result_var); + assign = new(mem_ctx) ir_assignment(result, + expr, + NULL); + base_ir->insert_before(assign); +} + +void +ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_variable *result_var, + ir_variable *a_var, + ir_variable *b_var) +{ + int i; + + for (i = 0; i < b_var->type->matrix_columns; i++) { + ir_rvalue *a = new(mem_ctx) ir_dereference_variable(a_var); + ir_rvalue *b = get_column(b_var, i); + ir_rvalue *result; + ir_expression *column_expr; + ir_assignment *column_assign; + + result = new(mem_ctx) ir_dereference_variable(result_var); + result = new(mem_ctx) ir_swizzle(result, i, 0, 0, 0, 1); + + column_expr = new(mem_ctx) ir_expression(ir_binop_dot, + result->type, + a, + b); + + column_assign = new(mem_ctx) ir_assignment(result, + column_expr, + NULL); + base_ir->insert_before(column_assign); + } +} + +void +ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_variable *result_var, + ir_variable *a_var, + ir_variable *b_var) +{ + int i; + + for (i = 0; i < a_var->type->matrix_columns; i++) { + ir_rvalue *a = get_column(a_var, i); + ir_rvalue *b = new(mem_ctx) ir_dereference_variable(b_var); + ir_rvalue *result = get_column(result_var, i); + ir_expression *column_expr; + ir_assignment *column_assign; + + column_expr = new(mem_ctx) ir_expression(ir_binop_mul, + result->type, + a, + b); + + column_assign = new(mem_ctx) ir_assignment(result, + column_expr, + NULL); + base_ir->insert_before(column_assign); + } +} + +void +ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_variable *result_var, + ir_variable *a_var, + ir_variable *b_var, + bool test_equal) +{ + /* This essentially implements the following GLSL: + * + * bool equal(mat4 a, mat4 b) + * { + * return !any(bvec4(a[0] != b[0], + * a[1] != b[1], + * a[2] != b[2], + * a[3] != b[3]); + * } + * + * bool nequal(mat4 a, mat4 b) + * { + * return any(bvec4(a[0] != b[0], + * a[1] != b[1], + * a[2] != b[2], + * a[3] != b[3]); + * } + */ + const unsigned columns = a_var->type->matrix_columns; + const glsl_type *const bvec_type = + glsl_type::get_instance(GLSL_TYPE_BOOL, columns, 1); + + ir_variable *const tmp_bvec = + new(this->mem_ctx) ir_variable(bvec_type, "mat_cmp_bvec", + ir_var_temporary); + this->base_ir->insert_before(tmp_bvec); + + for (unsigned i = 0; i < columns; i++) { + ir_dereference *const op0 = get_column(a_var, i); + ir_dereference *const op1 = get_column(b_var, i); + + ir_expression *const cmp = + new(this->mem_ctx) ir_expression(ir_binop_nequal, + glsl_type::bool_type, op0, op1); + + ir_rvalue *const swiz = + new(this->mem_ctx) ir_swizzle(cmp, i, i, i, i, columns); + + ir_dereference *const lhs = + new(this->mem_ctx) ir_dereference_variable(tmp_bvec); + + ir_assignment *const assign = + new(this->mem_ctx) ir_assignment(lhs, swiz, NULL, (1U << i)); + + this->base_ir->insert_before(assign); + } + + ir_rvalue *const val = + new(this->mem_ctx) ir_dereference_variable(tmp_bvec); + + ir_expression *any = + new(this->mem_ctx) ir_expression(ir_unop_any, glsl_type::bool_type, + val, NULL); + + if (test_equal) + any = new(this->mem_ctx) ir_expression(ir_unop_logic_not, + glsl_type::bool_type, + any, NULL); + + ir_rvalue *const result = + new(this->mem_ctx) ir_dereference_variable(result_var); + + ir_assignment *const assign = + new(mem_ctx) ir_assignment(result, any, NULL); + base_ir->insert_before(assign); +} + +static bool +has_matrix_operand(const ir_expression *expr, unsigned &columns) +{ + for (unsigned i = 0; i < expr->get_num_operands(); i++) { + if (expr->operands[i]->type->is_matrix()) { + columns = expr->operands[i]->type->matrix_columns; + return true; + } + } + + return false; +} + + +ir_visitor_status +ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign) +{ + ir_expression *orig_expr = orig_assign->rhs->as_expression(); + unsigned int i, matrix_columns = 1; + ir_variable *op_var[2]; + + if (!orig_expr) + return visit_continue; + + if (!has_matrix_operand(orig_expr, matrix_columns)) + return visit_continue; + + mem_ctx = talloc_parent(orig_assign); + + ir_dereference_variable *lhs_deref = + orig_assign->lhs->as_dereference_variable(); + assert(lhs_deref); + + ir_variable *result_var = lhs_deref->var; + + /* Store the expression operands in temps so we can use them + * multiple times. + */ + for (i = 0; i < orig_expr->get_num_operands(); i++) { + ir_assignment *assign; + + op_var[i] = new(mem_ctx) ir_variable(orig_expr->operands[i]->type, + "mat_op_to_vec", + ir_var_temporary); + base_ir->insert_before(op_var[i]); + + lhs_deref = new(mem_ctx) ir_dereference_variable(op_var[i]); + assign = new(mem_ctx) ir_assignment(lhs_deref, + orig_expr->operands[i], + NULL); + base_ir->insert_before(assign); + } + + /* OK, time to break down this matrix operation. */ + switch (orig_expr->operation) { + case ir_unop_neg: { + const unsigned mask = (1U << result_var->type->vector_elements) - 1; + + /* Apply the operation to each column.*/ + for (i = 0; i < matrix_columns; i++) { + ir_rvalue *op0 = get_column(op_var[0], i); + ir_dereference *result = get_column(result_var, i); + ir_expression *column_expr; + ir_assignment *column_assign; + + column_expr = new(mem_ctx) ir_expression(orig_expr->operation, + result->type, + op0, + NULL); + + column_assign = new(mem_ctx) ir_assignment(result, + column_expr, + NULL, + mask); + assert(column_assign->write_mask != 0); + base_ir->insert_before(column_assign); + } + break; + } + case ir_binop_add: + case ir_binop_sub: + case ir_binop_div: + case ir_binop_mod: { + const unsigned mask = (1U << result_var->type->vector_elements) - 1; + + /* For most operations, the matrix version is just going + * column-wise through and applying the operation to each column + * if available. + */ + for (i = 0; i < matrix_columns; i++) { + ir_rvalue *op0 = get_column(op_var[0], i); + ir_rvalue *op1 = get_column(op_var[1], i); + ir_dereference *result = get_column(result_var, i); + ir_expression *column_expr; + ir_assignment *column_assign; + + column_expr = new(mem_ctx) ir_expression(orig_expr->operation, + result->type, + op0, + op1); + + column_assign = new(mem_ctx) ir_assignment(result, + column_expr, + NULL, + mask); + assert(column_assign->write_mask != 0); + base_ir->insert_before(column_assign); + } + break; + } + case ir_binop_mul: + if (op_var[0]->type->is_matrix()) { + if (op_var[1]->type->is_matrix()) { + do_mul_mat_mat(result_var, op_var[0], op_var[1]); + } else if (op_var[1]->type->is_vector()) { + do_mul_mat_vec(result_var, op_var[0], op_var[1]); + } else { + assert(op_var[1]->type->is_scalar()); + do_mul_mat_scalar(result_var, op_var[0], op_var[1]); + } + } else { + assert(op_var[1]->type->is_matrix()); + if (op_var[0]->type->is_vector()) { + do_mul_vec_mat(result_var, op_var[0], op_var[1]); + } else { + assert(op_var[0]->type->is_scalar()); + do_mul_mat_scalar(result_var, op_var[1], op_var[0]); + } + } + break; + + case ir_binop_equal: + case ir_binop_nequal: + do_equal_mat_mat(result_var, op_var[1], op_var[0], + (orig_expr->operation == ir_binop_equal)); + break; + + default: + printf("FINISHME: Handle matrix operation for %s\n", + orig_expr->operator_string()); + abort(); + } + orig_assign->remove(); + this->made_progress = true; + + return visit_continue; +} diff --git a/src/glsl/ir_mod_to_fract.cpp b/src/glsl/ir_mod_to_fract.cpp new file mode 100644 index 0000000000..71c9472b12 --- /dev/null +++ b/src/glsl/ir_mod_to_fract.cpp @@ -0,0 +1,90 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_mod_to_floor.cpp + * + * Breaks an ir_unop_mod expression down to (op1 * fract(op0 / op1)) + * + * Many GPUs don't have a MOD instruction (945 and 965 included), and + * if we have to break it down like this anyway, it gives an + * opportunity to do things like constant fold the (1.0 / op1) easily. + */ + +#include "ir.h" + +class ir_mod_to_fract_visitor : public ir_hierarchical_visitor { +public: + ir_mod_to_fract_visitor() + { + this->made_progress = false; + } + + ir_visitor_status visit_leave(ir_expression *); + + bool made_progress; +}; + +bool +do_mod_to_fract(exec_list *instructions) +{ + ir_mod_to_fract_visitor v; + + visit_list_elements(&v, instructions); + return v.made_progress; +} + +ir_visitor_status +ir_mod_to_fract_visitor::visit_leave(ir_expression *ir) +{ + if (ir->operation != ir_binop_mod) + return visit_continue; + + ir_variable *temp = new(ir) ir_variable(ir->operands[1]->type, "mod_b", + ir_var_temporary); + this->base_ir->insert_before(temp); + + ir_assignment *assign; + ir_rvalue *expr; + + assign = new(ir) ir_assignment(new(ir) ir_dereference_variable(temp), + ir->operands[1], NULL); + this->base_ir->insert_before(assign); + + expr = new(ir) ir_expression(ir_binop_div, + ir->operands[0]->type, + ir->operands[0], + new(ir) ir_dereference_variable(temp)); + + expr = new(ir) ir_expression(ir_unop_fract, + ir->operands[0]->type, + expr, + NULL); + + ir->operation = ir_binop_mul; + ir->operands[0] = new(ir) ir_dereference_variable(temp); + ir->operands[1] = expr; + this->made_progress = true; + + return visit_continue; +} diff --git a/src/glsl/ir_noop_swizzle.cpp b/src/glsl/ir_noop_swizzle.cpp new file mode 100644 index 0000000000..b78c87b47f --- /dev/null +++ b/src/glsl/ir_noop_swizzle.cpp @@ -0,0 +1,80 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_noop_swizzle.cpp + * + * If a swizzle doesn't change the order or count of components, then + * remove the swizzle so that other optimization passes see the value + * behind it. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_rvalue_visitor.h" +#include "ir_print_visitor.h" +#include "glsl_types.h" + +class ir_noop_swizzle_visitor : public ir_rvalue_visitor { +public: + ir_noop_swizzle_visitor() + { + this->progress = false; + } + + void handle_rvalue(ir_rvalue **rvalue); + bool progress; +}; + +void +ir_noop_swizzle_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + ir_swizzle *swiz = (*rvalue)->as_swizzle(); + if (!swiz || swiz->type != swiz->val->type) + return; + + int elems = swiz->val->type->vector_elements; + if (swiz->mask.x != 0) + return; + if (elems >= 2 && swiz->mask.y != 1) + return; + if (elems >= 3 && swiz->mask.z != 1) + return; + if (elems >= 4 && swiz->mask.w != 1) + return; + + this->progress = true; + *rvalue = swiz->val; +} + +bool +do_noop_swizzle(exec_list *instructions) +{ + ir_noop_swizzle_visitor v; + visit_list_elements(&v, instructions); + + return v.progress; +} diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h new file mode 100644 index 0000000000..33f4bc78f7 --- /dev/null +++ b/src/glsl/ir_optimization.h @@ -0,0 +1,57 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + +/** + * \file ir_optimization.h + * + * Prototypes for optimization passes to be called by the compiler and drivers. + */ + +bool do_common_optimization(exec_list *ir, bool linked); + +bool do_algebraic(exec_list *instructions); +bool do_constant_folding(exec_list *instructions); +bool do_constant_variable(exec_list *instructions); +bool do_constant_variable_unlinked(exec_list *instructions); +bool do_copy_propagation(exec_list *instructions); +bool do_constant_propagation(exec_list *instructions); +bool do_dead_code(exec_list *instructions); +bool do_dead_code_local(exec_list *instructions); +bool do_dead_code_unlinked(exec_list *instructions); +bool do_dead_functions(exec_list *instructions); +bool do_div_to_mul_rcp(exec_list *instructions); +bool do_explog_to_explog2(exec_list *instructions); +bool do_function_inlining(exec_list *instructions); +bool do_if_return(exec_list *instructions); +bool do_if_simplification(exec_list *instructions); +bool do_if_to_cond_assign(exec_list *instructions); +bool do_mat_op_to_vec(exec_list *instructions); +bool do_mod_to_fract(exec_list *instructions); +bool do_noop_swizzle(exec_list *instructions); +bool do_structure_splitting(exec_list *instructions); +bool do_sub_to_add_neg(exec_list *instructions); +bool do_swizzle_swizzle(exec_list *instructions); +bool do_tree_grafting(exec_list *instructions); +bool do_vec_index_to_cond_assign(exec_list *instructions); +bool do_vec_index_to_swizzle(exec_list *instructions); diff --git a/src/glsl/ir_print_visitor.cpp b/src/glsl/ir_print_visitor.cpp new file mode 100644 index 0000000000..f47ad87550 --- /dev/null +++ b/src/glsl/ir_print_visitor.cpp @@ -0,0 +1,459 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ir_print_visitor.h" +#include "glsl_types.h" +#include "glsl_parser_extras.h" + +static void print_type(const glsl_type *t); + +void +ir_instruction::print(void) const +{ + ir_instruction *deconsted = const_cast<ir_instruction *>(this); + + ir_print_visitor v; + deconsted->accept(&v); +} + +void +_mesa_print_ir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + if (state) { + for (unsigned i = 0; i < state->num_user_structures; i++) { + const glsl_type *const s = state->user_structures[i]; + + printf("(structure (%s) (%s@%p) (%u) (\n", + s->name, s->name, (void *) s, s->length); + + for (unsigned j = 0; j < s->length; j++) { + printf("\t(("); + print_type(s->fields.structure[j].type); + printf(")(%s))\n", s->fields.structure[j].name); + } + + printf(")\n"); + } + } + + printf("(\n"); + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + ir->print(); + if (ir->ir_type != ir_type_function) + printf("\n"); + } + printf("\n)"); +} + + +void ir_print_visitor::indent(void) +{ + for (int i = 0; i < indentation; i++) + printf(" "); +} + +static void +print_type(const glsl_type *t) +{ + if (t->base_type == GLSL_TYPE_ARRAY) { + printf("(array "); + print_type(t->fields.array); + printf(" %u)", t->length); + } else if ((t->base_type == GLSL_TYPE_STRUCT) + && (strncmp("gl_", t->name, 3) != 0)) { + printf("%s@%p", t->name, (void *) t); + } else { + printf("%s", t->name); + } +} + + +void ir_print_visitor::visit(ir_variable *ir) +{ + printf("(declare "); + + const char *const cent = (ir->centroid) ? "centroid " : ""; + const char *const inv = (ir->invariant) ? "invariant " : ""; + const char *const mode[] = { "", "uniform ", "in ", "out ", "inout ", + "temporary " }; + const char *const interp[] = { "", "flat", "noperspective" }; + + printf("(%s%s%s%s) ", + cent, inv, mode[ir->mode], interp[ir->interpolation]); + + print_type(ir->type); + printf(" %s@%p)", ir->name, (void *) ir); +} + + +void ir_print_visitor::visit(ir_function_signature *ir) +{ + printf("(signature "); + indentation++; + + print_type(ir->return_type); + printf("\n"); + indent(); + + printf("(parameters\n"); + indentation++; + + foreach_iter(exec_list_iterator, iter, ir->parameters) { + ir_variable *const inst = (ir_variable *) iter.get(); + + indent(); + inst->accept(this); + printf("\n"); + } + indentation--; + + indent(); + printf(")\n"); + + indent(); + + printf("(\n"); + indentation++; + + foreach_iter(exec_list_iterator, iter, ir->body) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + + indent(); + inst->accept(this); + printf("\n"); + } + indentation--; + indent(); + printf("))\n"); + indentation--; +} + + +void ir_print_visitor::visit(ir_function *ir) +{ + /* Don't print built-in functions as part of the IR. */ + if (ir->is_builtin) + return; + + printf("(function %s\n", ir->name); + indentation++; + foreach_iter(exec_list_iterator, iter, *ir) { + ir_function_signature *const sig = (ir_function_signature *) iter.get(); + + indent(); + sig->accept(this); + printf("\n"); + } + indentation--; + indent(); + printf(")\n\n"); +} + + +void ir_print_visitor::visit(ir_expression *ir) +{ + printf("(expression "); + + print_type(ir->type); + + printf(" %s ", ir->operator_string()); + + if (ir->operands[0]) + ir->operands[0]->accept(this); + + if (ir->operands[1]) + ir->operands[1]->accept(this); + printf(") "); +} + + +void ir_print_visitor::visit(ir_texture *ir) +{ + printf("(%s ", ir->opcode_string()); + + ir->sampler->accept(this); + printf(" "); + + ir->coordinate->accept(this); + + printf(" (%d %d %d) ", ir->offsets[0], ir->offsets[1], ir->offsets[2]); + + if (ir->op != ir_txf) { + if (ir->projector) + ir->projector->accept(this); + else + printf("1"); + + if (ir->shadow_comparitor) { + printf(" "); + ir->shadow_comparitor->accept(this); + } else { + printf(" ()"); + } + } + + printf(" "); + switch (ir->op) + { + case ir_tex: + break; + case ir_txb: + ir->lod_info.bias->accept(this); + break; + case ir_txl: + case ir_txf: + ir->lod_info.lod->accept(this); + break; + case ir_txd: + printf("("); + ir->lod_info.grad.dPdx->accept(this); + printf(" "); + ir->lod_info.grad.dPdy->accept(this); + printf(")"); + break; + }; + printf(")"); +} + + +void ir_print_visitor::visit(ir_swizzle *ir) +{ + const unsigned swiz[4] = { + ir->mask.x, + ir->mask.y, + ir->mask.z, + ir->mask.w, + }; + + printf("(swiz "); + for (unsigned i = 0; i < ir->mask.num_components; i++) { + printf("%c", "xyzw"[swiz[i]]); + } + printf(" "); + ir->val->accept(this); + printf(")"); +} + + +void ir_print_visitor::visit(ir_dereference_variable *ir) +{ + ir_variable *var = ir->variable_referenced(); + printf("(var_ref %s@%p) ", var->name, (void *) var); +} + + +void ir_print_visitor::visit(ir_dereference_array *ir) +{ + printf("(array_ref "); + ir->array->accept(this); + ir->array_index->accept(this); + printf(") "); +} + + +void ir_print_visitor::visit(ir_dereference_record *ir) +{ + printf("(record_ref "); + ir->record->accept(this); + printf(" %s) ", ir->field); +} + + +void ir_print_visitor::visit(ir_assignment *ir) +{ + printf("(assign "); + + if (ir->condition) + ir->condition->accept(this); + else + printf("(constant bool (1))"); + + + char mask[5]; + unsigned j = 0; + + for (unsigned i = 0; i < 4; i++) { + if ((ir->write_mask & (1 << i)) != 0) { + mask[j] = "xyzw"[i]; + j++; + } + } + mask[j] = '\0'; + + printf(" (%s) ", mask); + + ir->lhs->accept(this); + + printf(" "); + + ir->rhs->accept(this); + printf(") "); +} + + +void ir_print_visitor::visit(ir_constant *ir) +{ + const glsl_type *const base_type = ir->type->get_base_type(); + + printf("(constant "); + print_type(ir->type); + printf(" ("); + + if (ir->type->is_array()) { + for (unsigned i = 0; i < ir->type->length; i++) + ir->get_array_element(i)->accept(this); + } else { + for (unsigned i = 0; i < ir->type->components(); i++) { + if (i != 0) + printf(" "); + switch (base_type->base_type) { + case GLSL_TYPE_UINT: printf("%u", ir->value.u[i]); break; + case GLSL_TYPE_INT: printf("%d", ir->value.i[i]); break; + case GLSL_TYPE_FLOAT: printf("%f", ir->value.f[i]); break; + case GLSL_TYPE_BOOL: printf("%d", ir->value.b[i]); break; + default: assert(0); + } + } + } + printf(")) "); +} + + +void +ir_print_visitor::visit(ir_call *ir) +{ + printf("(call %s (", ir->callee_name()); + foreach_iter(exec_list_iterator, iter, *ir) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + + inst->accept(this); + } + printf("))\n"); +} + + +void +ir_print_visitor::visit(ir_return *ir) +{ + printf("(return"); + + ir_rvalue *const value = ir->get_value(); + if (value) { + printf(" "); + value->accept(this); + } + + printf(")"); +} + + +void +ir_print_visitor::visit(ir_discard *ir) +{ + printf("(discard "); + + if (ir->condition != NULL) { + printf(" "); + ir->condition->accept(this); + } + + printf(")"); +} + + +void +ir_print_visitor::visit(ir_if *ir) +{ + printf("(if "); + ir->condition->accept(this); + + printf("(\n"); + indentation++; + + foreach_iter(exec_list_iterator, iter, ir->then_instructions) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + + indent(); + inst->accept(this); + printf("\n"); + } + + indentation--; + indent(); + printf(")\n"); + + indent(); + printf("(\n"); + indentation++; + + foreach_iter(exec_list_iterator, iter, ir->else_instructions) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + + indent(); + inst->accept(this); + printf("\n"); + } + indentation--; + indent(); + printf("))\n"); +} + + +void +ir_print_visitor::visit(ir_loop *ir) +{ + printf("(loop ("); + if (ir->counter != NULL) + ir->counter->accept(this); + printf(") ("); + if (ir->from != NULL) + ir->from->accept(this); + printf(") ("); + if (ir->to != NULL) + ir->to->accept(this); + printf(") ("); + if (ir->increment != NULL) + ir->increment->accept(this); + printf(") (\n"); + indentation++; + + foreach_iter(exec_list_iterator, iter, ir->body_instructions) { + ir_instruction *const inst = (ir_instruction *) iter.get(); + + indent(); + inst->accept(this); + printf("\n"); + } + indentation--; + indent(); + printf("))\n"); +} + + +void +ir_print_visitor::visit(ir_loop_jump *ir) +{ + printf("%s", ir->is_break() ? "break" : "continue"); +} diff --git a/src/glsl/ir_print_visitor.h b/src/glsl/ir_print_visitor.h new file mode 100644 index 0000000000..4feeb8c184 --- /dev/null +++ b/src/glsl/ir_print_visitor.h @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef IR_PRINT_VISITOR_H +#define IR_PRINT_VISITOR_H + +#include "ir.h" +#include "ir_visitor.h" + +extern void _mesa_print_ir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + +/** + * Abstract base class of visitors of IR instruction trees + */ +class ir_print_visitor : public ir_visitor { +public: + ir_print_visitor() + { + indentation = 0; + } + + virtual ~ir_print_visitor() + { + /* empty */ + } + + void indent(void); + + /** + * \name Visit methods + * + * As typical for the visitor pattern, there must be one \c visit method for + * each concrete subclass of \c ir_instruction. Virtual base classes within + * the hierarchy should not have \c visit methods. + */ + /*@{*/ + virtual void visit(ir_variable *); + virtual void visit(ir_function_signature *); + virtual void visit(ir_function *); + virtual void visit(ir_expression *); + virtual void visit(ir_texture *); + virtual void visit(ir_swizzle *); + virtual void visit(ir_dereference_variable *); + virtual void visit(ir_dereference_array *); + virtual void visit(ir_dereference_record *); + virtual void visit(ir_assignment *); + virtual void visit(ir_constant *); + virtual void visit(ir_call *); + virtual void visit(ir_return *); + virtual void visit(ir_discard *); + virtual void visit(ir_if *); + virtual void visit(ir_loop *); + virtual void visit(ir_loop_jump *); + /*@}*/ + +private: + int indentation; +}; + +#endif /* IR_PRINT_VISITOR_H */ diff --git a/src/glsl/ir_reader.cpp b/src/glsl/ir_reader.cpp new file mode 100644 index 0000000000..e57e03c307 --- /dev/null +++ b/src/glsl/ir_reader.cpp @@ -0,0 +1,1088 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <cstdarg> + +extern "C" { +#include <talloc.h> +} + +#include "ir_reader.h" +#include "glsl_parser_extras.h" +#include "glsl_types.h" +#include "s_expression.h" + +static void ir_read_error(_mesa_glsl_parse_state *, s_expression *, + const char *fmt, ...); +static const glsl_type *read_type(_mesa_glsl_parse_state *, s_expression *); + +static void scan_for_prototypes(_mesa_glsl_parse_state *, exec_list *, + s_expression *); +static ir_function *read_function(_mesa_glsl_parse_state *, s_list *, + bool skip_body); +static void read_function_sig(_mesa_glsl_parse_state *, ir_function *, + s_list *, bool skip_body); + +static void read_instructions(_mesa_glsl_parse_state *, exec_list *, + s_expression *, ir_loop *); +static ir_instruction *read_instruction(_mesa_glsl_parse_state *, + s_expression *, ir_loop *); +static ir_variable *read_declaration(_mesa_glsl_parse_state *, s_list *); +static ir_if *read_if(_mesa_glsl_parse_state *, s_list *, ir_loop *); +static ir_loop *read_loop(_mesa_glsl_parse_state *st, s_list *list); +static ir_return *read_return(_mesa_glsl_parse_state *, s_list *); + +static ir_rvalue *read_rvalue(_mesa_glsl_parse_state *, s_expression *); +static ir_assignment *read_assignment(_mesa_glsl_parse_state *, s_list *); +static ir_expression *read_expression(_mesa_glsl_parse_state *, s_list *); +static ir_call *read_call(_mesa_glsl_parse_state *, s_list *); +static ir_swizzle *read_swizzle(_mesa_glsl_parse_state *, s_list *); +static ir_constant *read_constant(_mesa_glsl_parse_state *, s_list *); +static ir_texture *read_texture(_mesa_glsl_parse_state *, s_list *); + +static ir_dereference *read_dereference(_mesa_glsl_parse_state *, + s_expression *); +static ir_dereference *read_var_ref(_mesa_glsl_parse_state *, s_list *); +static ir_dereference *read_array_ref(_mesa_glsl_parse_state *, s_list *); +static ir_dereference *read_record_ref(_mesa_glsl_parse_state *, s_list *); + +void +_mesa_glsl_read_ir(_mesa_glsl_parse_state *state, exec_list *instructions, + const char *src, bool scan_for_protos) +{ + s_expression *expr = s_expression::read_expression(state, src); + if (expr == NULL) { + ir_read_error(state, NULL, "couldn't parse S-Expression."); + return; + } + + if (scan_for_protos) { + scan_for_prototypes(state, instructions, expr); + if (state->error) + return; + } + + read_instructions(state, instructions, expr, NULL); + talloc_free(expr); +} + +static void +ir_read_error(_mesa_glsl_parse_state *state, s_expression *expr, + const char *fmt, ...) +{ + va_list ap; + + state->error = true; + + state->info_log = talloc_strdup_append(state->info_log, "error: "); + + va_start(ap, fmt); + state->info_log = talloc_vasprintf_append(state->info_log, fmt, ap); + va_end(ap); + state->info_log = talloc_strdup_append(state->info_log, "\n"); + + if (expr != NULL) { + state->info_log = talloc_strdup_append(state->info_log, + "...in this context:\n "); + expr->print(); + state->info_log = talloc_strdup_append(state->info_log, "\n\n"); + } +} + +static const glsl_type * +read_type(_mesa_glsl_parse_state *st, s_expression *expr) +{ + s_list *list = SX_AS_LIST(expr); + if (list != NULL) { + s_symbol *type_sym = SX_AS_SYMBOL(list->subexpressions.get_head()); + if (type_sym == NULL) { + ir_read_error(st, expr, "expected type (array ...) or (struct ...)"); + return NULL; + } + if (strcmp(type_sym->value(), "array") == 0) { + if (list->length() != 3) { + ir_read_error(st, expr, "expected type (array <type> <int>)"); + return NULL; + } + + // Read base type + s_expression *base_expr = (s_expression*) type_sym->next; + const glsl_type *base_type = read_type(st, base_expr); + if (base_type == NULL) { + ir_read_error(st, NULL, "when reading base type of array"); + return NULL; + } + + // Read array size + s_int *size = SX_AS_INT(base_expr->next); + if (size == NULL) { + ir_read_error(st, expr, "found non-integer array size"); + return NULL; + } + + return glsl_type::get_array_instance(base_type, size->value()); + } else if (strcmp(type_sym->value(), "struct") == 0) { + assert(false); // FINISHME + } else { + ir_read_error(st, expr, "expected (array ...) or (struct ...); " + "found (%s ...)", type_sym->value()); + return NULL; + } + } + + s_symbol *type_sym = SX_AS_SYMBOL(expr); + if (type_sym == NULL) { + ir_read_error(st, expr, "expected <type> (symbol or list)"); + return NULL; + } + + const glsl_type *type = st->symbols->get_type(type_sym->value()); + if (type == NULL) + ir_read_error(st, expr, "invalid type: %s", type_sym->value()); + + return type; +} + + +static void +scan_for_prototypes(_mesa_glsl_parse_state *st, exec_list *instructions, + s_expression *expr) +{ + s_list *list = SX_AS_LIST(expr); + if (list == NULL) { + ir_read_error(st, expr, "Expected (<instruction> ...); found an atom."); + return; + } + + foreach_iter(exec_list_iterator, it, list->subexpressions) { + s_list *sub = SX_AS_LIST(it.get()); + if (sub == NULL) + continue; // not a (function ...); ignore it. + + s_symbol *tag = SX_AS_SYMBOL(sub->subexpressions.get_head()); + if (tag == NULL || strcmp(tag->value(), "function") != 0) + continue; // not a (function ...); ignore it. + + ir_function *f = read_function(st, sub, true); + if (f == NULL) + return; + instructions->push_tail(f); + } +} + +static ir_function * +read_function(_mesa_glsl_parse_state *st, s_list *list, bool skip_body) +{ + void *ctx = st; + bool added = false; + if (list->length() < 3) { + ir_read_error(st, list, "Expected (function <name> (signature ...) ...)"); + return NULL; + } + + s_symbol *name = SX_AS_SYMBOL(list->subexpressions.head->next); + if (name == NULL) { + ir_read_error(st, list, "Expected (function <name> ...)"); + return NULL; + } + + ir_function *f = st->symbols->get_function(name->value()); + if (f == NULL) { + f = new(ctx) ir_function(name->value()); + f->is_builtin = true; + added = st->symbols->add_function(f->name, f); + assert(added); + } + + exec_list_iterator it = list->subexpressions.iterator(); + it.next(); // skip "function" tag + it.next(); // skip function name + for (/* nothing */; it.has_next(); it.next()) { + s_list *siglist = SX_AS_LIST(it.get()); + if (siglist == NULL) { + ir_read_error(st, list, "Expected (function (signature ...) ...)"); + return NULL; + } + + s_symbol *tag = SX_AS_SYMBOL(siglist->subexpressions.get_head()); + if (tag == NULL || strcmp(tag->value(), "signature") != 0) { + ir_read_error(st, siglist, "Expected (signature ...)"); + return NULL; + } + + read_function_sig(st, f, siglist, skip_body); + } + return added ? f : NULL; +} + +static void +read_function_sig(_mesa_glsl_parse_state *st, ir_function *f, s_list *list, + bool skip_body) +{ + void *ctx = st; + if (list->length() != 4) { + ir_read_error(st, list, "Expected (signature <type> (parameters ...) " + "(<instruction> ...))"); + return; + } + + s_expression *type_expr = (s_expression*) list->subexpressions.head->next; + const glsl_type *return_type = read_type(st, type_expr); + if (return_type == NULL) + return; + + s_list *paramlist = SX_AS_LIST(type_expr->next); + s_list *body_list = SX_AS_LIST(paramlist->next); + if (paramlist == NULL || body_list == NULL) { + ir_read_error(st, list, "Expected (signature <type> (parameters ...) " + "(<instruction> ...))"); + return; + } + s_symbol *paramtag = SX_AS_SYMBOL(paramlist->subexpressions.get_head()); + if (paramtag == NULL || strcmp(paramtag->value(), "parameters") != 0) { + ir_read_error(st, paramlist, "Expected (parameters ...)"); + return; + } + + // Read the parameters list into a temporary place. + exec_list hir_parameters; + st->symbols->push_scope(); + + exec_list_iterator it = paramlist->subexpressions.iterator(); + for (it.next() /* skip "parameters" */; it.has_next(); it.next()) { + s_list *decl = SX_AS_LIST(it.get()); + ir_variable *var = read_declaration(st, decl); + if (var == NULL) + return; + + hir_parameters.push_tail(var); + } + + ir_function_signature *sig = f->exact_matching_signature(&hir_parameters); + if (sig == NULL && skip_body) { + /* If scanning for prototypes, generate a new signature. */ + sig = new(ctx) ir_function_signature(return_type); + f->add_signature(sig); + } else if (sig != NULL) { + const char *badvar = sig->qualifiers_match(&hir_parameters); + if (badvar != NULL) { + ir_read_error(st, list, "function `%s' parameter `%s' qualifiers " + "don't match prototype", f->name, badvar); + return; + } + + if (sig->return_type != return_type) { + ir_read_error(st, list, "function `%s' return type doesn't " + "match prototype", f->name); + return; + } + } else { + /* No prototype for this body exists - skip it. */ + st->symbols->pop_scope(); + return; + } + assert(sig != NULL); + + sig->replace_parameters(&hir_parameters); + + if (!skip_body && !body_list->subexpressions.is_empty()) { + if (sig->is_defined) { + ir_read_error(st, list, "function %s redefined", f->name); + return; + } + read_instructions(st, &sig->body, body_list, NULL); + sig->is_defined = true; + } + + st->symbols->pop_scope(); +} + +static void +read_instructions(_mesa_glsl_parse_state *st, exec_list *instructions, + s_expression *expr, ir_loop *loop_ctx) +{ + // Read in a list of instructions + s_list *list = SX_AS_LIST(expr); + if (list == NULL) { + ir_read_error(st, expr, "Expected (<instruction> ...); found an atom."); + return; + } + + foreach_iter(exec_list_iterator, it, list->subexpressions) { + s_expression *sub = (s_expression*) it.get(); + ir_instruction *ir = read_instruction(st, sub, loop_ctx); + if (ir != NULL) + instructions->push_tail(ir); + } +} + + +static ir_instruction * +read_instruction(_mesa_glsl_parse_state *st, s_expression *expr, + ir_loop *loop_ctx) +{ + void *ctx = st; + s_symbol *symbol = SX_AS_SYMBOL(expr); + if (symbol != NULL) { + if (strcmp(symbol->value(), "break") == 0 && loop_ctx != NULL) + return new(ctx) ir_loop_jump(ir_loop_jump::jump_break); + if (strcmp(symbol->value(), "continue") == 0 && loop_ctx != NULL) + return new(ctx) ir_loop_jump(ir_loop_jump::jump_continue); + } + + s_list *list = SX_AS_LIST(expr); + if (list == NULL || list->subexpressions.is_empty()) { + ir_read_error(st, expr, "Invalid instruction.\n"); + return NULL; + } + + s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head()); + if (tag == NULL) { + ir_read_error(st, expr, "expected instruction tag"); + return NULL; + } + + ir_instruction *inst = NULL; + if (strcmp(tag->value(), "declare") == 0) { + inst = read_declaration(st, list); + } else if (strcmp(tag->value(), "assign") == 0) { + inst = read_assignment(st, list); + } else if (strcmp(tag->value(), "if") == 0) { + inst = read_if(st, list, loop_ctx); + } else if (strcmp(tag->value(), "loop") == 0) { + inst = read_loop(st, list); + } else if (strcmp(tag->value(), "return") == 0) { + inst = read_return(st, list); + } else if (strcmp(tag->value(), "function") == 0) { + inst = read_function(st, list, false); + } else { + inst = read_rvalue(st, list); + if (inst == NULL) + ir_read_error(st, NULL, "when reading instruction"); + } + return inst; +} + + +static ir_variable * +read_declaration(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + if (list->length() != 4) { + ir_read_error(st, list, "expected (declare (<qualifiers>) <type> " + "<name>)"); + return NULL; + } + + s_list *quals = SX_AS_LIST(list->subexpressions.head->next); + if (quals == NULL) { + ir_read_error(st, list, "expected a list of variable qualifiers"); + return NULL; + } + + s_expression *type_expr = (s_expression*) quals->next; + const glsl_type *type = read_type(st, type_expr); + if (type == NULL) + return NULL; + + s_symbol *var_name = SX_AS_SYMBOL(type_expr->next); + if (var_name == NULL) { + ir_read_error(st, list, "expected variable name, found non-symbol"); + return NULL; + } + + ir_variable *var = new(ctx) ir_variable(type, var_name->value(), + ir_var_auto); + + foreach_iter(exec_list_iterator, it, quals->subexpressions) { + s_symbol *qualifier = SX_AS_SYMBOL(it.get()); + if (qualifier == NULL) { + ir_read_error(st, list, "qualifier list must contain only symbols"); + delete var; + return NULL; + } + + // FINISHME: Check for duplicate/conflicting qualifiers. + if (strcmp(qualifier->value(), "centroid") == 0) { + var->centroid = 1; + } else if (strcmp(qualifier->value(), "invariant") == 0) { + var->invariant = 1; + } else if (strcmp(qualifier->value(), "uniform") == 0) { + var->mode = ir_var_uniform; + } else if (strcmp(qualifier->value(), "auto") == 0) { + var->mode = ir_var_auto; + } else if (strcmp(qualifier->value(), "in") == 0) { + var->mode = ir_var_in; + } else if (strcmp(qualifier->value(), "out") == 0) { + var->mode = ir_var_out; + } else if (strcmp(qualifier->value(), "inout") == 0) { + var->mode = ir_var_inout; + } else if (strcmp(qualifier->value(), "smooth") == 0) { + var->interpolation = ir_var_smooth; + } else if (strcmp(qualifier->value(), "flat") == 0) { + var->interpolation = ir_var_flat; + } else if (strcmp(qualifier->value(), "noperspective") == 0) { + var->interpolation = ir_var_noperspective; + } else { + ir_read_error(st, list, "unknown qualifier: %s", qualifier->value()); + delete var; + return NULL; + } + } + + // Add the variable to the symbol table + st->symbols->add_variable(var->name, var); + + return var; +} + + +static ir_if * +read_if(_mesa_glsl_parse_state *st, s_list *list, ir_loop *loop_ctx) +{ + void *ctx = st; + if (list->length() != 4) { + ir_read_error(st, list, "expected (if <condition> (<then> ...) " + "(<else> ...))"); + return NULL; + } + + s_expression *cond_expr = (s_expression*) list->subexpressions.head->next; + ir_rvalue *condition = read_rvalue(st, cond_expr); + if (condition == NULL) { + ir_read_error(st, NULL, "when reading condition of (if ...)"); + return NULL; + } + + s_expression *then_expr = (s_expression*) cond_expr->next; + s_expression *else_expr = (s_expression*) then_expr->next; + + ir_if *iff = new(ctx) ir_if(condition); + + read_instructions(st, &iff->then_instructions, then_expr, loop_ctx); + read_instructions(st, &iff->else_instructions, else_expr, loop_ctx); + if (st->error) { + delete iff; + iff = NULL; + } + return iff; +} + + +static ir_loop * +read_loop(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + if (list->length() != 6) { + ir_read_error(st, list, "expected (loop <counter> <from> <to> " + "<increment> <body>)"); + return NULL; + } + + s_expression *count_expr = (s_expression*) list->subexpressions.head->next; + s_expression *from_expr = (s_expression*) count_expr->next; + s_expression *to_expr = (s_expression*) from_expr->next; + s_expression *inc_expr = (s_expression*) to_expr->next; + s_expression *body_expr = (s_expression*) inc_expr->next; + + // FINISHME: actually read the count/from/to fields. + + ir_loop *loop = new(ctx) ir_loop; + read_instructions(st, &loop->body_instructions, body_expr, loop); + if (st->error) { + delete loop; + loop = NULL; + } + return loop; +} + + +static ir_return * +read_return(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + if (list->length() != 2) { + ir_read_error(st, list, "expected (return <rvalue>)"); + return NULL; + } + + s_expression *expr = (s_expression*) list->subexpressions.head->next; + + ir_rvalue *retval = read_rvalue(st, expr); + if (retval == NULL) { + ir_read_error(st, NULL, "when reading return value"); + return NULL; + } + + return new(ctx) ir_return(retval); +} + + +static ir_rvalue * +read_rvalue(_mesa_glsl_parse_state *st, s_expression *expr) +{ + s_list *list = SX_AS_LIST(expr); + if (list == NULL || list->subexpressions.is_empty()) + return NULL; + + s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head()); + if (tag == NULL) { + ir_read_error(st, expr, "expected rvalue tag"); + return NULL; + } + + ir_rvalue *rvalue = read_dereference(st, list); + if (rvalue != NULL || st->error) + return rvalue; + else if (strcmp(tag->value(), "swiz") == 0) { + rvalue = read_swizzle(st, list); + } else if (strcmp(tag->value(), "expression") == 0) { + rvalue = read_expression(st, list); + } else if (strcmp(tag->value(), "call") == 0) { + rvalue = read_call(st, list); + } else if (strcmp(tag->value(), "constant") == 0) { + rvalue = read_constant(st, list); + } else { + rvalue = read_texture(st, list); + if (rvalue == NULL && !st->error) + ir_read_error(st, expr, "unrecognized rvalue tag: %s", tag->value()); + } + + return rvalue; +} + +static ir_assignment * +read_assignment(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + if (list->length() != 4) { + ir_read_error(st, list, "expected (assign <condition> <lhs> <rhs>)"); + return NULL; + } + + s_expression *cond_expr = (s_expression*) list->subexpressions.head->next; + s_expression *lhs_expr = (s_expression*) cond_expr->next; + s_expression *rhs_expr = (s_expression*) lhs_expr->next; + + // FINISHME: Deal with "true" condition + ir_rvalue *condition = read_rvalue(st, cond_expr); + if (condition == NULL) { + ir_read_error(st, NULL, "when reading condition of assignment"); + return NULL; + } + + ir_rvalue *lhs = read_rvalue(st, lhs_expr); + if (lhs == NULL) { + ir_read_error(st, NULL, "when reading left-hand side of assignment"); + return NULL; + } + + ir_rvalue *rhs = read_rvalue(st, rhs_expr); + if (rhs == NULL) { + ir_read_error(st, NULL, "when reading right-hand side of assignment"); + return NULL; + } + + return new(ctx) ir_assignment(lhs, rhs, condition); +} + +static ir_call * +read_call(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + if (list->length() != 3) { + ir_read_error(st, list, "expected (call <name> (<param> ...))"); + return NULL; + } + + s_symbol *name = SX_AS_SYMBOL(list->subexpressions.head->next); + s_list *params = SX_AS_LIST(name->next); + if (name == NULL || params == NULL) { + ir_read_error(st, list, "expected (call <name> (<param> ...))"); + return NULL; + } + + exec_list parameters; + + foreach_iter(exec_list_iterator, it, params->subexpressions) { + s_expression *expr = (s_expression*) it.get(); + ir_rvalue *param = read_rvalue(st, expr); + if (param == NULL) { + ir_read_error(st, list, "when reading parameter to function call"); + return NULL; + } + parameters.push_tail(param); + } + + ir_function *f = st->symbols->get_function(name->value()); + if (f == NULL) { + ir_read_error(st, list, "found call to undefined function %s", + name->value()); + return NULL; + } + + ir_function_signature *callee = f->matching_signature(¶meters); + if (callee == NULL) { + ir_read_error(st, list, "couldn't find matching signature for function " + "%s", name->value()); + return NULL; + } + + return new(ctx) ir_call(callee, ¶meters); +} + +static ir_expression * +read_expression(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + const unsigned list_length = list->length(); + if (list_length < 4) { + ir_read_error(st, list, "expected (expression <type> <operator> " + "<operand> [<operand>])"); + return NULL; + } + + s_expression *type_expr = (s_expression*) list->subexpressions.head->next; + const glsl_type *type = read_type(st, type_expr); + if (type == NULL) + return NULL; + + /* Read the operator */ + s_symbol *op_sym = SX_AS_SYMBOL(type_expr->next); + if (op_sym == NULL) { + ir_read_error(st, list, "expected operator, found non-symbol"); + return NULL; + } + + ir_expression_operation op = ir_expression::get_operator(op_sym->value()); + if (op == (ir_expression_operation) -1) { + ir_read_error(st, list, "invalid operator: %s", op_sym->value()); + return NULL; + } + + /* Now that we know the operator, check for the right number of operands */ + if (ir_expression::get_num_operands(op) == 2) { + if (list_length != 5) { + ir_read_error(st, list, "expected (expression <type> %s <operand> " + " <operand>)", op_sym->value()); + return NULL; + } + } else { + if (list_length != 4) { + ir_read_error(st, list, "expected (expression <type> %s <operand>)", + op_sym->value()); + return NULL; + } + } + + s_expression *exp1 = (s_expression*) (op_sym->next); + ir_rvalue *arg1 = read_rvalue(st, exp1); + if (arg1 == NULL) { + ir_read_error(st, NULL, "when reading first operand of %s", + op_sym->value()); + return NULL; + } + + ir_rvalue *arg2 = NULL; + if (ir_expression::get_num_operands(op) == 2) { + s_expression *exp2 = (s_expression*) (exp1->next); + arg2 = read_rvalue(st, exp2); + if (arg2 == NULL) { + ir_read_error(st, NULL, "when reading second operand of %s", + op_sym->value()); + return NULL; + } + } + + return new(ctx) ir_expression(op, type, arg1, arg2); +} + +static ir_swizzle * +read_swizzle(_mesa_glsl_parse_state *st, s_list *list) +{ + if (list->length() != 3) { + ir_read_error(st, list, "expected (swiz <swizzle> <rvalue>)"); + return NULL; + } + + s_symbol *swiz = SX_AS_SYMBOL(list->subexpressions.head->next); + if (swiz == NULL) { + ir_read_error(st, list, "expected a valid swizzle; found non-symbol"); + return NULL; + } + + if (strlen(swiz->value()) > 4) { + ir_read_error(st, list, "expected a valid swizzle; found %s", + swiz->value()); + return NULL; + } + + s_expression *sub = (s_expression*) swiz->next; + if (sub == NULL) { + ir_read_error(st, list, "expected rvalue: (swizzle %s <rvalue>)", + swiz->value()); + return NULL; + } + + ir_rvalue *rvalue = read_rvalue(st, sub); + if (rvalue == NULL) + return NULL; + + ir_swizzle *ir = ir_swizzle::create(rvalue, swiz->value(), + rvalue->type->vector_elements); + if (ir == NULL) + ir_read_error(st, list, "invalid swizzle"); + + return ir; +} + +static ir_constant * +read_constant(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + if (list->length() != 3) { + ir_read_error(st, list, "expected (constant <type> (...))"); + return NULL; + } + + s_expression *type_expr = (s_expression*) list->subexpressions.head->next; + const glsl_type *type = read_type(st, type_expr); + if (type == NULL) + return NULL; + + s_list *values = SX_AS_LIST(type_expr->next); + if (values == NULL) { + ir_read_error(st, list, "expected (constant <type> (...))"); + return NULL; + } + + if (type->is_array()) { + const unsigned elements_supplied = values->length(); + if (elements_supplied != type->length) { + ir_read_error(st, values, "expected exactly %u array elements, " + "given %u", type->length, elements_supplied); + return NULL; + } + + exec_list elements; + foreach_iter(exec_list_iterator, it, values->subexpressions) { + s_expression *expr = (s_expression *) it.get(); + s_list *elt = SX_AS_LIST(expr); + if (elt == NULL) { + ir_read_error(st, expr, "expected (constant ...) array element"); + return NULL; + } + + ir_constant *ir_elt = read_constant(st, elt); + if (ir_elt == NULL) + return NULL; + elements.push_tail(ir_elt); + } + return new(ctx) ir_constant(type, &elements); + } + + const glsl_type *const base_type = type->get_base_type(); + + ir_constant_data data = { { 0 } }; + + // Read in list of values (at most 16). + int k = 0; + foreach_iter(exec_list_iterator, it, values->subexpressions) { + if (k >= 16) { + ir_read_error(st, values, "expected at most 16 numbers"); + return NULL; + } + + s_expression *expr = (s_expression*) it.get(); + + if (base_type->base_type == GLSL_TYPE_FLOAT) { + s_number *value = SX_AS_NUMBER(expr); + if (value == NULL) { + ir_read_error(st, values, "expected numbers"); + return NULL; + } + data.f[k] = value->fvalue(); + } else { + s_int *value = SX_AS_INT(expr); + if (value == NULL) { + ir_read_error(st, values, "expected integers"); + return NULL; + } + + switch (base_type->base_type) { + case GLSL_TYPE_UINT: { + data.u[k] = value->value(); + break; + } + case GLSL_TYPE_INT: { + data.i[k] = value->value(); + break; + } + case GLSL_TYPE_BOOL: { + data.b[k] = value->value(); + break; + } + default: + ir_read_error(st, values, "unsupported constant type"); + return NULL; + } + } + ++k; + } + + return new(ctx) ir_constant(type, &data); +} + +static ir_dereference * +read_dereference(_mesa_glsl_parse_state *st, s_expression *expr) +{ + s_list *list = SX_AS_LIST(expr); + if (list == NULL || list->subexpressions.is_empty()) + return NULL; + + s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.head); + assert(tag != NULL); + + if (strcmp(tag->value(), "var_ref") == 0) + return read_var_ref(st, list); + if (strcmp(tag->value(), "array_ref") == 0) + return read_array_ref(st, list); + if (strcmp(tag->value(), "record_ref") == 0) + return read_record_ref(st, list); + return NULL; +} + +static ir_dereference * +read_var_ref(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + if (list->length() != 2) { + ir_read_error(st, list, "expected (var_ref <variable name>)"); + return NULL; + } + s_symbol *var_name = SX_AS_SYMBOL(list->subexpressions.head->next); + if (var_name == NULL) { + ir_read_error(st, list, "expected (var_ref <variable name>)"); + return NULL; + } + + ir_variable *var = st->symbols->get_variable(var_name->value()); + if (var == NULL) { + ir_read_error(st, list, "undeclared variable: %s", var_name->value()); + return NULL; + } + + return new(ctx) ir_dereference_variable(var); +} + +static ir_dereference * +read_array_ref(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + if (list->length() != 3) { + ir_read_error(st, list, "expected (array_ref <rvalue> <index>)"); + return NULL; + } + + s_expression *subj_expr = (s_expression*) list->subexpressions.head->next; + ir_rvalue *subject = read_rvalue(st, subj_expr); + if (subject == NULL) { + ir_read_error(st, NULL, "when reading the subject of an array_ref"); + return NULL; + } + + s_expression *idx_expr = (s_expression*) subj_expr->next; + ir_rvalue *idx = read_rvalue(st, idx_expr); + return new(ctx) ir_dereference_array(subject, idx); +} + +static ir_dereference * +read_record_ref(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + if (list->length() != 3) { + ir_read_error(st, list, "expected (record_ref <rvalue> <field>)"); + return NULL; + } + + s_expression *subj_expr = (s_expression*) list->subexpressions.head->next; + ir_rvalue *subject = read_rvalue(st, subj_expr); + if (subject == NULL) { + ir_read_error(st, NULL, "when reading the subject of a record_ref"); + return NULL; + } + + s_symbol *field = SX_AS_SYMBOL(subj_expr->next); + if (field == NULL) { + ir_read_error(st, list, "expected (record_ref ... <field name>)"); + return NULL; + } + return new(ctx) ir_dereference_record(subject, field->value()); +} + +static bool +valid_texture_list_length(ir_texture_opcode op, s_list *list) +{ + unsigned required_length = 7; + if (op == ir_txf) + required_length = 5; + else if (op == ir_tex) + required_length = 6; + + return list->length() == required_length; +} + +static ir_texture * +read_texture(_mesa_glsl_parse_state *st, s_list *list) +{ + void *ctx = st; + s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.head); + assert(tag != NULL); + + ir_texture_opcode op = ir_texture::get_opcode(tag->value()); + if (op == (ir_texture_opcode) -1) + return NULL; + + if (!valid_texture_list_length(op, list)) { + ir_read_error(st, NULL, "invalid list size in (%s ...)", tag->value()); + return NULL; + } + + ir_texture *tex = new(ctx) ir_texture(op); + + // Read sampler (must be a deref) + s_expression *sampler_expr = (s_expression *) tag->next; + ir_dereference *sampler = read_dereference(st, sampler_expr); + if (sampler == NULL) { + ir_read_error(st, NULL, "when reading sampler in (%s ...)", tag->value()); + return NULL; + } + tex->set_sampler(sampler); + + // Read coordinate (any rvalue) + s_expression *coordinate_expr = (s_expression *) sampler_expr->next; + tex->coordinate = read_rvalue(st, coordinate_expr); + if (tex->coordinate == NULL) { + ir_read_error(st, NULL, "when reading coordinate in (%s ...)", + tag->value()); + return NULL; + } + + // Read texel offset, i.e. (0 0 0) + s_list *offset_list = SX_AS_LIST(coordinate_expr->next); + if (offset_list == NULL || offset_list->length() != 3) { + ir_read_error(st, offset_list, "expected (<int> <int> <int>)"); + return NULL; + } + s_int *offset_x = SX_AS_INT(offset_list->subexpressions.head); + s_int *offset_y = SX_AS_INT(offset_x->next); + s_int *offset_z = SX_AS_INT(offset_y->next); + if (offset_x == NULL || offset_y == NULL || offset_z == NULL) { + ir_read_error(st, offset_list, "expected (<int> <int> <int>)"); + return NULL; + } + tex->offsets[0] = offset_x->value(); + tex->offsets[1] = offset_y->value(); + tex->offsets[2] = offset_z->value(); + + if (op == ir_txf) { + s_expression *lod_expr = (s_expression *) offset_list->next; + tex->lod_info.lod = read_rvalue(st, lod_expr); + if (tex->lod_info.lod == NULL) { + ir_read_error(st, NULL, "when reading LOD in (txf ...)"); + return NULL; + } + } else { + s_expression *proj_expr = (s_expression *) offset_list->next; + s_int *proj_as_int = SX_AS_INT(proj_expr); + if (proj_as_int && proj_as_int->value() == 1) { + tex->projector = NULL; + } else { + tex->projector = read_rvalue(st, proj_expr); + if (tex->projector == NULL) { + ir_read_error(st, NULL, "when reading projective divide in (%s ..)", + tag->value()); + return NULL; + } + } + + s_list *shadow_list = SX_AS_LIST(proj_expr->next); + if (shadow_list == NULL) { + ir_read_error(st, NULL, "shadow comparitor must be a list"); + return NULL; + } + if (shadow_list->subexpressions.is_empty()) { + tex->shadow_comparitor= NULL; + } else { + tex->shadow_comparitor = read_rvalue(st, shadow_list); + if (tex->shadow_comparitor == NULL) { + ir_read_error(st, NULL, "when reading shadow comparitor in (%s ..)", + tag->value()); + return NULL; + } + } + s_expression *lod_expr = (s_expression *) shadow_list->next; + + switch (op) { + case ir_txb: + tex->lod_info.bias = read_rvalue(st, lod_expr); + if (tex->lod_info.bias == NULL) { + ir_read_error(st, NULL, "when reading LOD bias in (txb ...)"); + return NULL; + } + break; + case ir_txl: + tex->lod_info.lod = read_rvalue(st, lod_expr); + if (tex->lod_info.lod == NULL) { + ir_read_error(st, NULL, "when reading LOD in (txl ...)"); + return NULL; + } + break; + case ir_txd: { + s_list *lod_list = SX_AS_LIST(lod_expr); + if (lod_list->length() != 2) { + ir_read_error(st, lod_expr, "expected (dPdx dPdy) in (txd ...)"); + return NULL; + } + s_expression *dx_expr = (s_expression *) lod_list->subexpressions.head; + s_expression *dy_expr = (s_expression *) dx_expr->next; + + tex->lod_info.grad.dPdx = read_rvalue(st, dx_expr); + if (tex->lod_info.grad.dPdx == NULL) { + ir_read_error(st, NULL, "when reading dPdx in (txd ...)"); + return NULL; + } + tex->lod_info.grad.dPdy = read_rvalue(st, dy_expr); + if (tex->lod_info.grad.dPdy == NULL) { + ir_read_error(st, NULL, "when reading dPdy in (txd ...)"); + return NULL; + } + break; + } + default: + // tex doesn't have any extra parameters and txf was handled earlier. + break; + }; + } + return tex; +} diff --git a/src/glsl/ir_reader.h b/src/glsl/ir_reader.h new file mode 100644 index 0000000000..aef2ca23bd --- /dev/null +++ b/src/glsl/ir_reader.h @@ -0,0 +1,34 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef IR_READER_H +#define IR_READER_H + +#include "ir.h" + +void _mesa_glsl_read_ir(_mesa_glsl_parse_state *state, exec_list *instructions, + const char *src, bool scan_for_prototypes); + +#endif /* IR_READER_H */ diff --git a/src/glsl/ir_rvalue_visitor.cpp b/src/glsl/ir_rvalue_visitor.cpp new file mode 100644 index 0000000000..613b07c302 --- /dev/null +++ b/src/glsl/ir_rvalue_visitor.cpp @@ -0,0 +1,134 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_rvalue_visitor.cpp + * + * Generic class to implement the common pattern we have of wanting to + * visit each ir_rvalue * and possibly change that node to a different + * class. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_rvalue_visitor.h" +#include "ir_print_visitor.h" +#include "glsl_types.h" + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_expression *ir) +{ + unsigned int operand; + + for (operand = 0; operand < ir->get_num_operands(); operand++) { + handle_rvalue(&ir->operands[operand]); + } + + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_texture *ir) +{ + handle_rvalue(&ir->coordinate); + handle_rvalue(&ir->projector); + handle_rvalue(&ir->shadow_comparitor); + + switch (ir->op) { + case ir_tex: + break; + case ir_txb: + handle_rvalue(&ir->lod_info.bias); + break; + case ir_txf: + case ir_txl: + handle_rvalue(&ir->lod_info.lod); + break; + case ir_txd: + handle_rvalue(&ir->lod_info.grad.dPdx); + handle_rvalue(&ir->lod_info.grad.dPdy); + break; + } + + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_swizzle *ir) +{ + handle_rvalue(&ir->val); + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_dereference_array *ir) +{ + handle_rvalue(&ir->array_index); + handle_rvalue(&ir->array); + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_dereference_record *ir) +{ + handle_rvalue(&ir->record); + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_assignment *ir) +{ + handle_rvalue(&ir->rhs); + handle_rvalue(&ir->condition); + + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_call *ir) +{ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param = (ir_rvalue *)iter.get(); + ir_rvalue *new_param = param; + handle_rvalue(&new_param); + + if (new_param != param) { + param->replace_with(new_param); + } + } + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_return *ir) +{ + handle_rvalue(&ir->value);; + return visit_continue; +} + +ir_visitor_status +ir_rvalue_visitor::visit_leave(ir_if *ir) +{ + handle_rvalue(&ir->condition); + return visit_continue; +} diff --git a/src/glsl/ir_rvalue_visitor.h b/src/glsl/ir_rvalue_visitor.h new file mode 100644 index 0000000000..31a56beb9b --- /dev/null +++ b/src/glsl/ir_rvalue_visitor.h @@ -0,0 +1,47 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_rvalue_visitor.h + * + * Generic class to implement the common pattern we have of wanting to + * visit each ir_rvalue * and possibly change that node to a different + * class. Just implement handle_rvalue() and you will be called with + * a pointer to each rvalue in the tree. + */ + +class ir_rvalue_visitor : public ir_hierarchical_visitor { +public: + + virtual ir_visitor_status visit_leave(ir_assignment *); + virtual ir_visitor_status visit_leave(ir_call *); + virtual ir_visitor_status visit_leave(ir_dereference_array *); + virtual ir_visitor_status visit_leave(ir_dereference_record *); + virtual ir_visitor_status visit_leave(ir_expression *); + virtual ir_visitor_status visit_leave(ir_if *); + virtual ir_visitor_status visit_leave(ir_return *); + virtual ir_visitor_status visit_leave(ir_swizzle *); + virtual ir_visitor_status visit_leave(ir_texture *); + + virtual void handle_rvalue(ir_rvalue **rvalue) = 0; +}; diff --git a/src/glsl/ir_set_program_inouts.cpp b/src/glsl/ir_set_program_inouts.cpp new file mode 100644 index 0000000000..b3f1cc0d8b --- /dev/null +++ b/src/glsl/ir_set_program_inouts.cpp @@ -0,0 +1,167 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_set_program_inouts.cpp + * + * Sets the InputsRead and OutputsWritten of Mesa programs. + * + * Mesa programs (gl_program, not gl_shader_program) have a set of + * flags indicating which varyings are read and written. Computing + * which are actually read from some sort of backend code can be + * tricky when variable array indexing involved. So this pass + * provides support for setting InputsRead and OutputsWritten right + * from the GLSL IR. + */ + +extern "C" { +#include "main/core.h" /* for struct gl_program */ +#include "program/hash_table.h" +} +#include "ir.h" +#include "ir_visitor.h" +#include "glsl_types.h" + +class ir_set_program_inouts_visitor : public ir_hierarchical_visitor { +public: + ir_set_program_inouts_visitor(struct gl_program *prog) + { + this->prog = prog; + this->ht = hash_table_ctor(0, + hash_table_pointer_hash, + hash_table_pointer_compare); + } + ~ir_set_program_inouts_visitor() + { + hash_table_dtor(this->ht); + } + + virtual ir_visitor_status visit_enter(ir_dereference_array *); + virtual ir_visitor_status visit_enter(ir_function_signature *); + virtual ir_visitor_status visit(ir_dereference_variable *); + virtual ir_visitor_status visit(ir_variable *); + + struct gl_program *prog; + struct hash_table *ht; +}; + +static void +mark(struct gl_program *prog, ir_variable *var, int index) +{ + /* As of GLSL 1.20, varyings can only be floats, floating-point + * vectors or matrices, or arrays of them. For Mesa programs using + * InputsRead/OutputsWritten, everything but matrices uses one + * slot, while matrices use a slot per column. Presumably + * something doing a more clever packing would use something other + * than InputsRead/OutputsWritten. + */ + const glsl_type *element_type; + int element_size; + + if (var->type->is_array()) + element_type = var->type->fields.array; + else + element_type = var->type; + + if (element_type->is_matrix()) + element_size = element_type->matrix_columns; + else + element_size = 1; + + index *= element_size; + for (int i = 0; i < element_size; i++) { + if (var->mode == ir_var_in) + prog->InputsRead |= BITFIELD64_BIT(var->location + index + i); + else + prog->OutputsWritten |= BITFIELD64_BIT(var->location + index + i); + } +} + +/* Default handler: Mark all the locations in the variable as used. */ +ir_visitor_status +ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir) +{ + if (hash_table_find(this->ht, ir->var) == NULL) + return visit_continue; + + if (ir->type->is_array()) { + for (unsigned int i = 0; i < ir->type->length; i++) { + mark(this->prog, ir->var, i); + } + } else { + mark(this->prog, ir->var, 0); + } + + return visit_continue; +} + +ir_visitor_status +ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) +{ + ir_dereference_variable *deref_var; + ir_constant *index = ir->array_index->as_constant(); + deref_var = ir->array->as_dereference_variable(); + ir_variable *var = NULL; + + /* Check that we're dereferencing a shader in or out */ + if (deref_var) + var = (ir_variable *)hash_table_find(this->ht, deref_var->var); + + if (index && var) { + mark(this->prog, var, index->value.i[0]); + return visit_continue_with_parent; + } + + return visit_continue; +} + +ir_visitor_status +ir_set_program_inouts_visitor::visit(ir_variable *ir) +{ + if (ir->mode == ir_var_in || + ir->mode == ir_var_out) { + hash_table_insert(this->ht, ir, ir); + } + + return visit_continue; +} + +ir_visitor_status +ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir) +{ + /* We don't want to descend into the function parameters and + * consider them as shader inputs or outputs. + */ + visit_list_elements(this, &ir->body); + return visit_continue_with_parent; +} + +void +do_set_program_inouts(exec_list *instructions, struct gl_program *prog) +{ + ir_set_program_inouts_visitor v(prog); + + prog->InputsRead = 0; + prog->OutputsWritten = 0; + visit_list_elements(&v, instructions); +} diff --git a/src/glsl/ir_structure_splitting.cpp b/src/glsl/ir_structure_splitting.cpp new file mode 100644 index 0000000000..ff3ec936eb --- /dev/null +++ b/src/glsl/ir_structure_splitting.cpp @@ -0,0 +1,361 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_structure_splitting.cpp + * + * If a structure is only ever referenced by its components, then + * split those components out to individual variables so they can be + * handled normally by other optimization passes. + * + * This skips structures like uniforms, which need to be accessible as + * structures for their access by the GL. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_print_visitor.h" +#include "ir_rvalue_visitor.h" +#include "glsl_types.h" + +static bool debug = false; + +// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined +// function) with the variable_entry class seen in ir_variable_refcount.h +// Perhaps we can use the one in ir_variable_refcount.h and make this class +// here go away? +class variable_entry2 : public exec_node +{ +public: + variable_entry2(ir_variable *var) + { + this->var = var; + this->whole_structure_access = 0; + this->declaration = false; + this->components = NULL; + this->mem_ctx = NULL; + } + + ir_variable *var; /* The key: the variable's pointer. */ + + /** Number of times the variable is referenced, including assignments. */ + unsigned whole_structure_access; + + bool declaration; /* If the variable had a decl in the instruction stream */ + + ir_variable **components; + + /** talloc_parent(this->var) -- the shader's talloc context. */ + void *mem_ctx; +}; + + +class ir_structure_reference_visitor : public ir_hierarchical_visitor { +public: + ir_structure_reference_visitor(void) + { + this->mem_ctx = talloc_new(NULL); + this->variable_list.make_empty(); + } + + ~ir_structure_reference_visitor(void) + { + talloc_free(mem_ctx); + } + + virtual ir_visitor_status visit(ir_variable *); + virtual ir_visitor_status visit(ir_dereference_variable *); + virtual ir_visitor_status visit_enter(ir_dereference_record *); + virtual ir_visitor_status visit_enter(ir_assignment *); + virtual ir_visitor_status visit_enter(ir_function_signature *); + + variable_entry2 *get_variable_entry2(ir_variable *var); + + /* List of variable_entry */ + exec_list variable_list; + + void *mem_ctx; +}; + +variable_entry2 * +ir_structure_reference_visitor::get_variable_entry2(ir_variable *var) +{ + assert(var); + + if (!var->type->is_record() || var->mode == ir_var_uniform) + return NULL; + + foreach_iter(exec_list_iterator, iter, this->variable_list) { + variable_entry2 *entry = (variable_entry2 *)iter.get(); + if (entry->var == var) + return entry; + } + + variable_entry2 *entry = new(mem_ctx) variable_entry2(var); + this->variable_list.push_tail(entry); + return entry; +} + + +ir_visitor_status +ir_structure_reference_visitor::visit(ir_variable *ir) +{ + variable_entry2 *entry = this->get_variable_entry2(ir); + + if (entry) + entry->declaration = true; + + return visit_continue; +} + +ir_visitor_status +ir_structure_reference_visitor::visit(ir_dereference_variable *ir) +{ + ir_variable *const var = ir->variable_referenced(); + variable_entry2 *entry = this->get_variable_entry2(var); + + if (entry) + entry->whole_structure_access++; + + return visit_continue; +} + +ir_visitor_status +ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir) +{ + (void) ir; + /* Don't descend into the ir_dereference_variable below. */ + return visit_continue_with_parent; +} + +ir_visitor_status +ir_structure_reference_visitor::visit_enter(ir_assignment *ir) +{ + if (ir->lhs->as_dereference_variable() && + ir->rhs->as_dereference_variable() && + !ir->condition) { + /* We'll split copies of a structure to copies of components, so don't + * descend to the ir_dereference_variables. + */ + return visit_continue_with_parent; + } + return visit_continue; +} + +ir_visitor_status +ir_structure_reference_visitor::visit_enter(ir_function_signature *ir) +{ + /* We don't want to descend into the function parameters and + * dead-code eliminate them, so just accept the body here. + */ + visit_list_elements(this, &ir->body); + return visit_continue_with_parent; +} + +class ir_structure_splitting_visitor : public ir_rvalue_visitor { +public: + ir_structure_splitting_visitor(exec_list *vars) + { + this->variable_list = vars; + } + + virtual ~ir_structure_splitting_visitor() + { + } + + virtual ir_visitor_status visit_leave(ir_assignment *); + + void split_deref(ir_dereference **deref); + void handle_rvalue(ir_rvalue **rvalue); + variable_entry2 *get_splitting_entry(ir_variable *var); + + exec_list *variable_list; + void *mem_ctx; +}; + +variable_entry2 * +ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var) +{ + assert(var); + + if (!var->type->is_record()) + return NULL; + + foreach_iter(exec_list_iterator, iter, *this->variable_list) { + variable_entry2 *entry = (variable_entry2 *)iter.get(); + if (entry->var == var) { + return entry; + } + } + + return NULL; +} + +void +ir_structure_splitting_visitor::split_deref(ir_dereference **deref) +{ + if ((*deref)->ir_type != ir_type_dereference_record) + return; + + ir_dereference_record *deref_record = (ir_dereference_record *)*deref; + ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable(); + if (!deref_var) + return; + + variable_entry2 *entry = get_splitting_entry(deref_var->var); + if (!entry) + return; + + unsigned int i; + for (i = 0; i < entry->var->type->length; i++) { + if (strcmp(deref_record->field, + entry->var->type->fields.structure[i].name) == 0) + break; + } + assert(i != entry->var->type->length); + + *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]); +} + +void +ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + ir_dereference *deref = (*rvalue)->as_dereference(); + + if (!deref) + return; + + split_deref(&deref); + *rvalue = deref; +} + +ir_visitor_status +ir_structure_splitting_visitor::visit_leave(ir_assignment *ir) +{ + ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable(); + ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable(); + variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL; + variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL; + const glsl_type *type = ir->rhs->type; + + if ((lhs_entry || rhs_entry) && !ir->condition) { + for (unsigned int i = 0; i < type->length; i++) { + ir_dereference *new_lhs, *new_rhs; + void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx; + + if (lhs_entry) { + new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]); + } else { + new_lhs = new(mem_ctx) + ir_dereference_record(ir->lhs->clone(mem_ctx, NULL), + type->fields.structure[i].name); + } + + if (rhs_entry) { + new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]); + } else { + new_rhs = new(mem_ctx) + ir_dereference_record(ir->rhs->clone(mem_ctx, NULL), + type->fields.structure[i].name); + } + + ir->insert_before(new(mem_ctx) ir_assignment(new_lhs, + new_rhs, + NULL)); + } + ir->remove(); + } else { + handle_rvalue(&ir->rhs); + split_deref(&ir->lhs); + } + + handle_rvalue(&ir->condition); + + return visit_continue; +} + +bool +do_structure_splitting(exec_list *instructions) +{ + ir_structure_reference_visitor refs; + + visit_list_elements(&refs, instructions); + + /* Trim out variables we can't split. */ + foreach_iter(exec_list_iterator, iter, refs.variable_list) { + variable_entry2 *entry = (variable_entry2 *)iter.get(); + + if (debug) { + printf("structure %s@%p: decl %d, whole_access %d\n", + entry->var->name, (void *) entry->var, entry->declaration, + entry->whole_structure_access); + } + + if (!entry->declaration || entry->whole_structure_access) { + entry->remove(); + } + } + + if (refs.variable_list.is_empty()) + return false; + + void *mem_ctx = talloc_new(NULL); + + /* Replace the decls of the structures to be split with their split + * components. + */ + foreach_iter(exec_list_iterator, iter, refs.variable_list) { + variable_entry2 *entry = (variable_entry2 *)iter.get(); + const struct glsl_type *type = entry->var->type; + + entry->mem_ctx = talloc_parent(entry->var); + + entry->components = talloc_array(mem_ctx, + ir_variable *, + type->length); + + for (unsigned int i = 0; i < entry->var->type->length; i++) { + const char *name = talloc_asprintf(mem_ctx, "%s_%s", + entry->var->name, + type->fields.structure[i].name); + + entry->components[i] = + new(entry->mem_ctx) ir_variable(type->fields.structure[i].type, + name, + ir_var_temporary); + entry->var->insert_before(entry->components[i]); + } + + entry->var->remove(); + } + + ir_structure_splitting_visitor split(&refs.variable_list); + visit_list_elements(&split, instructions); + + talloc_free(mem_ctx); + + return true; +} diff --git a/src/glsl/ir_sub_to_add_neg.cpp b/src/glsl/ir_sub_to_add_neg.cpp new file mode 100644 index 0000000000..7ed8c1495e --- /dev/null +++ b/src/glsl/ir_sub_to_add_neg.cpp @@ -0,0 +1,76 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_sub_to_add_neg.cpp + * + * Breaks an ir_binop_sub expression down to add(op0, neg(op1)) + * + * This simplifies expression reassociation, and for many backends + * there is no subtract operation separate from adding the negation. + * For backends with native subtract operations, they will probably + * want to recognize add(op0, neg(op1)) or the other way around to + * produce a subtract anyway. + */ + +#include "ir.h" + +class ir_sub_to_add_neg_visitor : public ir_hierarchical_visitor { +public: + ir_sub_to_add_neg_visitor() + { + this->progress = false; + } + + ir_visitor_status visit_leave(ir_expression *); + + bool progress; +}; + +bool +do_sub_to_add_neg(exec_list *instructions) +{ + ir_sub_to_add_neg_visitor v; + + visit_list_elements(&v, instructions); + return v.progress; +} + +ir_visitor_status +ir_sub_to_add_neg_visitor::visit_leave(ir_expression *ir) +{ + if (ir->operation != ir_binop_sub) + return visit_continue; + + void *mem_ctx = talloc_parent(ir); + + ir->operation = ir_binop_add; + ir->operands[1] = new(mem_ctx) ir_expression(ir_unop_neg, + ir->operands[1]->type, + ir->operands[1], + NULL); + + this->progress = true; + + return visit_continue; +} diff --git a/src/glsl/ir_swizzle_swizzle.cpp b/src/glsl/ir_swizzle_swizzle.cpp new file mode 100644 index 0000000000..0ffb4fa313 --- /dev/null +++ b/src/glsl/ir_swizzle_swizzle.cpp @@ -0,0 +1,93 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_swizzle_swizzle.cpp + * + * Eliminates the second swizzle in a swizzle chain. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +class ir_swizzle_swizzle_visitor : public ir_hierarchical_visitor { +public: + ir_swizzle_swizzle_visitor() + { + progress = false; + } + + virtual ir_visitor_status visit_enter(ir_swizzle *); + + bool progress; +}; + +ir_visitor_status +ir_swizzle_swizzle_visitor::visit_enter(ir_swizzle *ir) +{ + int mask2[4]; + + ir_swizzle *swiz2 = ir->val->as_swizzle(); + if (!swiz2) + return visit_continue; + + memset(&mask2, 0, sizeof(mask2)); + if (swiz2->mask.num_components >= 1) + mask2[0] = swiz2->mask.x; + if (swiz2->mask.num_components >= 2) + mask2[1] = swiz2->mask.y; + if (swiz2->mask.num_components >= 3) + mask2[2] = swiz2->mask.z; + if (swiz2->mask.num_components >= 4) + mask2[3] = swiz2->mask.w; + + if (ir->mask.num_components >= 1) + ir->mask.x = mask2[ir->mask.x]; + if (ir->mask.num_components >= 2) + ir->mask.y = mask2[ir->mask.y]; + if (ir->mask.num_components >= 3) + ir->mask.z = mask2[ir->mask.z]; + if (ir->mask.num_components >= 4) + ir->mask.w = mask2[ir->mask.w]; + + ir->val = swiz2->val; + + this->progress = true; + + return visit_continue; +} + +/** + * Does a copy propagation pass on the code present in the instruction stream. + */ +bool +do_swizzle_swizzle(exec_list *instructions) +{ + ir_swizzle_swizzle_visitor v; + + v.run(instructions); + + return v.progress; +} diff --git a/src/glsl/ir_tree_grafting.cpp b/src/glsl/ir_tree_grafting.cpp new file mode 100644 index 0000000000..9b569b8284 --- /dev/null +++ b/src/glsl/ir_tree_grafting.cpp @@ -0,0 +1,367 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_tree_grafting.cpp + * + * Takes assignments to variables that are dereferenced only once and + * pastes the RHS expression into where the variable is dereferenced. + * + * In the process of various operations like function inlining and + * tertiary op handling, we'll end up with our expression trees having + * been chopped up into a series of assignments of short expressions + * to temps. Other passes like ir_algebraic.cpp would prefer to see + * the deepest expression trees they can to try to optimize them. + * + * This is a lot like copy propagaton. In comparison, copy + * propagation only acts on plain copies, not arbitrary expressions on + * the RHS. Generally, we wouldn't want to go pasting some + * complicated expression everywhere it got used, though, so we don't + * handle expressions in that pass. + * + * The hard part is making sure we don't move an expression across + * some other assignments that would change the value of the + * expression. So we split this into two passes: First, find the + * variables in our scope which are written to once and read once, and + * then go through basic blocks seeing if we find an opportunity to + * move those expressions safely. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_variable_refcount.h" +#include "ir_basic_block.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +static bool debug = false; + +class ir_tree_grafting_visitor : public ir_hierarchical_visitor { +public: + ir_tree_grafting_visitor(ir_assignment *graft_assign, + ir_variable *graft_var) + { + this->progress = false; + this->graft_assign = graft_assign; + this->graft_var = graft_var; + } + + virtual ir_visitor_status visit_leave(class ir_assignment *); + virtual ir_visitor_status visit_enter(class ir_call *); + virtual ir_visitor_status visit_enter(class ir_expression *); + virtual ir_visitor_status visit_enter(class ir_function *); + virtual ir_visitor_status visit_enter(class ir_function_signature *); + virtual ir_visitor_status visit_enter(class ir_if *); + virtual ir_visitor_status visit_enter(class ir_loop *); + virtual ir_visitor_status visit_enter(class ir_swizzle *); + virtual ir_visitor_status visit_enter(class ir_texture *); + + bool do_graft(ir_rvalue **rvalue); + + bool progress; + ir_variable *graft_var; + ir_assignment *graft_assign; +}; + +struct find_deref_info { + ir_variable *var; + bool found; +}; + +void +dereferences_variable_callback(ir_instruction *ir, void *data) +{ + struct find_deref_info *info = (struct find_deref_info *)data; + ir_dereference_variable *deref = ir->as_dereference_variable(); + + if (deref && deref->var == info->var) + info->found = true; +} + +static bool +dereferences_variable(ir_instruction *ir, ir_variable *var) +{ + struct find_deref_info info; + + info.var = var; + info.found = false; + + visit_tree(ir, dereferences_variable_callback, &info); + + return info.found; +} + +bool +ir_tree_grafting_visitor::do_graft(ir_rvalue **rvalue) +{ + if (!*rvalue) + return false; + + ir_dereference_variable *deref = (*rvalue)->as_dereference_variable(); + + if (!deref || deref->var != this->graft_var) + return false; + + if (debug) { + printf("GRAFTING:\n"); + this->graft_assign->print(); + printf("\n"); + printf("TO:\n"); + (*rvalue)->print(); + printf("\n"); + } + + this->graft_assign->remove(); + *rvalue = this->graft_assign->rhs; + + this->progress = true; + return true; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_loop *ir) +{ + (void)ir; + /* Do not traverse into the body of the loop since that is a + * different basic block. + */ + return visit_stop; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_leave(ir_assignment *ir) +{ + if (do_graft(&ir->rhs) || + do_graft(&ir->condition)) + return visit_stop; + + /* If this assignment updates a variable used in the assignment + * we're trying to graft, then we're done. + */ + if (dereferences_variable(this->graft_assign->rhs, + ir->lhs->variable_referenced())) { + if (debug) { + printf("graft killed by: "); + ir->print(); + printf("\n"); + } + return visit_stop; + } + + return visit_continue; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_function *ir) +{ + (void) ir; + return visit_continue_with_parent; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir) +{ + (void)ir; + return visit_continue_with_parent; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_call *ir) +{ + exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator(); + /* Reminder: iterating ir_call iterates its parameters. */ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_variable *sig_param = (ir_variable *)sig_iter.get(); + ir_rvalue *ir = (ir_rvalue *)iter.get(); + ir_rvalue *new_ir = ir; + + if (sig_param->mode != ir_var_in) + continue; + + if (do_graft(&new_ir)) { + ir->replace_with(new_ir); + return visit_stop; + } + sig_iter.next(); + } + + return visit_continue; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_expression *ir) +{ + for (unsigned int i = 0; i < ir->get_num_operands(); i++) { + if (do_graft(&ir->operands[i])) + return visit_stop; + } + + return visit_continue; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_if *ir) +{ + if (do_graft(&ir->condition)) + return visit_stop; + + /* Do not traverse into the body of the if-statement since that is a + * different basic block. + */ + return visit_continue_with_parent; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_swizzle *ir) +{ + if (do_graft(&ir->val)) + return visit_stop; + + return visit_continue; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_texture *ir) +{ + if (do_graft(&ir->coordinate) || + do_graft(&ir->projector) || + do_graft(&ir->shadow_comparitor)) + return visit_stop; + + switch (ir->op) { + case ir_tex: + break; + case ir_txb: + if (do_graft(&ir->lod_info.bias)) + return visit_stop; + break; + case ir_txf: + case ir_txl: + if (do_graft(&ir->lod_info.lod)) + return visit_stop; + break; + case ir_txd: + if (do_graft(&ir->lod_info.grad.dPdx) || + do_graft(&ir->lod_info.grad.dPdy)) + return visit_stop; + break; + } + + return visit_continue; +} + +struct tree_grafting_info { + ir_variable_refcount_visitor *refs; + bool progress; +}; + +static bool +try_tree_grafting(ir_assignment *start, + ir_variable *lhs_var, + ir_instruction *bb_last) +{ + ir_tree_grafting_visitor v(start, lhs_var); + + if (debug) { + printf("trying to graft: "); + lhs_var->print(); + printf("\n"); + } + + for (ir_instruction *ir = (ir_instruction *)start->next; + ir != bb_last->next; + ir = (ir_instruction *)ir->next) { + + if (debug) { + printf("- "); + ir->print(); + printf("\n"); + } + + ir_visitor_status s = ir->accept(&v); + if (s == visit_stop) + return v.progress; + } + + return false; +} + +static void +tree_grafting_basic_block(ir_instruction *bb_first, + ir_instruction *bb_last, + void *data) +{ + struct tree_grafting_info *info = (struct tree_grafting_info *)data; + ir_instruction *ir, *next; + + for (ir = bb_first, next = (ir_instruction *)ir->next; + ir != bb_last->next; + ir = next, next = (ir_instruction *)ir->next) { + ir_assignment *assign = ir->as_assignment(); + + if (!assign) + continue; + + ir_variable *lhs_var = assign->whole_variable_written(); + if (!lhs_var) + continue; + + if (lhs_var->mode == ir_var_out || + lhs_var->mode == ir_var_inout) + continue; + + variable_entry *entry = info->refs->get_variable_entry(lhs_var); + + if (!entry->declaration || + entry->assigned_count != 1 || + entry->referenced_count != 2) + continue; + + assert(assign == entry->assign); + + /* Found a possibly graftable assignment. Now, walk through the + * rest of the BB seeing if the deref is here, and if nothing interfered with + * pasting its expression's values in between. + */ + info->progress |= try_tree_grafting(assign, lhs_var, bb_last); + } +} + +/** + * Does a copy propagation pass on the code present in the instruction stream. + */ +bool +do_tree_grafting(exec_list *instructions) +{ + ir_variable_refcount_visitor refs; + struct tree_grafting_info info; + + info.progress = false; + info.refs = &refs; + + visit_list_elements(info.refs, instructions); + + call_for_basic_blocks(instructions, tree_grafting_basic_block, &info); + + return info.progress; +} diff --git a/src/glsl/ir_validate.cpp b/src/glsl/ir_validate.cpp new file mode 100644 index 0000000000..9ea11dd400 --- /dev/null +++ b/src/glsl/ir_validate.cpp @@ -0,0 +1,402 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_validate.cpp + * + * Attempts to verify that various invariants of the IR tree are true. + * + * In particular, at the moment it makes sure that no single + * ir_instruction node except for ir_variable appears multiple times + * in the ir tree. ir_variable does appear multiple times: Once as a + * declaration in an exec_list, and multiple times as the endpoint of + * a dereference chain. + */ + +#include <inttypes.h> +#include "ir.h" +#include "ir_hierarchical_visitor.h" +#include "program/hash_table.h" +#include "glsl_types.h" + +class ir_validate : public ir_hierarchical_visitor { +public: + ir_validate() + { + this->ht = hash_table_ctor(0, hash_table_pointer_hash, + hash_table_pointer_compare); + + this->current_function = NULL; + + this->callback = ir_validate::validate_ir; + this->data = ht; + } + + ~ir_validate() + { + hash_table_dtor(this->ht); + } + + virtual ir_visitor_status visit(ir_variable *v); + virtual ir_visitor_status visit(ir_dereference_variable *ir); + virtual ir_visitor_status visit(ir_if *ir); + + virtual ir_visitor_status visit_enter(ir_function *ir); + virtual ir_visitor_status visit_leave(ir_function *ir); + virtual ir_visitor_status visit_enter(ir_function_signature *ir); + + virtual ir_visitor_status visit_leave(ir_expression *ir); + + virtual ir_visitor_status visit_enter(ir_assignment *ir); + + static void validate_ir(ir_instruction *ir, void *data); + + ir_function *current_function; + + struct hash_table *ht; +}; + + +ir_visitor_status +ir_validate::visit(ir_dereference_variable *ir) +{ + if ((ir->var == NULL) || (ir->var->as_variable() == NULL)) { + printf("ir_dereference_variable @ %p does not specify a variable %p\n", + (void *) ir, (void *) ir->var); + abort(); + } + + if (hash_table_find(ht, ir->var) == NULL) { + printf("ir_dereference_variable @ %p specifies undeclared variable " + "`%s' @ %p\n", + (void *) ir, ir->var->name, (void *) ir->var); + abort(); + } + + this->validate_ir(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_validate::visit(ir_if *ir) +{ + if (ir->condition->type != glsl_type::bool_type) { + printf("ir_if condition %s type instead of bool.\n", + ir->condition->type->name); + ir->print(); + printf("\n"); + abort(); + } + + return visit_continue; +} + + +ir_visitor_status +ir_validate::visit_enter(ir_function *ir) +{ + /* Function definitions cannot be nested. + */ + if (this->current_function != NULL) { + printf("Function definition nested inside another function " + "definition:\n"); + printf("%s %p inside %s %p\n", + ir->name, (void *) ir, + this->current_function->name, (void *) this->current_function); + abort(); + } + + /* Store the current function hierarchy being traversed. This is used + * by the function signature visitor to ensure that the signatures are + * linked with the correct functions. + */ + this->current_function = ir; + + this->validate_ir(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_validate::visit_leave(ir_function *ir) +{ + assert(talloc_parent(ir->name) == ir); + + this->current_function = NULL; + return visit_continue; +} + +ir_visitor_status +ir_validate::visit_enter(ir_function_signature *ir) +{ + if (this->current_function != ir->function()) { + printf("Function signature nested inside wrong function " + "definition:\n"); + printf("%p inside %s %p instead of %s %p\n", + (void *) ir, + this->current_function->name, (void *) this->current_function, + ir->function_name(), (void *) ir->function()); + abort(); + } + + this->validate_ir(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_validate::visit_leave(ir_expression *ir) +{ + switch (ir->operation) { + case ir_unop_bit_not: + assert(ir->operands[0]->type == ir->type); + break; + case ir_unop_logic_not: + assert(ir->type->base_type == GLSL_TYPE_BOOL); + assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL); + break; + + case ir_unop_neg: + case ir_unop_abs: + case ir_unop_sign: + case ir_unop_rcp: + case ir_unop_rsq: + case ir_unop_sqrt: + assert(ir->type == ir->operands[0]->type); + break; + + case ir_unop_exp: + case ir_unop_log: + case ir_unop_exp2: + case ir_unop_log2: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT); + assert(ir->type == ir->operands[0]->type); + break; + + case ir_unop_f2i: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT); + assert(ir->type->base_type == GLSL_TYPE_INT); + break; + case ir_unop_i2f: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT); + assert(ir->type->base_type == GLSL_TYPE_FLOAT); + break; + case ir_unop_f2b: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT); + assert(ir->type->base_type == GLSL_TYPE_BOOL); + break; + case ir_unop_b2f: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL); + assert(ir->type->base_type == GLSL_TYPE_FLOAT); + break; + case ir_unop_i2b: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT); + assert(ir->type->base_type == GLSL_TYPE_BOOL); + break; + case ir_unop_b2i: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL); + assert(ir->type->base_type == GLSL_TYPE_INT); + break; + case ir_unop_u2f: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_UINT); + assert(ir->type->base_type == GLSL_TYPE_FLOAT); + break; + + case ir_unop_any: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL); + assert(ir->type == glsl_type::bool_type); + break; + + case ir_unop_trunc: + case ir_unop_ceil: + case ir_unop_floor: + case ir_unop_fract: + case ir_unop_sin: + case ir_unop_cos: + case ir_unop_dFdx: + case ir_unop_dFdy: + assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT); + assert(ir->operands[0]->type == ir->type); + break; + + case ir_binop_add: + case ir_binop_sub: + case ir_binop_mul: + case ir_binop_div: + case ir_binop_mod: + case ir_binop_min: + case ir_binop_max: + case ir_binop_pow: + if (ir->operands[0]->type->is_scalar()) + assert(ir->operands[1]->type == ir->type); + else if (ir->operands[1]->type->is_scalar()) + assert(ir->operands[0]->type == ir->type); + else if (ir->operands[0]->type->is_vector() && + ir->operands[1]->type->is_vector()) { + assert(ir->operands[0]->type == ir->operands[1]->type); + assert(ir->operands[0]->type == ir->type); + } + break; + case ir_binop_less: + case ir_binop_greater: + case ir_binop_lequal: + case ir_binop_gequal: + /* GLSL < > <= >= operators take scalar floats/ints, but in the + * IR we may want to do them for vectors instead to support the + * lessEqual() and friends builtins. + */ + assert(ir->type == glsl_type::bool_type); + assert(ir->operands[0]->type == ir->operands[1]->type); + break; + + case ir_binop_equal: + case ir_binop_nequal: + /* GLSL == and != operate on vectors and return a bool, and the + * IR matches that. We may want to switch up the IR to work on + * vectors and return a bvec and make the operators break down + * to ANDing/ORing the results of the vector comparison. + */ + assert(ir->type == glsl_type::bool_type); + assert(ir->operands[0]->type == ir->operands[1]->type); + break; + + case ir_binop_lshift: + case ir_binop_rshift: + case ir_binop_bit_and: + case ir_binop_bit_xor: + case ir_binop_bit_or: + assert(ir->operands[0]->type == ir->operands[1]->type); + assert(ir->type == ir->operands[0]->type); + assert(ir->type->base_type == GLSL_TYPE_INT || + ir->type->base_type == GLSL_TYPE_UINT); + break; + + case ir_binop_logic_and: + case ir_binop_logic_xor: + case ir_binop_logic_or: + assert(ir->type == glsl_type::bool_type); + assert(ir->operands[0]->type == glsl_type::bool_type); + assert(ir->operands[1]->type == glsl_type::bool_type); + break; + + case ir_binop_dot: + assert(ir->type == glsl_type::float_type); + assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT); + assert(ir->operands[0]->type == ir->operands[1]->type); + break; + + case ir_binop_cross: + assert(ir->operands[0]->type == glsl_type::vec3_type); + assert(ir->operands[1]->type == glsl_type::vec3_type); + assert(ir->type == glsl_type::vec3_type); + break; + } + + return visit_continue; +} + +ir_visitor_status +ir_validate::visit(ir_variable *ir) +{ + /* An ir_variable is the one thing that can (and will) appear multiple times + * in an IR tree. It is added to the hashtable so that it can be used + * in the ir_dereference_variable handler to ensure that a variable is + * declared before it is dereferenced. + */ + if (ir->name) + assert(talloc_parent(ir->name) == ir); + + hash_table_insert(ht, ir, ir); + return visit_continue; +} + +ir_visitor_status +ir_validate::visit_enter(ir_assignment *ir) +{ + const ir_dereference *const lhs = ir->lhs; + if (lhs->type->is_scalar() || lhs->type->is_vector()) { + if (ir->write_mask == 0) { + printf("Assignment LHS is %s, but write mask is 0:\n", + lhs->type->is_scalar() ? "scalar" : "vector"); + ir->print(); + abort(); + } + + /* Mask of fields that do not exist in the destination. These should + * not be written by the assignment. + */ + const unsigned invalid_mask = ~((1U << lhs->type->components()) - 1); + + if ((invalid_mask & ir->write_mask) != 0) { + printf("Assignment write mask enables invalid components for " + "type %s:\n", lhs->type->name); + ir->print(); + abort(); + } + } + + this->validate_ir(ir, this->data); + + return visit_continue; +} + +void +ir_validate::validate_ir(ir_instruction *ir, void *data) +{ + struct hash_table *ht = (struct hash_table *) data; + + if (hash_table_find(ht, ir)) { + printf("Instruction node present twice in ir tree:\n"); + ir->print(); + printf("\n"); + abort(); + } + hash_table_insert(ht, ir, ir); +} + +void +check_node_type(ir_instruction *ir, void *data) +{ + (void) data; + + if (ir->ir_type <= ir_type_unset || ir->ir_type >= ir_type_max) { + printf("Instruction node with unset type\n"); + ir->print(); printf("\n"); + } + assert(ir->type != glsl_type::error_type); +} + +void +validate_ir_tree(exec_list *instructions) +{ + ir_validate v; + + v.run(instructions); + + foreach_iter(exec_list_iterator, iter, *instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + + visit_tree(ir, check_node_type, NULL); + } +} diff --git a/src/glsl/ir_variable.cpp b/src/glsl/ir_variable.cpp new file mode 100644 index 0000000000..e638c9602f --- /dev/null +++ b/src/glsl/ir_variable.cpp @@ -0,0 +1,415 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ir.h" +#include "glsl_parser_extras.h" +#include "glsl_symbol_table.h" +#include "builtin_variables.h" + +static void generate_ARB_draw_buffers_variables(exec_list *, + struct _mesa_glsl_parse_state *, + bool, _mesa_glsl_parser_targets); + +static ir_variable * +add_variable(const char *name, enum ir_variable_mode mode, int slot, + const glsl_type *type, exec_list *instructions, + glsl_symbol_table *symtab) +{ + ir_variable *var = new(symtab) ir_variable(type, name, mode); + + switch (var->mode) { + case ir_var_auto: + case ir_var_in: + case ir_var_uniform: + var->read_only = true; + break; + case ir_var_inout: + case ir_var_out: + break; + default: + assert(0); + break; + } + + var->location = slot; + + /* Once the variable is created an initialized, add it to the symbol table + * and add the declaration to the IR stream. + */ + instructions->push_tail(var); + + symtab->add_variable(var->name, var); + return var; +} + +static ir_variable * +add_uniform(exec_list *instructions, + struct _mesa_glsl_parse_state *state, + const char *name, const glsl_type *type) +{ + return add_variable(name, ir_var_uniform, -1, type, instructions, + state->symbols); +} + +static void +add_builtin_variable(const builtin_variable *proto, exec_list *instructions, + glsl_symbol_table *symtab) +{ + /* Create a new variable declaration from the description supplied by + * the caller. + */ + const glsl_type *const type = symtab->get_type(proto->type); + + assert(type != NULL); + + add_variable(proto->name, proto->mode, proto->slot, type, instructions, + symtab); +} + +static void +add_builtin_constant(exec_list *instructions, + struct _mesa_glsl_parse_state *state, + const char *name, int value) +{ + ir_variable *const var = add_variable(name, ir_var_auto, + -1, glsl_type::int_type, + instructions, state->symbols); + var->constant_value = new(var) ir_constant(value); +} + +static void +generate_110_uniforms(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + for (unsigned i = 0 + ; i < Elements(builtin_110_deprecated_uniforms) + ; i++) { + add_builtin_variable(& builtin_110_deprecated_uniforms[i], + instructions, state->symbols); + } + + add_builtin_constant(instructions, state, "gl_MaxLights", + state->Const.MaxLights); + add_builtin_constant(instructions, state, "gl_MaxClipPlanes", + state->Const.MaxClipPlanes); + add_builtin_constant(instructions, state, "gl_MaxTextureUnits", + state->Const.MaxTextureUnits); + add_builtin_constant(instructions, state, "gl_MaxTextureCoords", + state->Const.MaxTextureCoords); + add_builtin_constant(instructions, state, "gl_MaxVertexAttribs", + state->Const.MaxVertexAttribs); + add_builtin_constant(instructions, state, "gl_MaxVertexUniformComponents", + state->Const.MaxVertexUniformComponents); + add_builtin_constant(instructions, state, "gl_MaxVaryingFloats", + state->Const.MaxVaryingFloats); + add_builtin_constant(instructions, state, "gl_MaxVertexTextureImageUnits", + state->Const.MaxVertexTextureImageUnits); + add_builtin_constant(instructions, state, "gl_MaxCombinedTextureImageUnits", + state->Const.MaxCombinedTextureImageUnits); + add_builtin_constant(instructions, state, "gl_MaxTextureImageUnits", + state->Const.MaxTextureImageUnits); + add_builtin_constant(instructions, state, "gl_MaxFragmentUniformComponents", + state->Const.MaxFragmentUniformComponents); + + const glsl_type *const mat4_array_type = + glsl_type::get_array_instance(glsl_type::mat4_type, + state->Const.MaxTextureCoords); + + add_uniform(instructions, state, "gl_TextureMatrix", mat4_array_type); + + add_uniform(instructions, state, "gl_DepthRange", + state->symbols->get_type("gl_DepthRangeParameters")); + + add_uniform(instructions, state, "gl_ClipPlane", + glsl_type::get_array_instance(glsl_type::vec4_type, + state->Const.MaxClipPlanes)); + add_uniform(instructions, state, "gl_Point", + state->symbols->get_type("gl_PointParameters")); + + const glsl_type *const material_parameters_type = + state->symbols->get_type("gl_MaterialParameters"); + add_uniform(instructions, state, "gl_FrontMaterial", material_parameters_type); + add_uniform(instructions, state, "gl_BackMaterial", material_parameters_type); + + const glsl_type *const light_source_array_type = + glsl_type::get_array_instance(state->symbols->get_type("gl_LightSourceParameters"), state->Const.MaxLights); + + add_uniform(instructions, state, "gl_LightSource", light_source_array_type); + + const glsl_type *const light_model_products_type = + state->symbols->get_type("gl_LightModelProducts"); + add_uniform(instructions, state, "gl_FrontLightModelProduct", + light_model_products_type); + add_uniform(instructions, state, "gl_BackLightModelProduct", + light_model_products_type); + + const glsl_type *const light_products_type = + glsl_type::get_array_instance(state->symbols->get_type("gl_LightProducts"), + state->Const.MaxLights); + add_uniform(instructions, state, "gl_FrontLightProduct", light_products_type); + add_uniform(instructions, state, "gl_BackLightProduct", light_products_type); + + add_uniform(instructions, state, "gl_TextureEnvColor", + glsl_type::get_array_instance(glsl_type::vec4_type, + state->Const.MaxTextureUnits)); + + const glsl_type *const texcoords_vec4 = + glsl_type::get_array_instance(glsl_type::vec4_type, + state->Const.MaxTextureCoords); + add_uniform(instructions, state, "gl_EyePlaneS", texcoords_vec4); + add_uniform(instructions, state, "gl_EyePlaneT", texcoords_vec4); + add_uniform(instructions, state, "gl_EyePlaneR", texcoords_vec4); + add_uniform(instructions, state, "gl_EyePlaneQ", texcoords_vec4); + add_uniform(instructions, state, "gl_ObjectPlaneS", texcoords_vec4); + add_uniform(instructions, state, "gl_ObjectPlaneT", texcoords_vec4); + add_uniform(instructions, state, "gl_ObjectPlaneR", texcoords_vec4); + add_uniform(instructions, state, "gl_ObjectPlaneQ", texcoords_vec4); + + add_uniform(instructions, state, "gl_Fog", + state->symbols->get_type("gl_FogParameters")); +} + +static void +generate_110_vs_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + for (unsigned i = 0; i < Elements(builtin_core_vs_variables); i++) { + add_builtin_variable(& builtin_core_vs_variables[i], + instructions, state->symbols); + } + + for (unsigned i = 0 + ; i < Elements(builtin_110_deprecated_vs_variables) + ; i++) { + add_builtin_variable(& builtin_110_deprecated_vs_variables[i], + instructions, state->symbols); + } + generate_110_uniforms(instructions, state); + + /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec: + * + * "As with all arrays, indices used to subscript gl_TexCoord must + * either be an integral constant expressions, or this array must be + * re-declared by the shader with a size. The size can be at most + * gl_MaxTextureCoords. Using indexes close to 0 may aid the + * implementation in preserving varying resources." + */ + const glsl_type *const vec4_array_type = + glsl_type::get_array_instance(glsl_type::vec4_type, 0); + + add_variable("gl_TexCoord", ir_var_out, VERT_RESULT_TEX0, vec4_array_type, + instructions, state->symbols); + + generate_ARB_draw_buffers_variables(instructions, state, false, + vertex_shader); +} + + +static void +generate_120_vs_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + /* GLSL version 1.20 did not add any built-in variables in the vertex + * shader. + */ + generate_110_vs_variables(instructions, state); +} + + +static void +generate_130_vs_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + generate_120_vs_variables(instructions, state); + + for (unsigned i = 0; i < Elements(builtin_130_vs_variables); i++) { + add_builtin_variable(& builtin_130_vs_variables[i], + instructions, state->symbols); + } + + const glsl_type *const clip_distance_array_type = + glsl_type::get_array_instance(glsl_type::float_type, + state->Const.MaxClipPlanes); + + /* FINISHME: gl_ClipDistance needs a real location assigned. */ + add_variable("gl_ClipDistance", ir_var_out, -1, clip_distance_array_type, + instructions, state->symbols); + +} + + +static void +initialize_vs_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + + switch (state->language_version) { + case 110: + generate_110_vs_variables(instructions, state); + break; + case 120: + generate_120_vs_variables(instructions, state); + break; + case 130: + generate_130_vs_variables(instructions, state); + break; + } +} + +static void +generate_110_fs_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + for (unsigned i = 0; i < Elements(builtin_core_fs_variables); i++) { + add_builtin_variable(& builtin_core_fs_variables[i], + instructions, state->symbols); + } + + for (unsigned i = 0 + ; i < Elements(builtin_110_deprecated_fs_variables) + ; i++) { + add_builtin_variable(& builtin_110_deprecated_fs_variables[i], + instructions, state->symbols); + } + generate_110_uniforms(instructions, state); + + /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec: + * + * "As with all arrays, indices used to subscript gl_TexCoord must + * either be an integral constant expressions, or this array must be + * re-declared by the shader with a size. The size can be at most + * gl_MaxTextureCoords. Using indexes close to 0 may aid the + * implementation in preserving varying resources." + */ + const glsl_type *const vec4_array_type = + glsl_type::get_array_instance(glsl_type::vec4_type, 0); + + add_variable("gl_TexCoord", ir_var_in, FRAG_ATTRIB_TEX0, vec4_array_type, + instructions, state->symbols); + + generate_ARB_draw_buffers_variables(instructions, state, false, + fragment_shader); +} + + +static void +generate_ARB_draw_buffers_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state, + bool warn, _mesa_glsl_parser_targets target) +{ + /* gl_MaxDrawBuffers is available in all shader stages. + */ + ir_variable *const mdb = + add_variable("gl_MaxDrawBuffers", ir_var_auto, -1, + glsl_type::int_type, instructions, state->symbols); + + if (warn) + mdb->warn_extension = "GL_ARB_draw_buffers"; + + mdb->constant_value = new(mdb) + ir_constant(int(state->Const.MaxDrawBuffers)); + + + /* gl_FragData is only available in the fragment shader. + */ + if (target == fragment_shader) { + const glsl_type *const vec4_array_type = + glsl_type::get_array_instance(glsl_type::vec4_type, + state->Const.MaxDrawBuffers); + + ir_variable *const fd = + add_variable("gl_FragData", ir_var_out, FRAG_RESULT_DATA0, + vec4_array_type, instructions, state->symbols); + + if (warn) + fd->warn_extension = "GL_ARB_draw_buffers"; + } +} + + +static void +generate_120_fs_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + generate_110_fs_variables(instructions, state); + + for (unsigned i = 0 + ; i < Elements(builtin_120_fs_variables) + ; i++) { + add_builtin_variable(& builtin_120_fs_variables[i], + instructions, state->symbols); + } +} + +static void +generate_130_fs_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + generate_120_fs_variables(instructions, state); + + const glsl_type *const clip_distance_array_type = + glsl_type::get_array_instance(glsl_type::float_type, + state->Const.MaxClipPlanes); + + /* FINISHME: gl_ClipDistance needs a real location assigned. */ + add_variable("gl_ClipDistance", ir_var_in, -1, clip_distance_array_type, + instructions, state->symbols); +} + +static void +initialize_fs_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + + switch (state->language_version) { + case 110: + generate_110_fs_variables(instructions, state); + break; + case 120: + generate_120_fs_variables(instructions, state); + break; + case 130: + generate_130_fs_variables(instructions, state); + break; + } +} + +void +_mesa_glsl_initialize_variables(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + switch (state->target) { + case vertex_shader: + initialize_vs_variables(instructions, state); + break; + case geometry_shader: + break; + case fragment_shader: + initialize_fs_variables(instructions, state); + break; + case ir_shader: + fprintf(stderr, "ir reader has no builtin variables"); + exit(1); + break; + } +} diff --git a/src/glsl/ir_variable_refcount.cpp b/src/glsl/ir_variable_refcount.cpp new file mode 100644 index 0000000000..7d39abb368 --- /dev/null +++ b/src/glsl/ir_variable_refcount.cpp @@ -0,0 +1,113 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_variable_refcount.cpp + * + * Provides a visitor which produces a list of variables referenced, + * how many times they were referenced and assigned, and whether they + * were defined in the scope. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_variable_refcount.h" +#include "glsl_types.h" + + +// constructor +variable_entry::variable_entry(ir_variable *var) +{ + this->var = var; + assign = NULL; + assigned_count = 0; + declaration = false; + referenced_count = 0; +} + + +variable_entry * +ir_variable_refcount_visitor::get_variable_entry(ir_variable *var) +{ + assert(var); + foreach_iter(exec_list_iterator, iter, this->variable_list) { + variable_entry *entry = (variable_entry *)iter.get(); + if (entry->var == var) + return entry; + } + + variable_entry *entry = new(mem_ctx) variable_entry(var); + assert(entry->referenced_count == 0); + this->variable_list.push_tail(entry); + return entry; +} + + +ir_visitor_status +ir_variable_refcount_visitor::visit(ir_variable *ir) +{ + variable_entry *entry = this->get_variable_entry(ir); + if (entry) + entry->declaration = true; + + return visit_continue; +} + + +ir_visitor_status +ir_variable_refcount_visitor::visit(ir_dereference_variable *ir) +{ + ir_variable *const var = ir->variable_referenced(); + variable_entry *entry = this->get_variable_entry(var); + + if (entry) + entry->referenced_count++; + + return visit_continue; +} + + +ir_visitor_status +ir_variable_refcount_visitor::visit_enter(ir_function_signature *ir) +{ + /* We don't want to descend into the function parameters and + * dead-code eliminate them, so just accept the body here. + */ + visit_list_elements(this, &ir->body); + return visit_continue_with_parent; +} + + +ir_visitor_status +ir_variable_refcount_visitor::visit_leave(ir_assignment *ir) +{ + variable_entry *entry; + entry = this->get_variable_entry(ir->lhs->variable_referenced()); + if (entry) { + entry->assigned_count++; + if (entry->assign == NULL) + entry->assign = ir; + } + + return visit_continue; +} diff --git a/src/glsl/ir_variable_refcount.h b/src/glsl/ir_variable_refcount.h new file mode 100644 index 0000000000..8b43bad71f --- /dev/null +++ b/src/glsl/ir_variable_refcount.h @@ -0,0 +1,78 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_variable_refcount.h + * + * Provides a visitor which produces a list of variables referenced, + * how many times they were referenced and assigned, and whether they + * were defined in the scope. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "glsl_types.h" + +class variable_entry : public exec_node +{ +public: + variable_entry(ir_variable *var); + + ir_variable *var; /* The key: the variable's pointer. */ + ir_assignment *assign; /* An assignment to the variable, if any */ + + /** Number of times the variable is referenced, including assignments. */ + unsigned referenced_count; + + /** Number of times the variable is assigned. */ + unsigned assigned_count; + + bool declaration; /* If the variable had a decl in the instruction stream */ +}; + +class ir_variable_refcount_visitor : public ir_hierarchical_visitor { +public: + ir_variable_refcount_visitor(void) + { + this->mem_ctx = talloc_new(NULL); + this->variable_list.make_empty(); + } + + ~ir_variable_refcount_visitor(void) + { + talloc_free(this->mem_ctx); + } + + virtual ir_visitor_status visit(ir_variable *); + virtual ir_visitor_status visit(ir_dereference_variable *); + + virtual ir_visitor_status visit_enter(ir_function_signature *); + virtual ir_visitor_status visit_leave(ir_assignment *); + + variable_entry *get_variable_entry(ir_variable *var); + + /* List of variable_entry */ + exec_list variable_list; + + void *mem_ctx; +}; diff --git a/src/glsl/ir_vec_index_to_cond_assign.cpp b/src/glsl/ir_vec_index_to_cond_assign.cpp new file mode 100644 index 0000000000..cd8dedf2fe --- /dev/null +++ b/src/glsl/ir_vec_index_to_cond_assign.cpp @@ -0,0 +1,258 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_vec_index_to_cond_assign.cpp + * + * Turns indexing into vector types to a series of conditional moves + * of each channel's swizzle into a temporary. + * + * Most GPUs don't have a native way to do this operation, and this + * works around that. For drivers using both this pass and + * ir_vec_index_to_swizzle, there's a risk that this pass will happen + * before sufficient constant folding to find that the array index is + * constant. However, we hope that other optimization passes, + * particularly constant folding of assignment conditions and copy + * propagation, will result in the same code in the end. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +/** + * Visitor class for replacing expressions with ir_constant values. + */ + +class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor { +public: + ir_vec_index_to_cond_assign_visitor() + { + progress = false; + } + + ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val); + + virtual ir_visitor_status visit_enter(ir_expression *); + virtual ir_visitor_status visit_enter(ir_swizzle *); + virtual ir_visitor_status visit_leave(ir_assignment *); + virtual ir_visitor_status visit_enter(ir_return *); + virtual ir_visitor_status visit_enter(ir_call *); + virtual ir_visitor_status visit_enter(ir_if *); + + bool progress; +}; + +ir_rvalue * +ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir) +{ + ir_dereference_array *orig_deref = ir->as_dereference_array(); + ir_assignment *assign; + ir_variable *index, *var; + ir_dereference *deref; + ir_expression *condition; + ir_swizzle *swizzle; + int i; + + if (!orig_deref) + return ir; + + if (orig_deref->array->type->is_matrix() || + orig_deref->array->type->is_array()) + return ir; + + void *mem_ctx = talloc_parent(ir); + + assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT); + + /* Store the index to a temporary to avoid reusing its tree. */ + index = new(base_ir) ir_variable(glsl_type::int_type, + "vec_index_tmp_i", + ir_var_temporary); + base_ir->insert_before(index); + deref = new(base_ir) ir_dereference_variable(index); + assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL); + base_ir->insert_before(assign); + + /* Temporary where we store whichever value we swizzle out. */ + var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v", + ir_var_temporary); + base_ir->insert_before(var); + + /* Generate a conditional move of each vector element to the temp. */ + for (i = 0; i < orig_deref->array->type->vector_elements; i++) { + deref = new(base_ir) ir_dereference_variable(index); + condition = new(base_ir) ir_expression(ir_binop_equal, + glsl_type::bool_type, + deref, + new(base_ir) ir_constant(i)); + + /* Just clone the rest of the deref chain when trying to get at the + * underlying variable. + */ + swizzle = new(base_ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL), + i, 0, 0, 0, 1); + + deref = new(base_ir) ir_dereference_variable(var); + assign = new(base_ir) ir_assignment(deref, swizzle, condition); + base_ir->insert_before(assign); + } + + this->progress = true; + return new(base_ir) ir_dereference_variable(var); +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir) +{ + unsigned int i; + + for (i = 0; i < ir->get_num_operands(); i++) { + ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]); + } + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir) +{ + /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which + * the result of indexing a vector is. But maybe at some point we'll end up + * using swizzling of scalars for vector construction. + */ + ir->val = convert_vec_index_to_cond_assign(ir->val); + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir) +{ + ir_variable *index, *var; + ir_dereference_variable *deref; + ir_assignment *assign; + int i; + + ir->rhs = convert_vec_index_to_cond_assign(ir->rhs); + if (ir->condition) + ir->condition = convert_vec_index_to_cond_assign(ir->condition); + + /* Last, handle the LHS */ + ir_dereference_array *orig_deref = ir->lhs->as_dereference_array(); + + if (!orig_deref || + orig_deref->array->type->is_matrix() || + orig_deref->array->type->is_array()) + return visit_continue; + + void *mem_ctx = talloc_parent(ir); + + assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT); + + /* Store the index to a temporary to avoid reusing its tree. */ + index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i", + ir_var_temporary); + ir->insert_before(index); + deref = new(ir) ir_dereference_variable(index); + assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL); + ir->insert_before(assign); + + /* Store the RHS to a temporary to avoid reusing its tree. */ + var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v", + ir_var_temporary); + ir->insert_before(var); + deref = new(ir) ir_dereference_variable(var); + assign = new(ir) ir_assignment(deref, ir->rhs, NULL); + ir->insert_before(assign); + + /* Generate a conditional move of each vector element to the temp. */ + for (i = 0; i < orig_deref->array->type->vector_elements; i++) { + ir_rvalue *condition, *swizzle; + + deref = new(ir) ir_dereference_variable(index); + condition = new(ir) ir_expression(ir_binop_equal, + glsl_type::bool_type, + deref, + new(ir) ir_constant(i)); + + /* Just clone the rest of the deref chain when trying to get at the + * underlying variable. + */ + swizzle = new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL), + i, 0, 0, 0, 1); + + deref = new(ir) ir_dereference_variable(var); + assign = new(ir) ir_assignment(swizzle, deref, condition); + ir->insert_before(assign); + } + ir->remove(); + + this->progress = true; + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir) +{ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param = (ir_rvalue *)iter.get(); + ir_rvalue *new_param = convert_vec_index_to_cond_assign(param); + + if (new_param != param) { + param->replace_with(new_param); + } + } + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir) +{ + if (ir->value) { + ir->value = convert_vec_index_to_cond_assign(ir->value); + } + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir) +{ + ir->condition = convert_vec_index_to_cond_assign(ir->condition); + + return visit_continue; +} + +bool +do_vec_index_to_cond_assign(exec_list *instructions) +{ + ir_vec_index_to_cond_assign_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} diff --git a/src/glsl/ir_vec_index_to_swizzle.cpp b/src/glsl/ir_vec_index_to_swizzle.cpp new file mode 100644 index 0000000000..969dc8f94a --- /dev/null +++ b/src/glsl/ir_vec_index_to_swizzle.cpp @@ -0,0 +1,157 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_vec_index_to_swizzle.cpp + * + * Turns constant indexing into vector types to swizzles. This will + * let other swizzle-aware optimization passes catch these constructs, + * and codegen backends not have to worry about this case. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +/** + * Visitor class for replacing expressions with ir_constant values. + */ + +class ir_vec_index_to_swizzle_visitor : public ir_hierarchical_visitor { +public: + ir_vec_index_to_swizzle_visitor() + { + progress = false; + } + + ir_rvalue *convert_vec_index_to_swizzle(ir_rvalue *val); + + virtual ir_visitor_status visit_enter(ir_expression *); + virtual ir_visitor_status visit_enter(ir_swizzle *); + virtual ir_visitor_status visit_enter(ir_assignment *); + virtual ir_visitor_status visit_enter(ir_return *); + virtual ir_visitor_status visit_enter(ir_call *); + virtual ir_visitor_status visit_enter(ir_if *); + + bool progress; +}; + +ir_rvalue * +ir_vec_index_to_swizzle_visitor::convert_vec_index_to_swizzle(ir_rvalue *ir) +{ + ir_dereference_array *deref = ir->as_dereference_array(); + ir_constant *ir_constant; + + if (!deref) + return ir; + + if (deref->array->type->is_matrix() || deref->array->type->is_array()) + return ir; + + assert(deref->array_index->type->base_type == GLSL_TYPE_INT); + ir_constant = deref->array_index->constant_expression_value(); + if (!ir_constant) + return ir; + + void *ctx = talloc_parent(ir); + this->progress = true; + return new(ctx) ir_swizzle(deref->array, + ir_constant->value.i[0], 0, 0, 0, 1); +} + +ir_visitor_status +ir_vec_index_to_swizzle_visitor::visit_enter(ir_expression *ir) +{ + unsigned int i; + + for (i = 0; i < ir->get_num_operands(); i++) { + ir->operands[i] = convert_vec_index_to_swizzle(ir->operands[i]); + } + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir) +{ + /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which + * the result of indexing a vector is. But maybe at some point we'll end up + * using swizzling of scalars for vector construction. + */ + ir->val = convert_vec_index_to_swizzle(ir->val); + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir) +{ + ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs)); + ir->rhs = convert_vec_index_to_swizzle(ir->rhs); + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_swizzle_visitor::visit_enter(ir_call *ir) +{ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param = (ir_rvalue *)iter.get(); + ir_rvalue *new_param = convert_vec_index_to_swizzle(param); + + if (new_param != param) { + param->replace_with(new_param); + } + } + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_swizzle_visitor::visit_enter(ir_return *ir) +{ + if (ir->value) { + ir->value = convert_vec_index_to_swizzle(ir->value); + } + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_swizzle_visitor::visit_enter(ir_if *ir) +{ + ir->condition = convert_vec_index_to_swizzle(ir->condition); + + return visit_continue; +} + +bool +do_vec_index_to_swizzle(exec_list *instructions) +{ + ir_vec_index_to_swizzle_visitor v; + + v.run(instructions); + + return v.progress; +} diff --git a/src/glsl/ir_visitor.h b/src/glsl/ir_visitor.h new file mode 100644 index 0000000000..b87d737318 --- /dev/null +++ b/src/glsl/ir_visitor.h @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef IR_VISITOR_H +#define IR_VISITOR_H + +/** + * Abstract base class of visitors of IR instruction trees + */ +class ir_visitor { +public: + virtual ~ir_visitor() + { + /* empty */ + } + + /** + * \name Visit methods + * + * As typical for the visitor pattern, there must be one \c visit method for + * each concrete subclass of \c ir_instruction. Virtual base classes within + * the hierarchy should not have \c visit methods. + */ + /*@{*/ + virtual void visit(class ir_variable *) = 0; + virtual void visit(class ir_function_signature *) = 0; + virtual void visit(class ir_function *) = 0; + virtual void visit(class ir_expression *) = 0; + virtual void visit(class ir_texture *) = 0; + virtual void visit(class ir_swizzle *) = 0; + virtual void visit(class ir_dereference_variable *) = 0; + virtual void visit(class ir_dereference_array *) = 0; + virtual void visit(class ir_dereference_record *) = 0; + virtual void visit(class ir_assignment *) = 0; + virtual void visit(class ir_constant *) = 0; + virtual void visit(class ir_call *) = 0; + virtual void visit(class ir_return *) = 0; + virtual void visit(class ir_discard *) = 0; + virtual void visit(class ir_if *) = 0; + virtual void visit(class ir_loop *) = 0; + virtual void visit(class ir_loop_jump *) = 0; + /*@}*/ +}; + +#endif /* IR_VISITOR_H */ diff --git a/src/glsl/link_functions.cpp b/src/glsl/link_functions.cpp new file mode 100644 index 0000000000..78c8b48cf1 --- /dev/null +++ b/src/glsl/link_functions.cpp @@ -0,0 +1,262 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <cstdlib> +#include <cstdio> +#include <cstdarg> + +extern "C" { +#include <talloc.h> +} + +#include "main/core.h" +#include "glsl_symbol_table.h" +#include "glsl_parser_extras.h" +#include "ir.h" +#include "program.h" +#include "program/hash_table.h" +#include "linker.h" + +static ir_function_signature * +find_matching_signature(const char *name, const exec_list *actual_parameters, + gl_shader **shader_list, unsigned num_shaders); + +class call_link_visitor : public ir_hierarchical_visitor { +public: + call_link_visitor(gl_shader_program *prog, gl_shader *linked, + gl_shader **shader_list, unsigned num_shaders) + { + this->prog = prog; + this->shader_list = shader_list; + this->num_shaders = num_shaders; + this->success = true; + this->linked = linked; + + this->locals = hash_table_ctor(0, hash_table_pointer_hash, + hash_table_pointer_compare); + } + + ~call_link_visitor() + { + hash_table_dtor(this->locals); + } + + virtual ir_visitor_status visit(ir_variable *ir) + { + hash_table_insert(locals, ir, ir); + return visit_continue; + } + + virtual ir_visitor_status visit_enter(ir_call *ir) + { + /* If ir is an ir_call from a function that was imported from another + * shader callee will point to an ir_function_signature in the original + * shader. In this case the function signature MUST NOT BE MODIFIED. + * Doing so will modify the original shader. This may prevent that + * shader from being linkable in other programs. + */ + const ir_function_signature *const callee = ir->get_callee(); + assert(callee != NULL); + const char *const name = callee->function_name(); + + /* Determine if the requested function signature already exists in the + * final linked shader. If it does, use it as the target of the call. + */ + ir_function_signature *sig = + find_matching_signature(name, &callee->parameters, &linked, 1); + if (sig != NULL) { + ir->set_callee(sig); + return visit_continue; + } + + /* Try to find the signature in one of the other shaders that is being + * linked. If it's not found there, return an error. + */ + sig = find_matching_signature(name, &ir->actual_parameters, shader_list, + num_shaders); + if (sig == NULL) { + /* FINISHME: Log the full signature of unresolved function. + */ + linker_error_printf(this->prog, "unresolved reference to function " + "`%s'\n", name); + this->success = false; + return visit_stop; + } + + /* Find the prototype information in the linked shader. Generate any + * details that may be missing. + */ + ir_function *f = linked->symbols->get_function(name); + if (f == NULL) + f = new(linked) ir_function(name); + + ir_function_signature *linked_sig = + f->exact_matching_signature(&callee->parameters); + if (linked_sig == NULL) { + linked_sig = new(linked) ir_function_signature(callee->return_type); + f->add_signature(linked_sig); + } + + /* At this point linked_sig and called may be the same. If ir is an + * ir_call from linked then linked_sig and callee will be + * ir_function_signatures that have no definitions (is_defined is false). + */ + assert(!linked_sig->is_defined); + assert(linked_sig->body.is_empty()); + + /* Create an in-place clone of the function definition. This multistep + * process introduces some complexity here, but it has some advantages. + * The parameter list and the and function body are cloned separately. + * The clone of the parameter list is used to prime the hashtable used + * to replace variable references in the cloned body. + * + * The big advantage is that the ir_function_signature does not change. + * This means that we don't have to process the rest of the IR tree to + * patch ir_call nodes. In addition, there is no way to remove or + * replace signature stored in a function. One could easily be added, + * but this avoids the need. + */ + struct hash_table *ht = hash_table_ctor(0, hash_table_pointer_hash, + hash_table_pointer_compare); + exec_list formal_parameters; + foreach_list_const(node, &sig->parameters) { + const ir_instruction *const original = (ir_instruction *) node; + assert(const_cast<ir_instruction *>(original)->as_variable()); + + ir_instruction *copy = original->clone(linked, ht); + formal_parameters.push_tail(copy); + } + + linked_sig->replace_parameters(&formal_parameters); + + foreach_list_const(node, &sig->body) { + const ir_instruction *const original = (ir_instruction *) node; + + ir_instruction *copy = original->clone(linked, ht); + linked_sig->body.push_tail(copy); + } + + linked_sig->is_defined = true; + hash_table_dtor(ht); + + /* Patch references inside the function to things outside the function + * (i.e., function calls and global variables). + */ + linked_sig->accept(this); + + ir->set_callee(linked_sig); + + return visit_continue; + } + + virtual ir_visitor_status visit(ir_dereference_variable *ir) + { + if (hash_table_find(locals, ir->var) == NULL) { + /* The non-function variable must be a global, so try to find the + * variable in the shader's symbol table. If the variable is not + * found, then it's a global that *MUST* be defined in the original + * shader. + */ + ir_variable *var = linked->symbols->get_variable(ir->var->name); + if (var == NULL) { + /* Clone the ir_variable that the dereference already has and add + * it to the linked shader. + */ + var = ir->var->clone(linked, NULL); + linked->symbols->add_variable(var->name, var); + linked->ir->push_head(var); + } + + ir->var = var; + } + + return visit_continue; + } + + /** Was function linking successful? */ + bool success; + +private: + /** + * Shader program being linked + * + * This is only used for logging error messages. + */ + gl_shader_program *prog; + + /** List of shaders available for linking. */ + gl_shader **shader_list; + + /** Number of shaders available for linking. */ + unsigned num_shaders; + + /** + * Final linked shader + * + * This is used two ways. It is used to find global variables in the + * linked shader that are accessed by the function. It is also used to add + * global variables from the shader where the function originated. + */ + gl_shader *linked; + + /** + * Table of variables local to the function. + */ + hash_table *locals; +}; + + +/** + * Searches a list of shaders for a particular function definition + */ +ir_function_signature * +find_matching_signature(const char *name, const exec_list *actual_parameters, + gl_shader **shader_list, unsigned num_shaders) +{ + for (unsigned i = 0; i < num_shaders; i++) { + ir_function *const f = shader_list[i]->symbols->get_function(name); + + if (f == NULL) + continue; + + ir_function_signature *sig = f->matching_signature(actual_parameters); + + if ((sig == NULL) || !sig->is_defined) + continue; + + return sig; + } + + return NULL; +} + + +bool +link_function_calls(gl_shader_program *prog, gl_shader *main, + gl_shader **shader_list, unsigned num_shaders) +{ + call_link_visitor v(prog, main, shader_list, num_shaders); + + v.run(main->ir); + return v.success; +} diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp new file mode 100644 index 0000000000..e0823c3af4 --- /dev/null +++ b/src/glsl/linker.cpp @@ -0,0 +1,1501 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file linker.cpp + * GLSL linker implementation + * + * Given a set of shaders that are to be linked to generate a final program, + * there are three distinct stages. + * + * In the first stage shaders are partitioned into groups based on the shader + * type. All shaders of a particular type (e.g., vertex shaders) are linked + * together. + * + * - Undefined references in each shader are resolve to definitions in + * another shader. + * - Types and qualifiers of uniforms, outputs, and global variables defined + * in multiple shaders with the same name are verified to be the same. + * - Initializers for uniforms and global variables defined + * in multiple shaders with the same name are verified to be the same. + * + * The result, in the terminology of the GLSL spec, is a set of shader + * executables for each processing unit. + * + * After the first stage is complete, a series of semantic checks are performed + * on each of the shader executables. + * + * - Each shader executable must define a \c main function. + * - Each vertex shader executable must write to \c gl_Position. + * - Each fragment shader executable must write to either \c gl_FragData or + * \c gl_FragColor. + * + * In the final stage individual shader executables are linked to create a + * complete exectuable. + * + * - Types of uniforms defined in multiple shader stages with the same name + * are verified to be the same. + * - Initializers for uniforms defined in multiple shader stages with the + * same name are verified to be the same. + * - Types and qualifiers of outputs defined in one stage are verified to + * be the same as the types and qualifiers of inputs defined with the same + * name in a later stage. + * + * \author Ian Romanick <ian.d.romanick@intel.com> + */ +#include <cstdlib> +#include <cstdio> +#include <cstdarg> +#include <climits> + +extern "C" { +#include <talloc.h> +} + +#include "main/core.h" +#include "glsl_symbol_table.h" +#include "ir.h" +#include "program.h" +#include "program/hash_table.h" +#include "linker.h" +#include "ir_optimization.h" + +/** + * Visitor that determines whether or not a variable is ever written. + */ +class find_assignment_visitor : public ir_hierarchical_visitor { +public: + find_assignment_visitor(const char *name) + : name(name), found(false) + { + /* empty */ + } + + virtual ir_visitor_status visit_enter(ir_assignment *ir) + { + ir_variable *const var = ir->lhs->variable_referenced(); + + if (strcmp(name, var->name) == 0) { + found = true; + return visit_stop; + } + + return visit_continue_with_parent; + } + + virtual ir_visitor_status visit_enter(ir_call *ir) + { + exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator(); + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param_rval = (ir_rvalue *)iter.get(); + ir_variable *sig_param = (ir_variable *)sig_iter.get(); + + if (sig_param->mode == ir_var_out || + sig_param->mode == ir_var_inout) { + ir_variable *var = param_rval->variable_referenced(); + if (var && strcmp(name, var->name) == 0) { + found = true; + return visit_stop; + } + } + sig_iter.next(); + } + + return visit_continue_with_parent; + } + + bool variable_found() + { + return found; + } + +private: + const char *name; /**< Find writes to a variable with this name. */ + bool found; /**< Was a write to the variable found? */ +}; + + +/** + * Visitor that determines whether or not a variable is ever read. + */ +class find_deref_visitor : public ir_hierarchical_visitor { +public: + find_deref_visitor(const char *name) + : name(name), found(false) + { + /* empty */ + } + + virtual ir_visitor_status visit(ir_dereference_variable *ir) + { + if (strcmp(this->name, ir->var->name) == 0) { + this->found = true; + return visit_stop; + } + + return visit_continue; + } + + bool variable_found() const + { + return this->found; + } + +private: + const char *name; /**< Find writes to a variable with this name. */ + bool found; /**< Was a write to the variable found? */ +}; + + +void +linker_error_printf(gl_shader_program *prog, const char *fmt, ...) +{ + va_list ap; + + prog->InfoLog = talloc_strdup_append(prog->InfoLog, "error: "); + va_start(ap, fmt); + prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, ap); + va_end(ap); +} + + +void +invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode, + int generic_base) +{ + foreach_list(node, sh->ir) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + + if ((var == NULL) || (var->mode != (unsigned) mode)) + continue; + + /* Only assign locations for generic attributes / varyings / etc. + */ + if (var->location >= generic_base) + var->location = -1; + } +} + + +/** + * Determine the number of attribute slots required for a particular type + * + * This code is here because it implements the language rules of a specific + * GLSL version. Since it's a property of the language and not a property of + * types in general, it doesn't really belong in glsl_type. + */ +unsigned +count_attribute_slots(const glsl_type *t) +{ + /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec: + * + * "A scalar input counts the same amount against this limit as a vec4, + * so applications may want to consider packing groups of four + * unrelated float inputs together into a vector to better utilize the + * capabilities of the underlying hardware. A matrix input will use up + * multiple locations. The number of locations used will equal the + * number of columns in the matrix." + * + * The spec does not explicitly say how arrays are counted. However, it + * should be safe to assume the total number of slots consumed by an array + * is the number of entries in the array multiplied by the number of slots + * consumed by a single element of the array. + */ + + if (t->is_array()) + return t->array_size() * count_attribute_slots(t->element_type()); + + if (t->is_matrix()) + return t->matrix_columns; + + return 1; +} + + +/** + * Verify that a vertex shader executable meets all semantic requirements + * + * \param shader Vertex shader executable to be verified + */ +bool +validate_vertex_shader_executable(struct gl_shader_program *prog, + struct gl_shader *shader) +{ + if (shader == NULL) + return true; + + find_assignment_visitor find("gl_Position"); + find.run(shader->ir); + if (!find.variable_found()) { + linker_error_printf(prog, + "vertex shader does not write to `gl_Position'\n"); + return false; + } + + return true; +} + + +/** + * Verify that a fragment shader executable meets all semantic requirements + * + * \param shader Fragment shader executable to be verified + */ +bool +validate_fragment_shader_executable(struct gl_shader_program *prog, + struct gl_shader *shader) +{ + if (shader == NULL) + return true; + + find_assignment_visitor frag_color("gl_FragColor"); + find_assignment_visitor frag_data("gl_FragData"); + + frag_color.run(shader->ir); + frag_data.run(shader->ir); + + if (frag_color.variable_found() && frag_data.variable_found()) { + linker_error_printf(prog, "fragment shader writes to both " + "`gl_FragColor' and `gl_FragData'\n"); + return false; + } + + return true; +} + + +/** + * Generate a string describing the mode of a variable + */ +static const char * +mode_string(const ir_variable *var) +{ + switch (var->mode) { + case ir_var_auto: + return (var->read_only) ? "global constant" : "global variable"; + + case ir_var_uniform: return "uniform"; + case ir_var_in: return "shader input"; + case ir_var_out: return "shader output"; + case ir_var_inout: return "shader inout"; + + case ir_var_temporary: + default: + assert(!"Should not get here."); + return "invalid variable"; + } +} + + +/** + * Perform validation of global variables used across multiple shaders + */ +bool +cross_validate_globals(struct gl_shader_program *prog, + struct gl_shader **shader_list, + unsigned num_shaders, + bool uniforms_only) +{ + /* Examine all of the uniforms in all of the shaders and cross validate + * them. + */ + glsl_symbol_table variables; + for (unsigned i = 0; i < num_shaders; i++) { + foreach_list(node, shader_list[i]->ir) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + + if (var == NULL) + continue; + + if (uniforms_only && (var->mode != ir_var_uniform)) + continue; + + /* Don't cross validate temporaries that are at global scope. These + * will eventually get pulled into the shaders 'main'. + */ + if (var->mode == ir_var_temporary) + continue; + + /* If a global with this name has already been seen, verify that the + * new instance has the same type. In addition, if the globals have + * initializers, the values of the initializers must be the same. + */ + ir_variable *const existing = variables.get_variable(var->name); + if (existing != NULL) { + if (var->type != existing->type) { + /* Consider the types to be "the same" if both types are arrays + * of the same type and one of the arrays is implicitly sized. + * In addition, set the type of the linked variable to the + * explicitly sized array. + */ + if (var->type->is_array() + && existing->type->is_array() + && (var->type->fields.array == existing->type->fields.array) + && ((var->type->length == 0) + || (existing->type->length == 0))) { + if (existing->type->length == 0) + existing->type = var->type; + } else { + linker_error_printf(prog, "%s `%s' declared as type " + "`%s' and type `%s'\n", + mode_string(var), + var->name, var->type->name, + existing->type->name); + return false; + } + } + + /* FINISHME: Handle non-constant initializers. + */ + if (var->constant_value != NULL) { + if (existing->constant_value != NULL) { + if (!var->constant_value->has_value(existing->constant_value)) { + linker_error_printf(prog, "initializers for %s " + "`%s' have differing values\n", + mode_string(var), var->name); + return false; + } + } else + /* If the first-seen instance of a particular uniform did not + * have an initializer but a later instance does, copy the + * initializer to the version stored in the symbol table. + */ + /* FINISHME: This is wrong. The constant_value field should + * FINISHME: not be modified! Imagine a case where a shader + * FINISHME: without an initializer is linked in two different + * FINISHME: programs with shaders that have differing + * FINISHME: initializers. Linking with the first will + * FINISHME: modify the shader, and linking with the second + * FINISHME: will fail. + */ + existing->constant_value = + var->constant_value->clone(talloc_parent(existing), NULL); + } + } else + variables.add_variable(var->name, var); + } + } + + return true; +} + + +/** + * Perform validation of uniforms used across multiple shader stages + */ +bool +cross_validate_uniforms(struct gl_shader_program *prog) +{ + return cross_validate_globals(prog, prog->_LinkedShaders, + prog->_NumLinkedShaders, true); +} + + +/** + * Validate that outputs from one stage match inputs of another + */ +bool +cross_validate_outputs_to_inputs(struct gl_shader_program *prog, + gl_shader *producer, gl_shader *consumer) +{ + glsl_symbol_table parameters; + /* FINISHME: Figure these out dynamically. */ + const char *const producer_stage = "vertex"; + const char *const consumer_stage = "fragment"; + + /* Find all shader outputs in the "producer" stage. + */ + foreach_list(node, producer->ir) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + + /* FINISHME: For geometry shaders, this should also look for inout + * FINISHME: variables. + */ + if ((var == NULL) || (var->mode != ir_var_out)) + continue; + + parameters.add_variable(var->name, var); + } + + + /* Find all shader inputs in the "consumer" stage. Any variables that have + * matching outputs already in the symbol table must have the same type and + * qualifiers. + */ + foreach_list(node, consumer->ir) { + ir_variable *const input = ((ir_instruction *) node)->as_variable(); + + /* FINISHME: For geometry shaders, this should also look for inout + * FINISHME: variables. + */ + if ((input == NULL) || (input->mode != ir_var_in)) + continue; + + ir_variable *const output = parameters.get_variable(input->name); + if (output != NULL) { + /* Check that the types match between stages. + */ + if (input->type != output->type) { + linker_error_printf(prog, + "%s shader output `%s' delcared as " + "type `%s', but %s shader input declared " + "as type `%s'\n", + producer_stage, output->name, + output->type->name, + consumer_stage, input->type->name); + return false; + } + + /* Check that all of the qualifiers match between stages. + */ + if (input->centroid != output->centroid) { + linker_error_printf(prog, + "%s shader output `%s' %s centroid qualifier, " + "but %s shader input %s centroid qualifier\n", + producer_stage, + output->name, + (output->centroid) ? "has" : "lacks", + consumer_stage, + (input->centroid) ? "has" : "lacks"); + return false; + } + + if (input->invariant != output->invariant) { + linker_error_printf(prog, + "%s shader output `%s' %s invariant qualifier, " + "but %s shader input %s invariant qualifier\n", + producer_stage, + output->name, + (output->invariant) ? "has" : "lacks", + consumer_stage, + (input->invariant) ? "has" : "lacks"); + return false; + } + + if (input->interpolation != output->interpolation) { + linker_error_printf(prog, + "%s shader output `%s' specifies %s " + "interpolation qualifier, " + "but %s shader input specifies %s " + "interpolation qualifier\n", + producer_stage, + output->name, + output->interpolation_string(), + consumer_stage, + input->interpolation_string()); + return false; + } + } + } + + return true; +} + + +/** + * Populates a shaders symbol table with all global declarations + */ +static void +populate_symbol_table(gl_shader *sh) +{ + sh->symbols = new(sh) glsl_symbol_table; + + foreach_list(node, sh->ir) { + ir_instruction *const inst = (ir_instruction *) node; + ir_variable *var; + ir_function *func; + + if ((func = inst->as_function()) != NULL) { + sh->symbols->add_function(func->name, func); + } else if ((var = inst->as_variable()) != NULL) { + sh->symbols->add_variable(var->name, var); + } + } +} + + +/** + * Remap variables referenced in an instruction tree + * + * This is used when instruction trees are cloned from one shader and placed in + * another. These trees will contain references to \c ir_variable nodes that + * do not exist in the target shader. This function finds these \c ir_variable + * references and replaces the references with matching variables in the target + * shader. + * + * If there is no matching variable in the target shader, a clone of the + * \c ir_variable is made and added to the target shader. The new variable is + * added to \b both the instruction stream and the symbol table. + * + * \param inst IR tree that is to be processed. + * \param symbols Symbol table containing global scope symbols in the + * linked shader. + * \param instructions Instruction stream where new variable declarations + * should be added. + */ +void +remap_variables(ir_instruction *inst, struct gl_shader *target, + hash_table *temps) +{ + class remap_visitor : public ir_hierarchical_visitor { + public: + remap_visitor(struct gl_shader *target, + hash_table *temps) + { + this->target = target; + this->symbols = target->symbols; + this->instructions = target->ir; + this->temps = temps; + } + + virtual ir_visitor_status visit(ir_dereference_variable *ir) + { + if (ir->var->mode == ir_var_temporary) { + ir_variable *var = (ir_variable *) hash_table_find(temps, ir->var); + + assert(var != NULL); + ir->var = var; + return visit_continue; + } + + ir_variable *const existing = + this->symbols->get_variable(ir->var->name); + if (existing != NULL) + ir->var = existing; + else { + ir_variable *copy = ir->var->clone(this->target, NULL); + + this->symbols->add_variable(copy->name, copy); + this->instructions->push_head(copy); + ir->var = copy; + } + + return visit_continue; + } + + private: + struct gl_shader *target; + glsl_symbol_table *symbols; + exec_list *instructions; + hash_table *temps; + }; + + remap_visitor v(target, temps); + + inst->accept(&v); +} + + +/** + * Move non-declarations from one instruction stream to another + * + * The intended usage pattern of this function is to pass the pointer to the + * head sentinel of a list (i.e., a pointer to the list cast to an \c exec_node + * pointer) for \c last and \c false for \c make_copies on the first + * call. Successive calls pass the return value of the previous call for + * \c last and \c true for \c make_copies. + * + * \param instructions Source instruction stream + * \param last Instruction after which new instructions should be + * inserted in the target instruction stream + * \param make_copies Flag selecting whether instructions in \c instructions + * should be copied (via \c ir_instruction::clone) into the + * target list or moved. + * + * \return + * The new "last" instruction in the target instruction stream. This pointer + * is suitable for use as the \c last parameter of a later call to this + * function. + */ +exec_node * +move_non_declarations(exec_list *instructions, exec_node *last, + bool make_copies, gl_shader *target) +{ + hash_table *temps = NULL; + + if (make_copies) + temps = hash_table_ctor(0, hash_table_pointer_hash, + hash_table_pointer_compare); + + foreach_list_safe(node, instructions) { + ir_instruction *inst = (ir_instruction *) node; + + if (inst->as_function()) + continue; + + ir_variable *var = inst->as_variable(); + if ((var != NULL) && (var->mode != ir_var_temporary)) + continue; + + assert(inst->as_assignment() + || ((var != NULL) && (var->mode == ir_var_temporary))); + + if (make_copies) { + inst = inst->clone(target, NULL); + + if (var != NULL) + hash_table_insert(temps, inst, var); + else + remap_variables(inst, target, temps); + } else { + inst->remove(); + } + + last->insert_after(inst); + last = inst; + } + + if (make_copies) + hash_table_dtor(temps); + + return last; +} + +/** + * Get the function signature for main from a shader + */ +static ir_function_signature * +get_main_function_signature(gl_shader *sh) +{ + ir_function *const f = sh->symbols->get_function("main"); + if (f != NULL) { + exec_list void_parameters; + + /* Look for the 'void main()' signature and ensure that it's defined. + * This keeps the linker from accidentally pick a shader that just + * contains a prototype for main. + * + * We don't have to check for multiple definitions of main (in multiple + * shaders) because that would have already been caught above. + */ + ir_function_signature *sig = f->matching_signature(&void_parameters); + if ((sig != NULL) && sig->is_defined) { + return sig; + } + } + + return NULL; +} + + +/** + * Combine a group of shaders for a single stage to generate a linked shader + * + * \note + * If this function is supplied a single shader, it is cloned, and the new + * shader is returned. + */ +static struct gl_shader * +link_intrastage_shaders(GLcontext *ctx, + struct gl_shader_program *prog, + struct gl_shader **shader_list, + unsigned num_shaders) +{ + /* Check that global variables defined in multiple shaders are consistent. + */ + if (!cross_validate_globals(prog, shader_list, num_shaders, false)) + return NULL; + + /* Check that there is only a single definition of each function signature + * across all shaders. + */ + for (unsigned i = 0; i < (num_shaders - 1); i++) { + foreach_list(node, shader_list[i]->ir) { + ir_function *const f = ((ir_instruction *) node)->as_function(); + + if (f == NULL) + continue; + + for (unsigned j = i + 1; j < num_shaders; j++) { + ir_function *const other = + shader_list[j]->symbols->get_function(f->name); + + /* If the other shader has no function (and therefore no function + * signatures) with the same name, skip to the next shader. + */ + if (other == NULL) + continue; + + foreach_iter (exec_list_iterator, iter, *f) { + ir_function_signature *sig = + (ir_function_signature *) iter.get(); + + if (!sig->is_defined || f->is_builtin) + continue; + + ir_function_signature *other_sig = + other->exact_matching_signature(& sig->parameters); + + if ((other_sig != NULL) && other_sig->is_defined + && !other_sig->function()->is_builtin) { + linker_error_printf(prog, + "function `%s' is multiply defined", + f->name); + return NULL; + } + } + } + } + } + + /* Find the shader that defines main, and make a clone of it. + * + * Starting with the clone, search for undefined references. If one is + * found, find the shader that defines it. Clone the reference and add + * it to the shader. Repeat until there are no undefined references or + * until a reference cannot be resolved. + */ + gl_shader *main = NULL; + for (unsigned i = 0; i < num_shaders; i++) { + if (get_main_function_signature(shader_list[i]) != NULL) { + main = shader_list[i]; + break; + } + } + + if (main == NULL) { + linker_error_printf(prog, "%s shader lacks `main'\n", + (shader_list[0]->Type == GL_VERTEX_SHADER) + ? "vertex" : "fragment"); + return NULL; + } + + gl_shader *const linked = ctx->Driver.NewShader(NULL, 0, main->Type); + linked->ir = new(linked) exec_list; + clone_ir_list(linked, linked->ir, main->ir); + + populate_symbol_table(linked); + + /* The a pointer to the main function in the final linked shader (i.e., the + * copy of the original shader that contained the main function). + */ + ir_function_signature *const main_sig = get_main_function_signature(linked); + + /* Move any instructions other than variable declarations or function + * declarations into main. + */ + exec_node *insertion_point = + move_non_declarations(linked->ir, (exec_node *) &main_sig->body, false, + linked); + + for (unsigned i = 0; i < num_shaders; i++) { + if (shader_list[i] == main) + continue; + + insertion_point = move_non_declarations(shader_list[i]->ir, + insertion_point, true, linked); + } + + /* Resolve initializers for global variables in the linked shader. + */ + unsigned num_linking_shaders = num_shaders; + for (unsigned i = 0; i < num_shaders; i++) + num_linking_shaders += shader_list[i]->num_builtins_to_link; + + gl_shader **linking_shaders = + (gl_shader **) calloc(num_linking_shaders, sizeof(gl_shader *)); + + memcpy(linking_shaders, shader_list, + sizeof(linking_shaders[0]) * num_shaders); + + unsigned idx = num_shaders; + for (unsigned i = 0; i < num_shaders; i++) { + memcpy(&linking_shaders[idx], shader_list[i]->builtins_to_link, + sizeof(linking_shaders[0]) * shader_list[i]->num_builtins_to_link); + idx += shader_list[i]->num_builtins_to_link; + } + + assert(idx == num_linking_shaders); + + link_function_calls(prog, linked, linking_shaders, num_linking_shaders); + + free(linking_shaders); + + return linked; +} + + +struct uniform_node { + exec_node link; + struct gl_uniform *u; + unsigned slots; +}; + +/** + * Update the sizes of linked shader uniform arrays to the maximum + * array index used. + * + * From page 81 (page 95 of the PDF) of the OpenGL 2.1 spec: + * + * If one or more elements of an array are active, + * GetActiveUniform will return the name of the array in name, + * subject to the restrictions listed above. The type of the array + * is returned in type. The size parameter contains the highest + * array element index used, plus one. The compiler or linker + * determines the highest index used. There will be only one + * active uniform reported by the GL per uniform array. + + */ +static void +update_uniform_array_sizes(struct gl_shader_program *prog) +{ + for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { + foreach_list(node, prog->_LinkedShaders[i]->ir) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + + if ((var == NULL) || (var->mode != ir_var_uniform) || + !var->type->is_array()) + continue; + + unsigned int size = var->max_array_access; + for (unsigned j = 0; j < prog->_NumLinkedShaders; j++) { + foreach_list(node2, prog->_LinkedShaders[j]->ir) { + ir_variable *other_var = ((ir_instruction *) node2)->as_variable(); + if (!other_var) + continue; + + if (strcmp(var->name, other_var->name) == 0 && + other_var->max_array_access > size) { + size = other_var->max_array_access; + } + } + } + if (size + 1 != var->type->fields.array->length) { + var->type = glsl_type::get_array_instance(var->type->fields.array, + size + 1); + /* FINISHME: We should update the types of array + * dereferences of this variable now. + */ + } + } + } +} + +static void +add_uniform(void *mem_ctx, exec_list *uniforms, struct hash_table *ht, + const char *name, const glsl_type *type, GLenum shader_type, + unsigned *next_shader_pos, unsigned *total_uniforms) +{ + if (type->is_record()) { + for (unsigned int i = 0; i < type->length; i++) { + const glsl_type *field_type = type->fields.structure[i].type; + char *field_name = talloc_asprintf(mem_ctx, "%s.%s", name, + type->fields.structure[i].name); + + add_uniform(mem_ctx, uniforms, ht, field_name, field_type, + shader_type, next_shader_pos, total_uniforms); + } + } else { + uniform_node *n = (uniform_node *) hash_table_find(ht, name); + unsigned int vec4_slots; + const glsl_type *array_elem_type = NULL; + + if (type->is_array()) { + array_elem_type = type->fields.array; + /* Array of structures. */ + if (array_elem_type->is_record()) { + for (unsigned int i = 0; i < type->length; i++) { + char *elem_name = talloc_asprintf(mem_ctx, "%s[%d]", name, i); + add_uniform(mem_ctx, uniforms, ht, elem_name, array_elem_type, + shader_type, next_shader_pos, total_uniforms); + } + return; + } + } + + /* Fix the storage size of samplers at 1 vec4 each. Be sure to pad out + * vectors to vec4 slots. + */ + if (type->is_array()) { + if (array_elem_type->is_sampler()) + vec4_slots = type->length; + else + vec4_slots = type->length * array_elem_type->matrix_columns; + } else if (type->is_sampler()) { + vec4_slots = 1; + } else { + vec4_slots = type->matrix_columns; + } + + if (n == NULL) { + n = (uniform_node *) calloc(1, sizeof(struct uniform_node)); + n->u = (gl_uniform *) calloc(1, sizeof(struct gl_uniform)); + n->slots = vec4_slots; + + n->u->Name = strdup(name); + n->u->Type = type; + n->u->VertPos = -1; + n->u->FragPos = -1; + n->u->GeomPos = -1; + (*total_uniforms)++; + + hash_table_insert(ht, n, name); + uniforms->push_tail(& n->link); + } + + switch (shader_type) { + case GL_VERTEX_SHADER: + n->u->VertPos = *next_shader_pos; + break; + case GL_FRAGMENT_SHADER: + n->u->FragPos = *next_shader_pos; + break; + case GL_GEOMETRY_SHADER: + n->u->GeomPos = *next_shader_pos; + break; + } + + (*next_shader_pos) += vec4_slots; + } +} + +void +assign_uniform_locations(struct gl_shader_program *prog) +{ + /* */ + exec_list uniforms; + unsigned total_uniforms = 0; + hash_table *ht = hash_table_ctor(32, hash_table_string_hash, + hash_table_string_compare); + void *mem_ctx = talloc_new(NULL); + + update_uniform_array_sizes(prog); + + for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { + unsigned next_position = 0; + + foreach_list(node, prog->_LinkedShaders[i]->ir) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + + if ((var == NULL) || (var->mode != ir_var_uniform)) + continue; + + if (strncmp(var->name, "gl_", 3) == 0) { + /* At the moment, we don't allocate uniform locations for + * builtin uniforms. It's permitted by spec, and we'll + * likely switch to doing that at some point, but not yet. + */ + continue; + } + + var->location = next_position; + add_uniform(mem_ctx, &uniforms, ht, var->name, var->type, + prog->_LinkedShaders[i]->Type, + &next_position, &total_uniforms); + } + } + + talloc_free(mem_ctx); + + gl_uniform_list *ul = (gl_uniform_list *) + calloc(1, sizeof(gl_uniform_list)); + + ul->Size = total_uniforms; + ul->NumUniforms = total_uniforms; + ul->Uniforms = (gl_uniform *) calloc(total_uniforms, sizeof(gl_uniform)); + + unsigned idx = 0; + uniform_node *next; + for (uniform_node *node = (uniform_node *) uniforms.head + ; node->link.next != NULL + ; node = next) { + next = (uniform_node *) node->link.next; + + node->link.remove(); + memcpy(&ul->Uniforms[idx], node->u, sizeof(gl_uniform)); + idx++; + + free(node->u); + free(node); + } + + hash_table_dtor(ht); + + prog->Uniforms = ul; +} + + +/** + * Find a contiguous set of available bits in a bitmask + * + * \param used_mask Bits representing used (1) and unused (0) locations + * \param needed_count Number of contiguous bits needed. + * + * \return + * Base location of the available bits on success or -1 on failure. + */ +int +find_available_slots(unsigned used_mask, unsigned needed_count) +{ + unsigned needed_mask = (1 << needed_count) - 1; + const int max_bit_to_test = (8 * sizeof(used_mask)) - needed_count; + + /* The comparison to 32 is redundant, but without it GCC emits "warning: + * cannot optimize possibly infinite loops" for the loop below. + */ + if ((needed_count == 0) || (max_bit_to_test < 0) || (max_bit_to_test > 32)) + return -1; + + for (int i = 0; i <= max_bit_to_test; i++) { + if ((needed_mask & ~used_mask) == needed_mask) + return i; + + needed_mask <<= 1; + } + + return -1; +} + + +bool +assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index) +{ + /* Mark invalid attribute locations as being used. + */ + unsigned used_locations = (max_attribute_index >= 32) + ? ~0 : ~((1 << max_attribute_index) - 1); + + gl_shader *const sh = prog->_LinkedShaders[0]; + assert(sh->Type == GL_VERTEX_SHADER); + + /* Operate in a total of four passes. + * + * 1. Invalidate the location assignments for all vertex shader inputs. + * + * 2. Assign locations for inputs that have user-defined (via + * glBindVertexAttribLocation) locatoins. + * + * 3. Sort the attributes without assigned locations by number of slots + * required in decreasing order. Fragmentation caused by attribute + * locations assigned by the application may prevent large attributes + * from having enough contiguous space. + * + * 4. Assign locations to any inputs without assigned locations. + */ + + invalidate_variable_locations(sh, ir_var_in, VERT_ATTRIB_GENERIC0); + + if (prog->Attributes != NULL) { + for (unsigned i = 0; i < prog->Attributes->NumParameters; i++) { + ir_variable *const var = + sh->symbols->get_variable(prog->Attributes->Parameters[i].Name); + + /* Note: attributes that occupy multiple slots, such as arrays or + * matrices, may appear in the attrib array multiple times. + */ + if ((var == NULL) || (var->location != -1)) + continue; + + /* From page 61 of the OpenGL 4.0 spec: + * + * "LinkProgram will fail if the attribute bindings assigned by + * BindAttribLocation do not leave not enough space to assign a + * location for an active matrix attribute or an active attribute + * array, both of which require multiple contiguous generic + * attributes." + * + * Previous versions of the spec contain similar language but omit the + * bit about attribute arrays. + * + * Page 61 of the OpenGL 4.0 spec also says: + * + * "It is possible for an application to bind more than one + * attribute name to the same location. This is referred to as + * aliasing. This will only work if only one of the aliased + * attributes is active in the executable program, or if no path + * through the shader consumes more than one attribute of a set + * of attributes aliased to the same location. A link error can + * occur if the linker determines that every path through the + * shader consumes multiple aliased attributes, but + * implementations are not required to generate an error in this + * case." + * + * These two paragraphs are either somewhat contradictory, or I don't + * fully understand one or both of them. + */ + /* FINISHME: The code as currently written does not support attribute + * FINISHME: location aliasing (see comment above). + */ + const int attr = prog->Attributes->Parameters[i].StateIndexes[0]; + const unsigned slots = count_attribute_slots(var->type); + + /* Mask representing the contiguous slots that will be used by this + * attribute. + */ + const unsigned use_mask = (1 << slots) - 1; + + /* Generate a link error if the set of bits requested for this + * attribute overlaps any previously allocated bits. + */ + if ((~(use_mask << attr) & used_locations) != used_locations) { + linker_error_printf(prog, + "insufficient contiguous attribute locations " + "available for vertex shader input `%s'", + var->name); + return false; + } + + var->location = VERT_ATTRIB_GENERIC0 + attr; + used_locations |= (use_mask << attr); + } + } + + /* Temporary storage for the set of attributes that need locations assigned. + */ + struct temp_attr { + unsigned slots; + ir_variable *var; + + /* Used below in the call to qsort. */ + static int compare(const void *a, const void *b) + { + const temp_attr *const l = (const temp_attr *) a; + const temp_attr *const r = (const temp_attr *) b; + + /* Reversed because we want a descending order sort below. */ + return r->slots - l->slots; + } + } to_assign[16]; + + unsigned num_attr = 0; + + foreach_list(node, sh->ir) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + + if ((var == NULL) || (var->mode != ir_var_in)) + continue; + + /* The location was explicitly assigned, nothing to do here. + */ + if (var->location != -1) + continue; + + to_assign[num_attr].slots = count_attribute_slots(var->type); + to_assign[num_attr].var = var; + num_attr++; + } + + /* If all of the attributes were assigned locations by the application (or + * are built-in attributes with fixed locations), return early. This should + * be the common case. + */ + if (num_attr == 0) + return true; + + qsort(to_assign, num_attr, sizeof(to_assign[0]), temp_attr::compare); + + /* VERT_ATTRIB_GENERIC0 is a psdueo-alias for VERT_ATTRIB_POS. It can only + * be explicitly assigned by via glBindAttribLocation. Mark it as reserved + * to prevent it from being automatically allocated below. + */ + find_deref_visitor find("gl_Vertex"); + find.run(sh->ir); + if (find.variable_found()) + used_locations |= (1 << 0); + + for (unsigned i = 0; i < num_attr; i++) { + /* Mask representing the contiguous slots that will be used by this + * attribute. + */ + const unsigned use_mask = (1 << to_assign[i].slots) - 1; + + int location = find_available_slots(used_locations, to_assign[i].slots); + + if (location < 0) { + linker_error_printf(prog, + "insufficient contiguous attribute locations " + "available for vertex shader input `%s'", + to_assign[i].var->name); + return false; + } + + to_assign[i].var->location = VERT_ATTRIB_GENERIC0 + location; + used_locations |= (use_mask << location); + } + + return true; +} + + +/** + * Demote shader outputs that are not read to being just plain global variables + */ +void +demote_unread_shader_outputs(gl_shader *sh) +{ + foreach_list(node, sh->ir) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + + if ((var == NULL) || (var->mode != ir_var_out)) + continue; + + /* An 'out' variable is only really a shader output if its value is read + * by the following stage. + */ + if (var->location == -1) { + var->mode = ir_var_auto; + } + } +} + + +void +assign_varying_locations(struct gl_shader_program *prog, + gl_shader *producer, gl_shader *consumer) +{ + /* FINISHME: Set dynamically when geometry shader support is added. */ + unsigned output_index = VERT_RESULT_VAR0; + unsigned input_index = FRAG_ATTRIB_VAR0; + + /* Operate in a total of three passes. + * + * 1. Assign locations for any matching inputs and outputs. + * + * 2. Mark output variables in the producer that do not have locations as + * not being outputs. This lets the optimizer eliminate them. + * + * 3. Mark input variables in the consumer that do not have locations as + * not being inputs. This lets the optimizer eliminate them. + */ + + invalidate_variable_locations(producer, ir_var_out, VERT_RESULT_VAR0); + invalidate_variable_locations(consumer, ir_var_in, FRAG_ATTRIB_VAR0); + + foreach_list(node, producer->ir) { + ir_variable *const output_var = ((ir_instruction *) node)->as_variable(); + + if ((output_var == NULL) || (output_var->mode != ir_var_out) + || (output_var->location != -1)) + continue; + + ir_variable *const input_var = + consumer->symbols->get_variable(output_var->name); + + if ((input_var == NULL) || (input_var->mode != ir_var_in)) + continue; + + assert(input_var->location == -1); + + output_var->location = output_index; + input_var->location = input_index; + + /* FINISHME: Support for "varying" records in GLSL 1.50. */ + assert(!output_var->type->is_record()); + + if (output_var->type->is_array()) { + const unsigned slots = output_var->type->length + * output_var->type->fields.array->matrix_columns; + + output_index += slots; + input_index += slots; + } else { + const unsigned slots = output_var->type->matrix_columns; + + output_index += slots; + input_index += slots; + } + } + + demote_unread_shader_outputs(producer); + + foreach_list(node, consumer->ir) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + + if ((var == NULL) || (var->mode != ir_var_in)) + continue; + + if (var->location == -1) { + if (prog->Version <= 120) { + /* On page 25 (page 31 of the PDF) of the GLSL 1.20 spec: + * + * Only those varying variables used (i.e. read) in + * the fragment shader executable must be written to + * by the vertex shader executable; declaring + * superfluous varying variables in a vertex shader is + * permissible. + * + * We interpret this text as meaning that the VS must + * write the variable for the FS to read it. See + * "glsl1-varying read but not written" in piglit. + */ + + linker_error_printf(prog, "fragment shader varying %s not written " + "by vertex shader\n.", var->name); + prog->LinkStatus = false; + } + + /* An 'in' variable is only really a shader input if its + * value is written by the previous stage. + */ + var->mode = ir_var_auto; + } + } +} + + +void +link_shaders(GLcontext *ctx, struct gl_shader_program *prog) +{ + prog->LinkStatus = false; + prog->Validated = false; + prog->_Used = false; + + if (prog->InfoLog != NULL) + talloc_free(prog->InfoLog); + + prog->InfoLog = talloc_strdup(NULL, ""); + + /* Separate the shaders into groups based on their type. + */ + struct gl_shader **vert_shader_list; + unsigned num_vert_shaders = 0; + struct gl_shader **frag_shader_list; + unsigned num_frag_shaders = 0; + + vert_shader_list = (struct gl_shader **) + calloc(2 * prog->NumShaders, sizeof(struct gl_shader *)); + frag_shader_list = &vert_shader_list[prog->NumShaders]; + + unsigned min_version = UINT_MAX; + unsigned max_version = 0; + for (unsigned i = 0; i < prog->NumShaders; i++) { + min_version = MIN2(min_version, prog->Shaders[i]->Version); + max_version = MAX2(max_version, prog->Shaders[i]->Version); + + switch (prog->Shaders[i]->Type) { + case GL_VERTEX_SHADER: + vert_shader_list[num_vert_shaders] = prog->Shaders[i]; + num_vert_shaders++; + break; + case GL_FRAGMENT_SHADER: + frag_shader_list[num_frag_shaders] = prog->Shaders[i]; + num_frag_shaders++; + break; + case GL_GEOMETRY_SHADER: + /* FINISHME: Support geometry shaders. */ + assert(prog->Shaders[i]->Type != GL_GEOMETRY_SHADER); + break; + } + } + + /* Previous to GLSL version 1.30, different compilation units could mix and + * match shading language versions. With GLSL 1.30 and later, the versions + * of all shaders must match. + */ + assert(min_version >= 110); + assert(max_version <= 130); + if ((max_version >= 130) && (min_version != max_version)) { + linker_error_printf(prog, "all shaders must use same shading " + "language version\n"); + goto done; + } + + prog->Version = max_version; + + for (unsigned int i = 0; i < prog->_NumLinkedShaders; i++) { + ctx->Driver.DeleteShader(ctx, prog->_LinkedShaders[i]); + } + + /* Link all shaders for a particular stage and validate the result. + */ + prog->_NumLinkedShaders = 0; + if (num_vert_shaders > 0) { + gl_shader *const sh = + link_intrastage_shaders(ctx, prog, vert_shader_list, num_vert_shaders); + + if (sh == NULL) + goto done; + + if (!validate_vertex_shader_executable(prog, sh)) + goto done; + + prog->_LinkedShaders[prog->_NumLinkedShaders] = sh; + prog->_NumLinkedShaders++; + } + + if (num_frag_shaders > 0) { + gl_shader *const sh = + link_intrastage_shaders(ctx, prog, frag_shader_list, num_frag_shaders); + + if (sh == NULL) + goto done; + + if (!validate_fragment_shader_executable(prog, sh)) + goto done; + + prog->_LinkedShaders[prog->_NumLinkedShaders] = sh; + prog->_NumLinkedShaders++; + } + + /* Here begins the inter-stage linking phase. Some initial validation is + * performed, then locations are assigned for uniforms, attributes, and + * varyings. + */ + if (cross_validate_uniforms(prog)) { + /* Validate the inputs of each stage with the output of the preceeding + * stage. + */ + for (unsigned i = 1; i < prog->_NumLinkedShaders; i++) { + if (!cross_validate_outputs_to_inputs(prog, + prog->_LinkedShaders[i - 1], + prog->_LinkedShaders[i])) + goto done; + } + + prog->LinkStatus = true; + } + + /* Do common optimization before assigning storage for attributes, + * uniforms, and varyings. Later optimization could possibly make + * some of that unused. + */ + for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { + while (do_common_optimization(prog->_LinkedShaders[i]->ir, true)) + ; + } + + assign_uniform_locations(prog); + + if (prog->_LinkedShaders[0]->Type == GL_VERTEX_SHADER) { + /* FINISHME: The value of the max_attribute_index parameter is + * FINISHME: implementation dependent based on the value of + * FINISHME: GL_MAX_VERTEX_ATTRIBS. GL_MAX_VERTEX_ATTRIBS must be + * FINISHME: at least 16, so hardcode 16 for now. + */ + if (!assign_attribute_locations(prog, 16)) + goto done; + + if (prog->_NumLinkedShaders == 1) + demote_unread_shader_outputs(prog->_LinkedShaders[0]); + } + + for (unsigned i = 1; i < prog->_NumLinkedShaders; i++) + assign_varying_locations(prog, + prog->_LinkedShaders[i - 1], + prog->_LinkedShaders[i]); + + /* FINISHME: Assign fragment shader output locations. */ + +done: + free(vert_shader_list); +} diff --git a/src/glsl/linker.h b/src/glsl/linker.h new file mode 100644 index 0000000000..a8ce16a7ec --- /dev/null +++ b/src/glsl/linker.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef GLSL_LINKER_H +#define GLSL_LINKER_H + +extern void +linker_error_printf(gl_shader_program *prog, const char *fmt, ...); + +extern bool +link_function_calls(gl_shader_program *prog, gl_shader *main, + gl_shader **shader_list, unsigned num_shaders); + +#endif /* GLSL_LINKER_H */ diff --git a/src/glsl/list.h b/src/glsl/list.h new file mode 100644 index 0000000000..a70b79d571 --- /dev/null +++ b/src/glsl/list.h @@ -0,0 +1,465 @@ +/* + * Copyright © 2008, 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file list.h + * \brief Doubly-linked list abstract container type. + * + * Each doubly-linked list has a sentinel head and tail node. These nodes + * contain no data. The head sentinel can be identified by its \c prev + * pointer being \c NULL. The tail sentinel can be identified by its + * \c next pointer being \c NULL. + * + * A list is empty if either the head sentinel's \c next pointer points to the + * tail sentinel or the tail sentinel's \c prev poiner points to the head + * sentinel. + * + * Instead of tracking two separate \c node structures and a \c list structure + * that points to them, the sentinel nodes are in a single structure. Noting + * that each sentinel node always has one \c NULL pointer, the \c NULL + * pointers occupy the same memory location. In the \c list structure + * contains a the following: + * + * - A \c head pointer that represents the \c next pointer of the + * head sentinel node. + * - A \c tail pointer that represents the \c prev pointer of the head + * sentinel node and the \c next pointer of the tail sentinel node. This + * pointer is \b always \c NULL. + * - A \c tail_prev pointer that represents the \c prev pointer of the + * tail sentinel node. + * + * Therefore, if \c head->next is \c NULL or \c tail_prev->prev is \c NULL, + * the list is empty. + * + * To anyone familiar with "exec lists" on the Amiga, this structure should + * be immediately recognizable. See the following link for the original Amiga + * operating system documentation on the subject. + * + * http://www.natami.net/dev/Libraries_Manual_guide/node02D7.html + * + * \author Ian Romanick <ian.d.romanick@intel.com> + */ + +#pragma once +#ifndef LIST_CONTAINER_H +#define LIST_CONTAINER_H + +#ifndef __cplusplus +#include <stddef.h> +#include <talloc.h> +#else +extern "C" { +#include <talloc.h> +} +#endif + +#include <assert.h> + +struct exec_node { + struct exec_node *next; + struct exec_node *prev; + +#ifdef __cplusplus + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *node; + + node = talloc_size(ctx, size); + assert(node != NULL); + + return node; + } + + /* If the user *does* call delete, that's OK, we will just + * talloc_free in that case. */ + static void operator delete(void *node) + { + talloc_free(node); + } + + exec_node() : next(NULL), prev(NULL) + { + /* empty */ + } + + const exec_node *get_next() const + { + return next; + } + + exec_node *get_next() + { + return next; + } + + const exec_node *get_prev() const + { + return prev; + } + + exec_node *get_prev() + { + return prev; + } + + void remove() + { + next->prev = prev; + prev->next = next; + next = NULL; + prev = NULL; + } + + /** + * Link a node with itself + * + * This creates a sort of degenerate list that is occasionally useful. + */ + void self_link() + { + next = this; + prev = this; + } + + /** + * Insert a node in the list after the current node + */ + void insert_after(exec_node *after) + { + after->next = this->next; + after->prev = this; + + this->next->prev = after; + this->next = after; + } + /** + * Insert a node in the list before the current node + */ + void insert_before(exec_node *before) + { + before->next = this; + before->prev = this->prev; + + this->prev->next = before; + this->prev = before; + } + /** + * Replace the current node with the given node. + */ + void replace_with(exec_node *replacement) + { + replacement->prev = this->prev; + replacement->next = this->next; + + this->prev->next = replacement; + this->next->prev = replacement; + } + + /** + * Is this the sentinel at the tail of the list? + */ + bool is_tail_sentinel() const + { + return this->next == NULL; + } + + /** + * Is this the sentinel at the head of the list? + */ + bool is_head_sentinel() const + { + return this->prev == NULL; + } +#endif +}; + + +#ifdef __cplusplus +/* This macro will not work correctly if `t' uses virtual inheritance. If you + * are using virtual inheritance, you deserve a slow and painful death. Enjoy! + */ +#define exec_list_offsetof(t, f, p) \ + (((char *) &((t *) p)->f) - ((char *) p)) +#else +#define exec_list_offsetof(t, f, p) offsetof(t, f) +#endif + +/** + * Get a pointer to the structure containing an exec_node + * + * Given a pointer to an \c exec_node embedded in a structure, get a pointer to + * the containing structure. + * + * \param type Base type of the structure containing the node + * \param node Pointer to the \c exec_node + * \param field Name of the field in \c type that is the embedded \c exec_node + */ +#define exec_node_data(type, node, field) \ + ((type *) (((char *) node) - exec_list_offsetof(type, field, node))) + +#ifdef __cplusplus +struct exec_node; + +class iterator { +public: + void next() + { + } + + void *get() + { + return NULL; + } + + bool has_next() const + { + return false; + } +}; + +class exec_list_iterator : public iterator { +public: + exec_list_iterator(exec_node *n) : node(n), _next(n->next) + { + /* empty */ + } + + void next() + { + node = _next; + _next = node->next; + } + + void remove() + { + node->remove(); + } + + exec_node *get() + { + return node; + } + + bool has_next() const + { + return _next != NULL; + } + +private: + exec_node *node; + exec_node *_next; +}; + +#define foreach_iter(iter_type, iter, container) \ + for (iter_type iter = (container) . iterator(); iter.has_next(); iter.next()) +#endif + + +struct exec_list { + struct exec_node *head; + struct exec_node *tail; + struct exec_node *tail_pred; + +#ifdef __cplusplus + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *node; + + node = talloc_size(ctx, size); + assert(node != NULL); + + return node; + } + + /* If the user *does* call delete, that's OK, we will just + * talloc_free in that case. */ + static void operator delete(void *node) + { + talloc_free(node); + } + + exec_list() + { + make_empty(); + } + + void make_empty() + { + head = (exec_node *) & tail; + tail = NULL; + tail_pred = (exec_node *) & head; + } + + bool is_empty() const + { + /* There are three ways to test whether a list is empty or not. + * + * - Check to see if the \c head points to the \c tail. + * - Check to see if the \c tail_pred points to the \c head. + * - Check to see if the \c head is the sentinel node by test whether its + * \c next pointer is \c NULL. + * + * The first two methods tend to generate better code on modern systems + * because they save a pointer dereference. + */ + return head == (exec_node *) &tail; + } + + const exec_node *get_head() const + { + return !is_empty() ? head : NULL; + } + + exec_node *get_head() + { + return !is_empty() ? head : NULL; + } + + const exec_node *get_tail() const + { + return !is_empty() ? tail_pred : NULL; + } + + exec_node *get_tail() + { + return !is_empty() ? tail_pred : NULL; + } + + void push_head(exec_node *n) + { + n->next = head; + n->prev = (exec_node *) &head; + + n->next->prev = n; + head = n; + } + + void push_tail(exec_node *n) + { + n->next = (exec_node *) &tail; + n->prev = tail_pred; + + n->prev->next = n; + tail_pred = n; + } + + void push_degenerate_list_at_head(exec_node *n) + { + assert(n->prev->next == n); + + n->prev->next = head; + head->prev = n->prev; + n->prev = (exec_node *) &head; + head = n; + } + + /** + * Move all of the nodes from this list to the target list + */ + void move_nodes_to(exec_list *target) + { + if (is_empty()) { + target->make_empty(); + } else { + target->head = head; + target->tail = NULL; + target->tail_pred = tail_pred; + + target->head->prev = (exec_node *) &target->head; + target->tail_pred->next = (exec_node *) &target->tail; + + make_empty(); + } + } + + /** + * Append all nodes from the source list to the target list + */ + void + append_list(exec_list *source) + { + if (source->is_empty()) + return; + + /* Link the first node of the source with the last node of the target list. + */ + this->tail_pred->next = source->head; + source->head->prev = this->tail_pred; + + /* Make the tail of the source list be the tail of the target list. + */ + this->tail_pred = source->tail_pred; + this->tail_pred->next = (exec_node *) &this->tail; + + /* Make the source list empty for good measure. + */ + source->make_empty(); + } + + exec_list_iterator iterator() + { + return exec_list_iterator(head); + } + + exec_list_iterator iterator() const + { + return exec_list_iterator((exec_node *) head); + } +#endif +}; + +/** + * This version is safe even if the current node is removed. + */ +#define foreach_list_safe(__node, __list) \ + for (exec_node * __node = (__list)->head, * __next = __node->next \ + ; __next != NULL \ + ; __node = __next, __next = __next->next) + +#define foreach_list(__node, __list) \ + for (exec_node * __node = (__list)->head \ + ; (__node)->next != NULL \ + ; (__node) = (__node)->next) + +#define foreach_list_const(__node, __list) \ + for (const exec_node * __node = (__list)->head \ + ; (__node)->next != NULL \ + ; (__node) = (__node)->next) + +#define foreach_list_typed(__type, __node, __field, __list) \ + for (__type * __node = \ + exec_node_data(__type, (__list)->head, __field); \ + (__node)->__field.next != NULL; \ + (__node) = exec_node_data(__type, (__node)->__field.next, __field)) + +#define foreach_list_typed_const(__type, __node, __field, __list) \ + for (const __type * __node = \ + exec_node_data(__type, (__list)->head, __field); \ + (__node)->__field.next != NULL; \ + (__node) = exec_node_data(__type, (__node)->__field.next, __field)) + +#endif /* LIST_CONTAINER_H */ diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp new file mode 100644 index 0000000000..cb9f8a5277 --- /dev/null +++ b/src/glsl/main.cpp @@ -0,0 +1,287 @@ +/* + * Copyright © 2008, 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <cstdlib> +#include <cstdio> +#include <getopt.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "ast.h" +#include "glsl_parser_extras.h" +#include "glsl_parser.h" +#include "ir_optimization.h" +#include "ir_print_visitor.h" +#include "program.h" + +extern "C" struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type); + +/* Copied from shader_api.c for the stand-alone compiler. + */ +struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) +{ + struct gl_shader *shader; + + (void) ctx; + + assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER); + shader = talloc_zero(NULL, struct gl_shader); + if (shader) { + shader->Type = type; + shader->Name = name; + shader->RefCount = 1; + } + return shader; +} + +/* Returned string will have 'ctx' as its talloc owner. */ +static char * +load_text_file(void *ctx, const char *file_name) +{ + char *text = NULL; + struct stat st; + ssize_t total_read = 0; + int fd = open(file_name, O_RDONLY); + + if (fd < 0) { + return NULL; + } + + if (fstat(fd, & st) == 0) { + text = (char *) talloc_size(ctx, st.st_size + 1); + if (text != NULL) { + do { + ssize_t bytes = read(fd, text + total_read, + st.st_size - total_read); + if (bytes < 0) { + free(text); + text = NULL; + break; + } + + if (bytes == 0) { + break; + } + + total_read += bytes; + } while (total_read < st.st_size); + + text[total_read] = '\0'; + } + } + + close(fd); + + return text; +} + + +void +usage_fail(const char *name) +{ + printf("%s <filename.frag|filename.vert>\n", name); + exit(EXIT_FAILURE); +} + + +int dump_ast = 0; +int dump_hir = 0; +int dump_lir = 0; +int do_link = 0; + +const struct option compiler_opts[] = { + { "dump-ast", 0, &dump_ast, 1 }, + { "dump-hir", 0, &dump_hir, 1 }, + { "dump-lir", 0, &dump_lir, 1 }, + { "link", 0, &do_link, 1 }, + { NULL, 0, NULL, 0 } +}; + +void +compile_shader(struct gl_shader *shader) +{ + struct _mesa_glsl_parse_state *state = + new(shader) _mesa_glsl_parse_state(NULL, shader->Type, shader); + + const char *source = shader->Source; + state->error = preprocess(state, &source, &state->info_log, + state->extensions); + + if (!state->error) { + _mesa_glsl_lexer_ctor(state, source); + _mesa_glsl_parse(state); + _mesa_glsl_lexer_dtor(state); + } + + if (dump_ast) { + foreach_list_const(n, &state->translation_unit) { + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + } + printf("\n\n"); + } + + shader->ir = new(shader) exec_list; + if (!state->error && !state->translation_unit.is_empty()) + _mesa_ast_to_hir(shader->ir, state); + + /* Print out the unoptimized IR. */ + if (!state->error && dump_hir) { + validate_ir_tree(shader->ir); + _mesa_print_ir(shader->ir, state); + } + + /* Optimization passes */ + if (!state->error && !shader->ir->is_empty()) { + bool progress; + do { + progress = false; + + progress = do_function_inlining(shader->ir) || progress; + progress = do_if_simplification(shader->ir) || progress; + progress = do_copy_propagation(shader->ir) || progress; + progress = do_dead_code_local(shader->ir) || progress; + progress = do_dead_code_unlinked(shader->ir) || progress; + progress = do_tree_grafting(shader->ir) || progress; + progress = do_constant_propagation(shader->ir) || progress; + progress = do_constant_variable_unlinked(shader->ir) || progress; + progress = do_constant_folding(shader->ir) || progress; + progress = do_algebraic(shader->ir) || progress; + progress = do_vec_index_to_swizzle(shader->ir) || progress; + progress = do_vec_index_to_cond_assign(shader->ir) || progress; + progress = do_swizzle_swizzle(shader->ir) || progress; + } while (progress); + + validate_ir_tree(shader->ir); + } + + + /* Print out the resulting IR */ + if (!state->error && dump_lir) { + _mesa_print_ir(shader->ir, state); + } + + shader->symbols = state->symbols; + shader->CompileStatus = !state->error; + shader->Version = state->language_version; + memcpy(shader->builtins_to_link, state->builtins_to_link, + sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link); + shader->num_builtins_to_link = state->num_builtins_to_link; + + if (shader->InfoLog) + talloc_free(shader->InfoLog); + + shader->InfoLog = state->info_log; + + /* Retain any live IR, but trash the rest. */ + reparent_ir(shader->ir, shader); + + talloc_free(state); + + return; +} + +int +main(int argc, char **argv) +{ + int status = EXIT_SUCCESS; + GLcontext local_ctx; + GLcontext *ctx = &local_ctx; + + ctx->Driver.NewShader = _mesa_new_shader; + + int c; + int idx = 0; + while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1) + /* empty */ ; + + + if (argc <= optind) + usage_fail(argv[0]); + + struct gl_shader_program *whole_program; + + whole_program = talloc_zero (NULL, struct gl_shader_program); + assert(whole_program != NULL); + + for (/* empty */; argc > optind; optind++) { + whole_program->Shaders = (struct gl_shader **) + talloc_realloc(whole_program, whole_program->Shaders, + struct gl_shader *, whole_program->NumShaders + 1); + assert(whole_program->Shaders != NULL); + + struct gl_shader *shader = talloc_zero(whole_program, gl_shader); + + whole_program->Shaders[whole_program->NumShaders] = shader; + whole_program->NumShaders++; + + const unsigned len = strlen(argv[optind]); + if (len < 6) + usage_fail(argv[0]); + + const char *const ext = & argv[optind][len - 5]; + if (strncmp(".vert", ext, 5) == 0) + shader->Type = GL_VERTEX_SHADER; + else if (strncmp(".geom", ext, 5) == 0) + shader->Type = GL_GEOMETRY_SHADER; + else if (strncmp(".frag", ext, 5) == 0) + shader->Type = GL_FRAGMENT_SHADER; + else + usage_fail(argv[0]); + + shader->Source = load_text_file(whole_program, argv[optind]); + if (shader->Source == NULL) { + printf("File \"%s\" does not exist.\n", argv[optind]); + exit(EXIT_FAILURE); + } + + compile_shader(shader); + + if (!shader->CompileStatus) { + printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog); + status = EXIT_FAILURE; + break; + } + } + + if ((status == EXIT_SUCCESS) && do_link) { + link_shaders(ctx, whole_program); + status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE; + + if (strlen(whole_program->InfoLog) > 0) + printf("Info log for linking:\n%s\n", whole_program->InfoLog); + } + + for (unsigned i = 0; i < whole_program->_NumLinkedShaders; i++) + talloc_free(whole_program->_LinkedShaders[i]); + + talloc_free(whole_program); + _mesa_glsl_release_types(); + _mesa_glsl_release_functions(); + + return status; +} diff --git a/src/glsl/pp/Makefile b/src/glsl/pp/Makefile deleted file mode 100644 index fda1c4202b..0000000000 --- a/src/glsl/pp/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -#src/glsl/pp/Makefile - -TOP = ../../.. - -include $(TOP)/configs/current - -LIBNAME = glslpp - -C_SOURCES = \ - sl_pp_context.c \ - sl_pp_define.c \ - sl_pp_dict.c \ - sl_pp_error.c \ - sl_pp_expression.c \ - sl_pp_extension.c \ - sl_pp_if.c \ - sl_pp_line.c \ - sl_pp_macro.c \ - sl_pp_pragma.c \ - sl_pp_process.c \ - sl_pp_purify.c \ - sl_pp_token.c \ - sl_pp_token_util.c \ - sl_pp_version.c - -include ../Makefile.template - diff --git a/src/glsl/pp/sl_pp_context.c b/src/glsl/pp/sl_pp_context.c deleted file mode 100644 index b8e1e99fc8..0000000000 --- a/src/glsl/pp/sl_pp_context.c +++ /dev/null @@ -1,183 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <string.h> -#include "sl_pp_macro.h" -#include "sl_pp_public.h" -#include "sl_pp_context.h" - - -struct sl_pp_context * -sl_pp_context_create(const char *input, - const struct sl_pp_purify_options *options) -{ - struct sl_pp_context *context; - - context = calloc(1, sizeof(struct sl_pp_context)); - if (!context) { - return NULL; - } - - if (sl_pp_dict_init(context)) { - sl_pp_context_destroy(context); - return NULL; - } - - context->getc_buf_capacity = 64; - context->getc_buf = malloc(context->getc_buf_capacity * sizeof(char)); - if (!context->getc_buf) { - sl_pp_context_destroy(context); - return NULL; - } - - if (sl_pp_token_buffer_init(&context->tokens, context)) { - sl_pp_context_destroy(context); - return NULL; - } - - context->macro_tail = &context->macro; - context->if_ptr = SL_PP_MAX_IF_NESTING; - context->if_value = 1; - memset(context->error_msg, 0, sizeof(context->error_msg)); - context->error_line = 1; - context->line = 1; - context->file = 0; - - sl_pp_purify_state_init(&context->pure, input, options); - - memset(&context->process_state, 0, sizeof(context->process_state)); - - return context; -} - -void -sl_pp_context_destroy(struct sl_pp_context *context) -{ - if (context) { - free(context->cstr_pool); - sl_pp_macro_free(context->macro); - free(context->getc_buf); - sl_pp_token_buffer_destroy(&context->tokens); - free(context->process_state.out); - free(context); - } -} - -const char * -sl_pp_context_error_message(const struct sl_pp_context *context) -{ - return context->error_msg; -} - -void -sl_pp_context_error_position(const struct sl_pp_context *context, - unsigned int *file, - unsigned int *line) -{ - if (file) { - *file = 0; - } - if (line) { - *line = context->error_line; - } -} - -int -sl_pp_context_add_predefined(struct sl_pp_context *context, - const char *name, - const char *value) -{ - struct sl_pp_predefined pre; - - if (context->num_predefined == SL_PP_MAX_PREDEFINED) { - return -1; - } - - pre.name = sl_pp_context_add_unique_str(context, name); - if (pre.name == -1) { - return -1; - } - - pre.value = sl_pp_context_add_unique_str(context, value); - if (pre.value == -1) { - return -1; - } - - context->predefined[context->num_predefined++] = pre; - return 0; -} - -int -sl_pp_context_add_unique_str(struct sl_pp_context *context, - const char *str) -{ - unsigned int size; - unsigned int offset = 0; - - size = strlen(str) + 1; - - /* Find out if this is a unique string. */ - while (offset < context->cstr_pool_len) { - const char *str2; - unsigned int size2; - - str2 = &context->cstr_pool[offset]; - size2 = strlen(str2) + 1; - if (size == size2 && !memcmp(str, str2, size - 1)) { - return offset; - } - - offset += size2; - } - - if (context->cstr_pool_len + size > context->cstr_pool_max) { - context->cstr_pool_max = (context->cstr_pool_len + size + 0xffff) & ~0xffff; - context->cstr_pool = realloc(context->cstr_pool, context->cstr_pool_max); - } - - if (!context->cstr_pool) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - - offset = context->cstr_pool_len; - memcpy(&context->cstr_pool[offset], str, size); - context->cstr_pool_len += size; - - return offset; -} - -const char * -sl_pp_context_cstr(const struct sl_pp_context *context, - int offset) -{ - if (offset == -1) { - return NULL; - } - return &context->cstr_pool[offset]; -} diff --git a/src/glsl/pp/sl_pp_context.h b/src/glsl/pp/sl_pp_context.h deleted file mode 100644 index e6244f6257..0000000000 --- a/src/glsl/pp/sl_pp_context.h +++ /dev/null @@ -1,99 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#ifndef SL_PP_CONTEXT_H -#define SL_PP_CONTEXT_H - -#include "sl_pp_dict.h" -#include "sl_pp_process.h" -#include "sl_pp_purify.h" -#include "sl_pp_token_util.h" - - -#define SL_PP_MAX_IF_NESTING 64 - -#define SL_PP_MAX_ERROR_MSG 1024 - -#define SL_PP_MAX_EXTENSIONS 16 - -#define SL_PP_MAX_PREDEFINED 16 - -struct sl_pp_extension { - int name; /*< GL_VENDOR_extension_name */ -}; - -struct sl_pp_predefined { - int name; - int value; -}; - -union sl_pp_if_state { - struct { - unsigned int condition:1; - unsigned int went_thru_else:1; - unsigned int had_true_cond:1; - } u; - unsigned int value; -}; - -struct sl_pp_context { - char *cstr_pool; - unsigned int cstr_pool_max; - unsigned int cstr_pool_len; - struct sl_pp_dict dict; - - struct sl_pp_macro *macro; - struct sl_pp_macro **macro_tail; - - struct sl_pp_extension extensions[SL_PP_MAX_EXTENSIONS]; - unsigned int num_extensions; - - struct sl_pp_predefined predefined[SL_PP_MAX_PREDEFINED]; - unsigned int num_predefined; - - union sl_pp_if_state if_stack[SL_PP_MAX_IF_NESTING]; - unsigned int if_ptr; - unsigned int if_value; - - char error_msg[SL_PP_MAX_ERROR_MSG]; - unsigned int error_line; - - unsigned int line; - unsigned int file; - - struct sl_pp_purify_state pure; - - char *getc_buf; - unsigned int getc_buf_size; - unsigned int getc_buf_capacity; - - struct sl_pp_token_buffer tokens; - - struct sl_pp_process_state process_state; -}; - -#endif /* SL_PP_CONTEXT_H */ diff --git a/src/glsl/pp/sl_pp_define.c b/src/glsl/pp/sl_pp_define.c deleted file mode 100644 index 370e6aa660..0000000000 --- a/src/glsl/pp/sl_pp_define.c +++ /dev/null @@ -1,240 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <string.h> -#include "sl_pp_context.h" -#include "sl_pp_macro.h" -#include "sl_pp_process.h" -#include "sl_pp_public.h" -#include "sl_pp_token.h" - - -static void -skip_whitespace(const struct sl_pp_token_info *input, - unsigned int *first, - unsigned int last) -{ - while (*first < last && input[*first].token == SL_PP_WHITESPACE) { - (*first)++; - } -} - - -static int -_parse_formal_args(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int *first, - unsigned int last, - struct sl_pp_macro *macro) -{ - struct sl_pp_macro_formal_arg **arg; - - macro->num_args = 0; - - skip_whitespace(input, first, last); - if (*first < last) { - if (input[*first].token == SL_PP_RPAREN) { - (*first)++; - return 0; - } - } else { - strcpy(context->error_msg, "expected either macro formal argument or `)'"); - return -1; - } - - arg = ¯o->arg; - - for (;;) { - if (*first < last && input[*first].token != SL_PP_IDENTIFIER) { - strcpy(context->error_msg, "expected macro formal argument"); - return -1; - } - - *arg = malloc(sizeof(struct sl_pp_macro_formal_arg)); - if (!*arg) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - - (**arg).name = input[*first].data.identifier; - (*first)++; - - (**arg).next = NULL; - arg = &(**arg).next; - - macro->num_args++; - - skip_whitespace(input, first, last); - if (*first < last) { - if (input[*first].token == SL_PP_COMMA) { - (*first)++; - skip_whitespace(input, first, last); - } else if (input[*first].token == SL_PP_RPAREN) { - (*first)++; - return 0; - } else { - strcpy(context->error_msg, "expected either `,' or `)'"); - return -1; - } - } else { - strcpy(context->error_msg, "expected either `,' or `)'"); - return -1; - } - } - - /* Should not gete here. */ -} - - -int -sl_pp_process_define(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last) -{ - int macro_name = -1; - struct sl_pp_macro *macro; - unsigned int i; - unsigned int body_len; - unsigned int j; - - if (first < last && input[first].token == SL_PP_IDENTIFIER) { - macro_name = input[first].data.identifier; - first++; - } - if (macro_name == -1) { - strcpy(context->error_msg, "expected macro name"); - return -1; - } - - /* Check for reserved macro names */ - { - const char *name = sl_pp_context_cstr(context, macro_name); - - if (strstr(name, "__")) { - strcpy(context->error_msg, "macro names containing `__' are reserved"); - return 1; - } - if (name[0] == 'G' && name[1] == 'L' && name[2] == '_') { - strcpy(context->error_msg, "macro names prefixed with `GL_' are reserved"); - return 1; - } - } - - for (macro = context->macro; macro; macro = macro->next) { - if (macro->name == macro_name) { - break; - } - } - - if (!macro) { - macro = sl_pp_macro_new(); - if (!macro) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - - *context->macro_tail = macro; - context->macro_tail = ¯o->next; - } else { - sl_pp_macro_reset(macro); - } - - macro->name = macro_name; - - /* - * If there is no whitespace between macro name and left paren, a macro - * formal argument list follows. This is the only place where the presence - * of a whitespace matters and it's the only reason why we are dealing - * with whitespace at this level. - */ - if (first < last && input[first].token == SL_PP_LPAREN) { - first++; - if (_parse_formal_args(context, input, &first, last, macro)) { - return -1; - } - } - - /* Calculate body size, trim out whitespace, make room for EOF. */ - body_len = 1; - for (i = first; i < last; i++) { - if (input[i].token != SL_PP_WHITESPACE) { - body_len++; - } - } - - macro->body = malloc(sizeof(struct sl_pp_token_info) * body_len); - if (!macro->body) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - - for (j = 0, i = first; i < last; i++) { - if (input[i].token != SL_PP_WHITESPACE) { - macro->body[j++] = input[i]; - } - } - macro->body[j++].token = SL_PP_EOF; - - return 0; -} - - -int -sl_pp_process_undef(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last) -{ - int macro_name = -1; - struct sl_pp_macro **pmacro; - struct sl_pp_macro *macro; - - if (first < last && input[first].token == SL_PP_IDENTIFIER) { - macro_name = input[first].data.identifier; - } - if (macro_name == -1) { - return 0; - } - - for (pmacro = &context->macro; *pmacro; pmacro = &(**pmacro).next) { - if ((**pmacro).name == macro_name) { - break; - } - } - if (!*pmacro) { - return 0; - } - - macro = *pmacro; - *pmacro = macro->next; - macro->next = NULL; - sl_pp_macro_free(macro); - - return 0; -} diff --git a/src/glsl/pp/sl_pp_dict.c b/src/glsl/pp/sl_pp_dict.c deleted file mode 100644 index 062139e6ac..0000000000 --- a/src/glsl/pp/sl_pp_dict.c +++ /dev/null @@ -1,85 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include "sl_pp_public.h" -#include "sl_pp_context.h" -#include "sl_pp_dict.h" - - -#define ADD_NAME_STR(CTX, NAME, STR)\ - do {\ - (CTX)->dict.NAME = sl_pp_context_add_unique_str((CTX), (STR));\ - if ((CTX)->dict.NAME == -1) {\ - return -1;\ - }\ - } while (0) - -#define ADD_NAME(CTX, NAME) ADD_NAME_STR(CTX, NAME, #NAME) - - -int -sl_pp_dict_init(struct sl_pp_context *context) -{ - ADD_NAME(context, all); - - ADD_NAME(context, require); - ADD_NAME(context, enable); - ADD_NAME(context, warn); - ADD_NAME(context, disable); - - ADD_NAME(context, defined); - - ADD_NAME_STR(context, ___LINE__, "__LINE__"); - ADD_NAME_STR(context, ___FILE__, "__FILE__"); - ADD_NAME_STR(context, ___VERSION__, "__VERSION__"); - - ADD_NAME(context, optimize); - ADD_NAME(context, debug); - - ADD_NAME(context, off); - ADD_NAME(context, on); - - ADD_NAME(context, define); - ADD_NAME(context, elif); - ADD_NAME_STR(context, _else, "else"); - ADD_NAME(context, endif); - ADD_NAME(context, error); - ADD_NAME(context, extension); - ADD_NAME_STR(context, _if, "if"); - ADD_NAME(context, ifdef); - ADD_NAME(context, ifndef); - ADD_NAME(context, line); - ADD_NAME(context, pragma); - ADD_NAME(context, undef); - - ADD_NAME(context, version); - - ADD_NAME_STR(context, _0, "0"); - ADD_NAME_STR(context, _1, "1"); - - return 0; -} diff --git a/src/glsl/pp/sl_pp_error.c b/src/glsl/pp/sl_pp_error.c deleted file mode 100644 index 482b67fcaf..0000000000 --- a/src/glsl/pp/sl_pp_error.c +++ /dev/null @@ -1,271 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <string.h> -#include "sl_pp_context.h" -#include "sl_pp_process.h" -#include "sl_pp_public.h" -#include "sl_pp_token.h" - - -void -sl_pp_process_error(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last) -{ - unsigned int out_len = 0; - unsigned int i; - - for (i = first; i < last; i++) { - const char *s = NULL; - char buf[2]; - - switch (input[i].token) { - case SL_PP_WHITESPACE: - s = " "; - break; - - case SL_PP_NEWLINE: - s = "\n"; - break; - - case SL_PP_HASH: - s = "#"; - break; - - case SL_PP_COMMA: - s = ","; - break; - - case SL_PP_SEMICOLON: - s = ";"; - break; - - case SL_PP_LBRACE: - s = "{"; - break; - - case SL_PP_RBRACE: - s = "}"; - break; - - case SL_PP_LPAREN: - s = "("; - break; - - case SL_PP_RPAREN: - s = ")"; - break; - - case SL_PP_LBRACKET: - s = "["; - break; - - case SL_PP_RBRACKET: - s = "]"; - break; - - case SL_PP_DOT: - s = "."; - break; - - case SL_PP_INCREMENT: - s = "++"; - break; - - case SL_PP_ADDASSIGN: - s = "+="; - break; - - case SL_PP_PLUS: - s = "+"; - break; - - case SL_PP_DECREMENT: - s = "--"; - break; - - case SL_PP_SUBASSIGN: - s = "-="; - break; - - case SL_PP_MINUS: - s = "-"; - break; - - case SL_PP_BITNOT: - s = "~"; - break; - - case SL_PP_NOTEQUAL: - s = "!="; - break; - - case SL_PP_NOT: - s = "!"; - break; - - case SL_PP_MULASSIGN: - s = "*="; - break; - - case SL_PP_STAR: - s = "*"; - break; - - case SL_PP_DIVASSIGN: - s = "/="; - break; - - case SL_PP_SLASH: - s = "/"; - break; - - case SL_PP_MODASSIGN: - s = "%="; - break; - - case SL_PP_MODULO: - s = "%"; - break; - - case SL_PP_LSHIFTASSIGN: - s = "<<="; - break; - - case SL_PP_LSHIFT: - s = "<<"; - break; - - case SL_PP_LESSEQUAL: - s = "<="; - break; - - case SL_PP_LESS: - s = "<"; - break; - - case SL_PP_RSHIFTASSIGN: - s = ">>="; - break; - - case SL_PP_RSHIFT: - s = ">>"; - break; - - case SL_PP_GREATEREQUAL: - s = ">="; - break; - - case SL_PP_GREATER: - s = ">"; - break; - - case SL_PP_EQUAL: - s = "=="; - break; - - case SL_PP_ASSIGN: - s = "="; - break; - - case SL_PP_AND: - s = "&&"; - break; - - case SL_PP_BITANDASSIGN: - s = "&="; - break; - - case SL_PP_BITAND: - s = "&"; - break; - - case SL_PP_XOR: - s = "^^"; - break; - - case SL_PP_BITXORASSIGN: - s = "^="; - break; - - case SL_PP_BITXOR: - s = "^"; - break; - - case SL_PP_OR: - s = "||"; - break; - - case SL_PP_BITORASSIGN: - s = "|="; - break; - - case SL_PP_BITOR: - s = "|"; - break; - - case SL_PP_QUESTION: - s = "?"; - break; - - case SL_PP_COLON: - s = ":"; - break; - - case SL_PP_IDENTIFIER: - s = sl_pp_context_cstr(context, input[i].data.identifier); - break; - - case SL_PP_UINT: - s = sl_pp_context_cstr(context, input[i].data._uint); - break; - - case SL_PP_FLOAT: - s = sl_pp_context_cstr(context, input[i].data._float); - break; - - case SL_PP_OTHER: - buf[0] = input[i].data.other; - buf[1] = '\0'; - s = buf; - break; - - default: - strcpy(context->error_msg, "internal error"); - return; - } - - while (*s != '\0' && out_len < sizeof(context->error_msg) - 1) { - context->error_msg[out_len++] = *s++; - } - } - - context->error_msg[out_len] = '\0'; -} diff --git a/src/glsl/pp/sl_pp_expression.c b/src/glsl/pp/sl_pp_expression.c deleted file mode 100644 index c3f48356b0..0000000000 --- a/src/glsl/pp/sl_pp_expression.c +++ /dev/null @@ -1,413 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <string.h> -#include "sl_pp_context.h" -#include "sl_pp_expression.h" -#include "sl_pp_public.h" -#include "sl_pp_token.h" - - -struct parse_context { - struct sl_pp_context *context; - const struct sl_pp_token_info *input; -}; - -static int -_parse_or(struct parse_context *ctx, - int *result); - -static int -_parse_primary(struct parse_context *ctx, - int *result) -{ - if (ctx->input->token == SL_PP_UINT) { - *result = atoi(sl_pp_context_cstr(ctx->context, ctx->input->data._uint)); - ctx->input++; - } else { - if (ctx->input->token != SL_PP_LPAREN) { - strcpy(ctx->context->error_msg, "expected `('"); - return -1; - } - ctx->input++; - if (_parse_or(ctx, result)) { - return -1; - } - if (ctx->input->token != SL_PP_RPAREN) { - strcpy(ctx->context->error_msg, "expected `)'"); - return -1; - } - ctx->input++; - } - return 0; -} - -static int -_parse_unary(struct parse_context *ctx, - int *result) -{ - if (!_parse_primary(ctx, result)) { - return 0; - } - - switch (ctx->input->token) { - case SL_PP_PLUS: - ctx->input++; - if (_parse_unary(ctx, result)) { - return -1; - } - *result = +*result; - break; - - case SL_PP_MINUS: - ctx->input++; - if (_parse_unary(ctx, result)) { - return -1; - } - *result = -*result; - break; - - case SL_PP_NOT: - ctx->input++; - if (_parse_unary(ctx, result)) { - return -1; - } - *result = !*result; - break; - - case SL_PP_BITNOT: - ctx->input++; - if (_parse_unary(ctx, result)) { - return -1; - } - *result = ~*result; - break; - - default: - return -1; - } - - return 0; -} - -static int -_parse_multiplicative(struct parse_context *ctx, - int *result) -{ - if (_parse_unary(ctx, result)) { - return -1; - } - for (;;) { - int right; - - switch (ctx->input->token) { - case SL_PP_STAR: - ctx->input++; - if (_parse_unary(ctx, &right)) { - return -1; - } - *result = *result * right; - break; - - case SL_PP_SLASH: - ctx->input++; - if (_parse_unary(ctx, &right)) { - return -1; - } - *result = *result / right; - break; - - case SL_PP_MODULO: - ctx->input++; - if (_parse_unary(ctx, &right)) { - return -1; - } - *result = *result % right; - break; - - default: - return 0; - } - } -} - -static int -_parse_additive(struct parse_context *ctx, - int *result) -{ - if (_parse_multiplicative(ctx, result)) { - return -1; - } - for (;;) { - int right; - - switch (ctx->input->token) { - case SL_PP_PLUS: - ctx->input++; - if (_parse_multiplicative(ctx, &right)) { - return -1; - } - *result = *result + right; - break; - - case SL_PP_MINUS: - ctx->input++; - if (_parse_multiplicative(ctx, &right)) { - return -1; - } - *result = *result - right; - break; - - default: - return 0; - } - } -} - -static int -_parse_shift(struct parse_context *ctx, - int *result) -{ - if (_parse_additive(ctx, result)) { - return -1; - } - for (;;) { - int right; - - switch (ctx->input->token) { - case SL_PP_LSHIFT: - ctx->input++; - if (_parse_additive(ctx, &right)) { - return -1; - } - *result = *result << right; - break; - - case SL_PP_RSHIFT: - ctx->input++; - if (_parse_additive(ctx, &right)) { - return -1; - } - *result = *result >> right; - break; - - default: - return 0; - } - } -} - -static int -_parse_relational(struct parse_context *ctx, - int *result) -{ - if (_parse_shift(ctx, result)) { - return -1; - } - for (;;) { - int right; - - switch (ctx->input->token) { - case SL_PP_LESSEQUAL: - ctx->input++; - if (_parse_shift(ctx, &right)) { - return -1; - } - *result = *result <= right; - break; - - case SL_PP_GREATEREQUAL: - ctx->input++; - if (_parse_shift(ctx, &right)) { - return -1; - } - *result = *result >= right; - break; - - case SL_PP_LESS: - ctx->input++; - if (_parse_shift(ctx, &right)) { - return -1; - } - *result = *result < right; - break; - - case SL_PP_GREATER: - ctx->input++; - if (_parse_shift(ctx, &right)) { - return -1; - } - *result = *result > right; - break; - - default: - return 0; - } - } -} - -static int -_parse_equality(struct parse_context *ctx, - int *result) -{ - if (_parse_relational(ctx, result)) { - return -1; - } - for (;;) { - int right; - - switch (ctx->input->token) { - case SL_PP_EQUAL: - ctx->input++; - if (_parse_relational(ctx, &right)) { - return -1; - } - *result = *result == right; - break; - - case SL_PP_NOTEQUAL: - ctx->input++; - if (_parse_relational(ctx, &right)) { - return -1; - } - *result = *result != right; - break; - - default: - return 0; - } - } -} - -static int -_parse_bitand(struct parse_context *ctx, - int *result) -{ - if (_parse_equality(ctx, result)) { - return -1; - } - while (ctx->input->token == SL_PP_BITAND) { - int right; - - ctx->input++; - if (_parse_equality(ctx, &right)) { - return -1; - } - *result = *result & right; - } - return 0; -} - -static int -_parse_xor(struct parse_context *ctx, - int *result) -{ - if (_parse_bitand(ctx, result)) { - return -1; - } - while (ctx->input->token == SL_PP_XOR) { - int right; - - ctx->input++; - if (_parse_bitand(ctx, &right)) { - return -1; - } - *result = *result ^ right; - } - return 0; -} - -static int -_parse_bitor(struct parse_context *ctx, - int *result) -{ - if (_parse_xor(ctx, result)) { - return -1; - } - while (ctx->input->token == SL_PP_BITOR) { - int right; - - ctx->input++; - if (_parse_xor(ctx, &right)) { - return -1; - } - *result = *result | right; - } - return 0; -} - -static int -_parse_and(struct parse_context *ctx, - int *result) -{ - if (_parse_bitor(ctx, result)) { - return -1; - } - while (ctx->input->token == SL_PP_AND) { - int right; - - ctx->input++; - if (_parse_bitor(ctx, &right)) { - return -1; - } - *result = *result && right; - } - return 0; -} - -static int -_parse_or(struct parse_context *ctx, - int *result) -{ - if (_parse_and(ctx, result)) { - return -1; - } - while (ctx->input->token == SL_PP_OR) { - int right; - - ctx->input++; - if (_parse_and(ctx, &right)) { - return -1; - } - *result = *result || right; - } - return 0; -} - -int -sl_pp_execute_expression(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - int *result) -{ - struct parse_context ctx; - - ctx.context = context; - ctx.input = input; - - return _parse_or(&ctx, result); -} diff --git a/src/glsl/pp/sl_pp_expression.h b/src/glsl/pp/sl_pp_expression.h deleted file mode 100644 index 522263bb25..0000000000 --- a/src/glsl/pp/sl_pp_expression.h +++ /dev/null @@ -1,40 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#ifndef SL_PP_EXPRESSION_H -#define SL_PP_EXPRESSION_H - -struct sl_pp_context; -struct sl_pp_token_info; - - -int -sl_pp_execute_expression(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - int *result); - -#endif /* SL_PP_EXPRESSION_H */ diff --git a/src/glsl/pp/sl_pp_extension.c b/src/glsl/pp/sl_pp_extension.c deleted file mode 100644 index 00dbdcf22b..0000000000 --- a/src/glsl/pp/sl_pp_extension.c +++ /dev/null @@ -1,180 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include "sl_pp_context.h" -#include "sl_pp_process.h" -#include "sl_pp_public.h" -#include "sl_pp_token.h" - - -/** - * Declare an extension to the preprocessor. This tells the preprocessor - * which extensions are supported by Mesa. - * The shader still needs to have a "#extension name: behavior" line to enable - * the extension. - */ -int -sl_pp_context_add_extension(struct sl_pp_context *context, - const char *name) -{ - struct sl_pp_extension ext; - - if (context->num_extensions == SL_PP_MAX_EXTENSIONS) { - return -1; - } - - ext.name = sl_pp_context_add_unique_str(context, name); - if (ext.name == -1) { - return -1; - } - - context->extensions[context->num_extensions++] = ext; - - assert(context->num_extensions <= sizeof(context->extensions)); - - return 0; -} - - -/** - * Process a "#extension name: behavior" directive. - */ -int -sl_pp_process_extension(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last, - struct sl_pp_process_state *state) -{ - int extension_name = -1; - int behavior = -1; - struct sl_pp_token_info out; - - /* Grab the extension name. */ - if (first < last && input[first].token == SL_PP_IDENTIFIER) { - extension_name = input[first].data.identifier; - first++; - } - if (extension_name == -1) { - strcpy(context->error_msg, "expected identifier after `#extension'"); - return -1; - } - - /* Make sure the extension is supported. */ - if (extension_name == context->dict.all) { - out.data.extension = extension_name; - } else { - unsigned int i; - - out.data.extension = -1; - for (i = 0; i < context->num_extensions; i++) { - if (extension_name == context->extensions[i].name) { - out.data.extension = extension_name; - break; - } - } - } - - /* Grab the colon separating the extension name and behavior. */ - while (first < last && input[first].token == SL_PP_WHITESPACE) { - first++; - } - if (first < last && input[first].token == SL_PP_COLON) { - first++; - } else { - strcpy(context->error_msg, "expected `:' after extension name"); - return -1; - } - while (first < last && input[first].token == SL_PP_WHITESPACE) { - first++; - } - - /* Grab the behavior name. */ - if (first < last && input[first].token == SL_PP_IDENTIFIER) { - behavior = input[first].data.identifier; - first++; - } - if (behavior == -1) { - strcpy(context->error_msg, "expected identifier after `:'"); - return -1; - } - - if (behavior == context->dict.require) { - if (out.data.extension == -1) { - strcpy(context->error_msg, "the required extension is not supported"); - return -1; - } - if (out.data.extension == context->dict.all) { - strcpy(context->error_msg, "invalid behavior for `all' extension: `require'"); - return -1; - } - out.token = SL_PP_EXTENSION_REQUIRE; - } else if (behavior == context->dict.enable) { - if (out.data.extension == -1) { - /* Warning: the extension cannot be enabled. */ - return 0; - } - if (out.data.extension == context->dict.all) { - strcpy(context->error_msg, "invalid behavior for `all' extension: `enable'"); - return -1; - } - out.token = SL_PP_EXTENSION_ENABLE; - } else if (behavior == context->dict.warn) { - if (out.data.extension == -1) { - /* Warning: the extension is not supported. */ - return 0; - } - out.token = SL_PP_EXTENSION_WARN; - } else if (behavior == context->dict.disable) { - if (out.data.extension == -1) { - /* Warning: the extension is not supported. */ - return 0; - } - out.token = SL_PP_EXTENSION_DISABLE; - } else { - strcpy(context->error_msg, "unrecognised behavior name"); - return -1; - } - - /* Grab the end of line. */ - while (first < last && input[first].token == SL_PP_WHITESPACE) { - first++; - } - if (first < last) { - strcpy(context->error_msg, "expected end of line after behavior name"); - return -1; - } - - if (sl_pp_process_out(state, &out)) { - return -1; - } - - return 0; -} diff --git a/src/glsl/pp/sl_pp_if.c b/src/glsl/pp/sl_pp_if.c deleted file mode 100644 index 6b7a1590b4..0000000000 --- a/src/glsl/pp/sl_pp_if.c +++ /dev/null @@ -1,343 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <string.h> -#include "sl_pp_context.h" -#include "sl_pp_expression.h" -#include "sl_pp_macro.h" -#include "sl_pp_process.h" -#include "sl_pp_token.h" - - -static int -_macro_is_defined(struct sl_pp_context *context, - int macro_name) -{ - unsigned int i; - struct sl_pp_macro *macro; - - for (i = 0; i < context->num_extensions; i++) { - if (macro_name == context->extensions[i].name) { - return 1; - } - } - - for (macro = context->macro; macro; macro = macro->next) { - if (macro_name == macro->name) { - return 1; - } - } - - return 0; -} - -static int -_parse_defined(struct sl_pp_context *context, - struct sl_pp_token_buffer *buffer, - struct sl_pp_process_state *state) -{ - struct sl_pp_token_info input; - int parens = 0; - int defined; - struct sl_pp_token_info result; - - if (sl_pp_token_buffer_skip_white(buffer, &input)) { - return -1; - } - - if (input.token == SL_PP_LPAREN) { - if (sl_pp_token_buffer_skip_white(buffer, &input)) { - return -1; - } - parens = 1; - } - - if (input.token != SL_PP_IDENTIFIER) { - strcpy(context->error_msg, "expected an identifier"); - return -1; - } - - defined = _macro_is_defined(context, input.data.identifier); - - if (parens) { - if (sl_pp_token_buffer_skip_white(buffer, &input)) { - return -1; - } - if (input.token != SL_PP_RPAREN) { - strcpy(context->error_msg, "expected `)'"); - return -1; - } - } - - result.token = SL_PP_UINT; - result.data._uint = (defined ? context->dict._1 : context->dict._0); - - if (sl_pp_process_out(state, &result)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - - return 0; -} - -static unsigned int -_evaluate_if_stack(struct sl_pp_context *context) -{ - unsigned int i; - - for (i = context->if_ptr; i < SL_PP_MAX_IF_NESTING; i++) { - if (!context->if_stack[i].u.condition) { - return 0; - } - } - return 1; -} - -static int -_parse_if(struct sl_pp_context *context, - struct sl_pp_token_buffer *buffer) -{ - struct sl_pp_process_state state; - int found_end = 0; - struct sl_pp_token_info eof; - int result; - - if (!context->if_ptr) { - strcpy(context->error_msg, "`#if' nesting too deep"); - return -1; - } - - memset(&state, 0, sizeof(state)); - while (!found_end) { - struct sl_pp_token_info input; - - sl_pp_token_buffer_get(buffer, &input); - switch (input.token) { - case SL_PP_WHITESPACE: - break; - - case SL_PP_IDENTIFIER: - if (input.data.identifier == context->dict.defined) { - if (_parse_defined(context, buffer, &state)) { - free(state.out); - return -1; - } - } else { - sl_pp_token_buffer_unget(buffer, &input); - if (sl_pp_macro_expand(context, buffer, NULL, &state, sl_pp_macro_expand_unknown_to_0)) { - free(state.out); - return -1; - } - } - break; - - case SL_PP_NEWLINE: - case SL_PP_EOF: - found_end = 1; - break; - - default: - if (sl_pp_process_out(&state, &input)) { - strcpy(context->error_msg, "out of memory"); - free(state.out); - return -1; - } - } - } - - eof.token = SL_PP_EOF; - if (sl_pp_process_out(&state, &eof)) { - strcpy(context->error_msg, "out of memory"); - free(state.out); - return -1; - } - - if (sl_pp_execute_expression(context, state.out, &result)) { - free(state.out); - return -1; - } - - free(state.out); - - context->if_ptr--; - context->if_stack[context->if_ptr].value = 0; - context->if_stack[context->if_ptr].u.condition = result ? 1 : 0; - context->if_value = _evaluate_if_stack(context); - - return 0; -} - -static int -_parse_else(struct sl_pp_context *context) -{ - union sl_pp_if_state *state = &context->if_stack[context->if_ptr]; - - if (context->if_ptr == SL_PP_MAX_IF_NESTING) { - strcpy(context->error_msg, "no matching `#if'"); - return -1; - } - - if (state->u.went_thru_else) { - strcpy(context->error_msg, "no matching `#if'"); - return -1; - } - - /* Once we had a true condition, the subsequent #elifs should always be false. */ - state->u.had_true_cond |= state->u.condition; - - /* Update current condition value and mark that we are in the #else block. */ - state->u.condition = !(state->u.had_true_cond | state->u.condition); - state->u.went_thru_else = 1; - context->if_value = _evaluate_if_stack(context); - - return 0; -} - -int -sl_pp_process_if(struct sl_pp_context *context, - struct sl_pp_token_buffer *buffer) -{ - return _parse_if(context, buffer); -} - -int -sl_pp_process_ifdef(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last) -{ - unsigned int i; - - if (!context->if_ptr) { - strcpy(context->error_msg, "`#if' nesting too deep"); - return -1; - } - - for (i = first; i < last; i++) { - switch (input[i].token) { - case SL_PP_IDENTIFIER: - context->if_ptr--; - context->if_stack[context->if_ptr].value = 0; - context->if_stack[context->if_ptr].u.condition = _macro_is_defined(context, input[i].data.identifier); - context->if_value = _evaluate_if_stack(context); - return 0; - - case SL_PP_WHITESPACE: - break; - - default: - strcpy(context->error_msg, "expected an identifier"); - return -1; - } - } - - strcpy(context->error_msg, "expected an identifier"); - return -1; -} - -int -sl_pp_process_ifndef(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last) -{ - unsigned int i; - - if (!context->if_ptr) { - strcpy(context->error_msg, "`#if' nesting too deep"); - return -1; - } - - for (i = first; i < last; i++) { - switch (input[i].token) { - case SL_PP_IDENTIFIER: - context->if_ptr--; - context->if_stack[context->if_ptr].value = 0; - context->if_stack[context->if_ptr].u.condition = !_macro_is_defined(context, input[i].data.identifier); - context->if_value = _evaluate_if_stack(context); - return 0; - - case SL_PP_WHITESPACE: - break; - - default: - strcpy(context->error_msg, "expected an identifier"); - return -1; - } - } - - strcpy(context->error_msg, "expected an identifier"); - return -1; -} - -int -sl_pp_process_elif(struct sl_pp_context *context, - struct sl_pp_token_buffer *buffer) -{ - if (_parse_else(context)) { - return -1; - } - - if (context->if_stack[context->if_ptr].u.condition) { - context->if_ptr++; - if (_parse_if(context, buffer)) { - return -1; - } - } - - /* We are still in the #if block. */ - context->if_stack[context->if_ptr].u.went_thru_else = 0; - - return 0; -} - -int -sl_pp_process_else(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last) -{ - return _parse_else(context); -} - -int -sl_pp_process_endif(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last) -{ - if (context->if_ptr == SL_PP_MAX_IF_NESTING) { - strcpy(context->error_msg, "no matching `#if'"); - return -1; - } - - context->if_ptr++; - context->if_value = _evaluate_if_stack(context); - - return 0; -} diff --git a/src/glsl/pp/sl_pp_line.c b/src/glsl/pp/sl_pp_line.c deleted file mode 100644 index 51581c7bb5..0000000000 --- a/src/glsl/pp/sl_pp_line.c +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <string.h> -#include "sl_pp_context.h" -#include "sl_pp_macro.h" -#include "sl_pp_public.h" -#include "sl_pp_process.h" -#include "sl_pp_token.h" - - -int -sl_pp_process_line(struct sl_pp_context *context, - struct sl_pp_token_buffer *buffer, - struct sl_pp_process_state *pstate) -{ - struct sl_pp_process_state state; - int found_end = 0; - int line_number = -1; - int file_number = -1; - unsigned int line; - unsigned int file; - - memset(&state, 0, sizeof(state)); - while (!found_end) { - struct sl_pp_token_info input; - - sl_pp_token_buffer_get(buffer, &input); - switch (input.token) { - case SL_PP_WHITESPACE: - break; - - case SL_PP_IDENTIFIER: - sl_pp_token_buffer_unget(buffer, &input); - if (sl_pp_macro_expand(context, buffer, NULL, &state, sl_pp_macro_expand_normal)) { - free(state.out); - return -1; - } - break; - - case SL_PP_NEWLINE: - case SL_PP_EOF: - found_end = 1; - break; - - default: - if (sl_pp_process_out(&state, &input)) { - strcpy(context->error_msg, "out of memory"); - free(state.out); - return -1; - } - } - } - - if (state.out_len > 0 && state.out[0].token == SL_PP_UINT) { - line_number = state.out[0].data._uint; - } else { - strcpy(context->error_msg, "expected a number after `#line'"); - free(state.out); - return -1; - } - - if (state.out_len > 1) { - if (state.out[1].token == SL_PP_UINT) { - file_number = state.out[1].data._uint; - } else { - strcpy(context->error_msg, "expected a number after line number"); - free(state.out); - return -1; - } - - if (state.out_len > 2) { - strcpy(context->error_msg, "expected an end of line after file number"); - free(state.out); - return -1; - } - } - - free(state.out); - - line = atoi(sl_pp_context_cstr(context, line_number)); - if (file_number != -1) { - file = atoi(sl_pp_context_cstr(context, file_number)); - } else { - file = context->file; - } - - if (context->line != line || context->file != file) { - struct sl_pp_token_info ti; - - ti.token = SL_PP_LINE; - ti.data.line.lineno = line; - ti.data.line.fileno = file; - if (sl_pp_process_out(pstate, &ti)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - - context->line = line; - context->file = file; - } - - return 0; -} diff --git a/src/glsl/pp/sl_pp_macro.c b/src/glsl/pp/sl_pp_macro.c deleted file mode 100644 index 2cf9ea342b..0000000000 --- a/src/glsl/pp/sl_pp_macro.c +++ /dev/null @@ -1,415 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include "sl_pp_context.h" -#include "sl_pp_public.h" -#include "sl_pp_macro.h" -#include "sl_pp_process.h" -#include "sl_pp_token.h" - - -static void -_macro_init(struct sl_pp_macro *macro) -{ - macro->name = -1; - macro->num_args = -1; - macro->arg = NULL; - macro->body = NULL; -} - -struct sl_pp_macro * -sl_pp_macro_new(void) -{ - struct sl_pp_macro *macro; - - macro = calloc(1, sizeof(struct sl_pp_macro)); - if (macro) { - _macro_init(macro); - } - return macro; -} - -static void -_macro_destroy(struct sl_pp_macro *macro) -{ - struct sl_pp_macro_formal_arg *arg = macro->arg; - - while (arg) { - struct sl_pp_macro_formal_arg *next_arg = arg->next; - - free(arg); - arg = next_arg; - } - - free(macro->body); -} - -void -sl_pp_macro_free(struct sl_pp_macro *macro) -{ - while (macro) { - struct sl_pp_macro *next_macro = macro->next; - - _macro_destroy(macro); - free(macro); - macro = next_macro; - } -} - -void -sl_pp_macro_reset(struct sl_pp_macro *macro) -{ - _macro_destroy(macro); - _macro_init(macro); -} - -static int -_out_number(struct sl_pp_context *context, - struct sl_pp_process_state *state, - unsigned int number) -{ - char buf[32]; - struct sl_pp_token_info ti; - - sprintf(buf, "%u", number); - - ti.token = SL_PP_UINT; - ti.data._uint = sl_pp_context_add_unique_str(context, buf); - if (sl_pp_process_out(state, &ti)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - - return 0; -} - -int -sl_pp_macro_expand(struct sl_pp_context *context, - struct sl_pp_token_buffer *tokens, - struct sl_pp_macro *local, - struct sl_pp_process_state *state, - enum sl_pp_macro_expand_behaviour behaviour) -{ - int mute = (behaviour == sl_pp_macro_expand_mute); - struct sl_pp_token_info input; - int macro_name; - struct sl_pp_macro *macro = NULL; - struct sl_pp_macro *actual_arg = NULL; - unsigned int j; - - if (sl_pp_token_buffer_get(tokens, &input)) { - return -1; - } - - if (input.token != SL_PP_IDENTIFIER) { - strcpy(context->error_msg, "expected an identifier"); - return -1; - } - - macro_name = input.data.identifier; - - /* First look for predefined macros. - */ - - if (macro_name == context->dict.___LINE__) { - if (!mute && _out_number(context, state, context->line)) { - return -1; - } - return 0; - } - if (macro_name == context->dict.___FILE__) { - if (!mute && _out_number(context, state, context->file)) { - return -1; - } - return 0; - } - if (macro_name == context->dict.___VERSION__) { - if (!mute && _out_number(context, state, 110)) { - return -1; - } - return 0; - } - - for (j = 0; j < context->num_predefined; j++) { - if (macro_name == context->predefined[j].name) { - if (!mute) { - struct sl_pp_token_info ti; - - ti.token = SL_PP_UINT; - ti.data._uint = context->predefined[j].value; - if (sl_pp_process_out(state, &ti)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - } - return 0; - } - } - - /* Replace extension names with 1. - */ - for (j = 0; j < context->num_extensions; j++) { - if (macro_name == context->extensions[j].name) { - if (!mute && _out_number(context, state, 1)) { - return -1; - } - return 0; - } - } - - if (local) { - for (macro = local; macro; macro = macro->next) { - if (macro->name == macro_name) { - break; - } - } - } - - if (!macro) { - for (macro = context->macro; macro; macro = macro->next) { - if (macro->name == macro_name) { - break; - } - } - } - - if (!macro) { - if (behaviour == sl_pp_macro_expand_unknown_to_0) { - if (_out_number(context, state, 0)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - } else if (!mute) { - if (sl_pp_process_out(state, &input)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - } - return 0; - } - - if (macro->num_args >= 0) { - if (sl_pp_token_buffer_skip_white(tokens, &input)) { - return -1; - } - if (input.token != SL_PP_LPAREN) { - strcpy(context->error_msg, "expected `('"); - return -1; - } - if (sl_pp_token_buffer_skip_white(tokens, &input)) { - return -1; - } - sl_pp_token_buffer_unget(tokens, &input); - } - - if (macro->num_args > 0) { - struct sl_pp_macro_formal_arg *formal_arg = macro->arg; - struct sl_pp_macro **pmacro = &actual_arg; - - for (j = 0; j < (unsigned int)macro->num_args; j++) { - struct sl_pp_process_state arg_state; - int done = 0; - unsigned int paren_nesting = 0; - struct sl_pp_token_info eof; - - memset(&arg_state, 0, sizeof(arg_state)); - - while (!done) { - if (sl_pp_token_buffer_get(tokens, &input)) { - goto fail_arg; - } - switch (input.token) { - case SL_PP_WHITESPACE: - break; - - case SL_PP_COMMA: - if (!paren_nesting) { - if (j < (unsigned int)macro->num_args - 1) { - done = 1; - } else { - strcpy(context->error_msg, "too many actual macro arguments"); - goto fail_arg; - } - } else { - if (sl_pp_process_out(&arg_state, &input)) { - strcpy(context->error_msg, "out of memory"); - goto fail_arg; - } - } - break; - - case SL_PP_LPAREN: - paren_nesting++; - if (sl_pp_process_out(&arg_state, &input)) { - goto oom_arg; - } - break; - - case SL_PP_RPAREN: - if (!paren_nesting) { - if (j == (unsigned int)macro->num_args - 1) { - done = 1; - } else { - strcpy(context->error_msg, "too few actual macro arguments"); - goto fail_arg; - } - } else { - paren_nesting--; - if (sl_pp_process_out(&arg_state, &input)) { - goto oom_arg; - } - } - break; - - case SL_PP_IDENTIFIER: - sl_pp_token_buffer_unget(tokens, &input); - if (sl_pp_macro_expand(context, tokens, local, &arg_state, sl_pp_macro_expand_normal)) { - goto fail_arg; - } - break; - - case SL_PP_EOF: - strcpy(context->error_msg, "too few actual macro arguments"); - goto fail_arg; - - default: - if (sl_pp_process_out(&arg_state, &input)) { - goto oom_arg; - } - } - } - - eof.token = SL_PP_EOF; - if (sl_pp_process_out(&arg_state, &eof)) { - goto oom_arg; - } - - *pmacro = sl_pp_macro_new(); - if (!*pmacro) { - goto oom_arg; - } - - (**pmacro).name = formal_arg->name; - (**pmacro).body = arg_state.out; - - formal_arg = formal_arg->next; - pmacro = &(**pmacro).next; - - continue; - -oom_arg: - strcpy(context->error_msg, "out of memory"); -fail_arg: - free(arg_state.out); - goto fail; - } - } - - /* Right paren for non-empty argument list has already been eaten. */ - if (macro->num_args == 0) { - if (sl_pp_token_buffer_skip_white(tokens, &input)) { - goto fail; - } - if (input.token != SL_PP_RPAREN) { - strcpy(context->error_msg, "expected `)'"); - goto fail; - } - } - - /* XXX: This is all wrong, we should be ungetting all tokens - * back to the main token buffer. - */ - { - struct sl_pp_token_buffer buffer; - - /* Seek to the end. - */ - for (j = 0; macro->body[j].token != SL_PP_EOF; j++) { - } - j++; - - /* Create a context-less token buffer since we are not going to underrun - * its internal buffer. - */ - if (sl_pp_token_buffer_init(&buffer, NULL)) { - strcpy(context->error_msg, "out of memory"); - goto fail; - } - - /* Unget the tokens in reverse order so later they will be fetched correctly. - */ - for (; j > 0; j--) { - sl_pp_token_buffer_unget(&buffer, ¯o->body[j - 1]); - } - - /* Expand. - */ - for (;;) { - struct sl_pp_token_info input; - - sl_pp_token_buffer_get(&buffer, &input); - switch (input.token) { - case SL_PP_NEWLINE: - if (sl_pp_process_out(state, &input)) { - strcpy(context->error_msg, "out of memory"); - sl_pp_token_buffer_destroy(&buffer); - goto fail; - } - break; - - case SL_PP_IDENTIFIER: - sl_pp_token_buffer_unget(&buffer, &input); - if (sl_pp_macro_expand(context, &buffer, actual_arg, state, behaviour)) { - sl_pp_token_buffer_destroy(&buffer); - goto fail; - } - break; - - case SL_PP_EOF: - sl_pp_token_buffer_destroy(&buffer); - sl_pp_macro_free(actual_arg); - return 0; - - default: - if (!mute) { - if (sl_pp_process_out(state, &input)) { - strcpy(context->error_msg, "out of memory"); - sl_pp_token_buffer_destroy(&buffer); - goto fail; - } - } - } - } - } - -fail: - sl_pp_macro_free(actual_arg); - return -1; -} diff --git a/src/glsl/pp/sl_pp_macro.h b/src/glsl/pp/sl_pp_macro.h deleted file mode 100644 index 6e65a0a588..0000000000 --- a/src/glsl/pp/sl_pp_macro.h +++ /dev/null @@ -1,70 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#ifndef SL_PP_MACRO_H -#define SL_PP_MACRO_H - -struct sl_pp_context; -struct sl_pp_process_state; -struct sl_pp_token_buffer; - -struct sl_pp_macro_formal_arg { - int name; - struct sl_pp_macro_formal_arg *next; -}; - -struct sl_pp_macro { - int name; - int num_args; /* -1 means no args, 0 means `()' */ - struct sl_pp_macro_formal_arg *arg; - struct sl_pp_token_info *body; - struct sl_pp_macro *next; -}; - -struct sl_pp_macro * -sl_pp_macro_new(void); - -void -sl_pp_macro_free(struct sl_pp_macro *macro); - -void -sl_pp_macro_reset(struct sl_pp_macro *macro); - -enum sl_pp_macro_expand_behaviour { - sl_pp_macro_expand_normal, - sl_pp_macro_expand_mute, - sl_pp_macro_expand_unknown_to_0 -}; - -int -sl_pp_macro_expand(struct sl_pp_context *context, - struct sl_pp_token_buffer *tokens, - struct sl_pp_macro *local, - struct sl_pp_process_state *state, - enum sl_pp_macro_expand_behaviour behaviour); - -#endif /* SL_PP_MACRO_H */ diff --git a/src/glsl/pp/sl_pp_pragma.c b/src/glsl/pp/sl_pp_pragma.c deleted file mode 100644 index 6789704db0..0000000000 --- a/src/glsl/pp/sl_pp_pragma.c +++ /dev/null @@ -1,110 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <string.h> -#include "sl_pp_context.h" -#include "sl_pp_process.h" -#include "sl_pp_token.h" - - -int -sl_pp_process_pragma(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last, - struct sl_pp_process_state *state) -{ - int pragma_name = -1; - struct sl_pp_token_info out; - int arg_name = -1; - - if (first < last && input[first].token == SL_PP_IDENTIFIER) { - pragma_name = input[first].data.identifier; - first++; - } - if (pragma_name == -1) { - return 0; - } - - if (pragma_name == context->dict.optimize) { - out.token = SL_PP_PRAGMA_OPTIMIZE; - } else if (pragma_name == context->dict.debug) { - out.token = SL_PP_PRAGMA_DEBUG; - } else { - return 0; - } - - while (first < last && input[first].token == SL_PP_WHITESPACE) { - first++; - } - - if (first < last && input[first].token == SL_PP_LPAREN) { - first++; - } else { - return 0; - } - - while (first < last && input[first].token == SL_PP_WHITESPACE) { - first++; - } - - if (first < last && input[first].token == SL_PP_IDENTIFIER) { - arg_name = input[first].data.identifier; - first++; - } - if (arg_name == -1) { - return 0; - } - - if (arg_name == context->dict.off) { - out.data.pragma = 0; - } else if (arg_name == context->dict.on) { - out.data.pragma = 1; - } else { - return 0; - } - - while (first < last && input[first].token == SL_PP_WHITESPACE) { - first++; - } - - if (first < last && input[first].token == SL_PP_RPAREN) { - first++; - } else { - return 0; - } - - /* Ignore the tokens that follow. */ - - if (sl_pp_process_out(state, &out)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - - return 0; -} diff --git a/src/glsl/pp/sl_pp_process.c b/src/glsl/pp/sl_pp_process.c deleted file mode 100644 index 2f12393237..0000000000 --- a/src/glsl/pp/sl_pp_process.c +++ /dev/null @@ -1,331 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include "sl_pp_context.h" -#include "sl_pp_macro.h" -#include "sl_pp_process.h" -#include "sl_pp_public.h" -#include "sl_pp_token.h" - - -int -sl_pp_process_out(struct sl_pp_process_state *state, - const struct sl_pp_token_info *token) -{ - if (state->out_len >= state->out_max) { - unsigned int new_max = state->out_max; - - if (new_max < 0x100) { - new_max = 0x100; - } else if (new_max < 0x10000) { - new_max *= 2; - } else { - new_max += 0x10000; - } - - state->out = realloc(state->out, new_max * sizeof(struct sl_pp_token_info)); - if (!state->out) { - return -1; - } - state->out_max = new_max; - } - - state->out[state->out_len++] = *token; - return 0; -} - -int -sl_pp_process_get(struct sl_pp_context *context, - struct sl_pp_token_info *output) -{ - if (!context->process_state.out) { - if (context->line > 1) { - struct sl_pp_token_info ti; - - ti.token = SL_PP_LINE; - ti.data.line.lineno = context->line - 1; - ti.data.line.fileno = context->file; - if (sl_pp_process_out(&context->process_state, &ti)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - - ti.token = SL_PP_NEWLINE; - if (sl_pp_process_out(&context->process_state, &ti)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - } - } - - for (;;) { - struct sl_pp_token_info input; - int found_eof = 0; - - if (context->process_state.out_len) { - assert(context->process_state.out); - *output = context->process_state.out[0]; - - if (context->process_state.out_len > 1) { - unsigned int i; - - for (i = 1; i < context->process_state.out_len; i++) { - context->process_state.out[i - 1] = context->process_state.out[i]; - } - } - context->process_state.out_len--; - - return 0; - } - - if (sl_pp_token_buffer_skip_white(&context->tokens, &input)) { - return -1; - } - if (input.token == SL_PP_HASH) { - if (sl_pp_token_buffer_skip_white(&context->tokens, &input)) { - return -1; - } - switch (input.token) { - case SL_PP_IDENTIFIER: - { - int name; - int found_eol = 0; - struct sl_pp_token_info endof; - struct sl_pp_token_peek peek; - int result = 0; - - /* Directive name. */ - name = input.data.identifier; - - if (sl_pp_token_buffer_skip_white(&context->tokens, &input)) { - return -1; - } - sl_pp_token_buffer_unget(&context->tokens, &input); - - if (sl_pp_token_peek_init(&peek, &context->tokens)) { - return -1; - } - - while (!found_eol) { - if (sl_pp_token_peek_get(&peek, &input)) { - sl_pp_token_peek_destroy(&peek); - return -1; - } - switch (input.token) { - case SL_PP_NEWLINE: - /* Preserve newline just for the sake of line numbering. */ - endof = input; - found_eol = 1; - break; - - case SL_PP_EOF: - endof = input; - found_eof = 1; - found_eol = 1; - break; - - default: - break; - } - } - - if (name == context->dict._if) { - struct sl_pp_token_buffer buffer; - - result = sl_pp_token_peek_to_buffer(&peek, &buffer); - if (result == 0) { - result = sl_pp_process_if(context, &buffer); - sl_pp_token_buffer_destroy(&buffer); - } - } else if (name == context->dict.ifdef) { - result = sl_pp_process_ifdef(context, peek.tokens, 0, peek.size - 1); - } else if (name == context->dict.ifndef) { - result = sl_pp_process_ifndef(context, peek.tokens, 0, peek.size - 1); - } else if (name == context->dict.elif) { - struct sl_pp_token_buffer buffer; - - result = sl_pp_token_peek_to_buffer(&peek, &buffer); - if (result == 0) { - result = sl_pp_process_elif(context, &buffer); - sl_pp_token_buffer_destroy(&buffer); - } - } else if (name == context->dict._else) { - result = sl_pp_process_else(context, peek.tokens, 0, peek.size - 1); - } else if (name == context->dict.endif) { - result = sl_pp_process_endif(context, peek.tokens, 0, peek.size - 1); - } else if (context->if_value) { - if (name == context->dict.define) { - result = sl_pp_process_define(context, peek.tokens, 0, peek.size - 1); - } else if (name == context->dict.error) { - sl_pp_process_error(context, peek.tokens, 0, peek.size - 1); - result = -1; - } else if (name == context->dict.extension) { - result = sl_pp_process_extension(context, peek.tokens, 0, peek.size - 1, &context->process_state); - } else if (name == context->dict.line) { - struct sl_pp_token_buffer buffer; - - result = sl_pp_token_peek_to_buffer(&peek, &buffer); - if (result == 0) { - result = sl_pp_process_line(context, &buffer, &context->process_state); - sl_pp_token_buffer_destroy(&buffer); - } - } else if (name == context->dict.pragma) { - result = sl_pp_process_pragma(context, peek.tokens, 0, peek.size - 1, &context->process_state); - } else if (name == context->dict.undef) { - result = sl_pp_process_undef(context, peek.tokens, 0, peek.size - 1); - } else { - strcpy(context->error_msg, "unrecognised directive name"); - result = -1; - } - } - - sl_pp_token_peek_commit(&peek); - sl_pp_token_peek_destroy(&peek); - - if (result) { - return result; - } - - if (sl_pp_process_out(&context->process_state, &endof)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - context->line++; - } - break; - - case SL_PP_NEWLINE: - /* Empty directive. */ - if (sl_pp_process_out(&context->process_state, &input)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - context->line++; - break; - - case SL_PP_EOF: - /* Empty directive. */ - if (sl_pp_process_out(&context->process_state, &input)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - found_eof = 1; - break; - - default: - strcpy(context->error_msg, "expected a directive name"); - return -1; - } - } else { - int found_eol = 0; - - sl_pp_token_buffer_unget(&context->tokens, &input); - - while (!found_eol) { - if (sl_pp_token_buffer_get(&context->tokens, &input)) { - return -1; - } - - switch (input.token) { - case SL_PP_WHITESPACE: - /* Drop whitespace all together at this point. */ - break; - - case SL_PP_NEWLINE: - /* Preserve newline just for the sake of line numbering. */ - if (sl_pp_process_out(&context->process_state, &input)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - context->line++; - found_eol = 1; - break; - - case SL_PP_EOF: - if (sl_pp_process_out(&context->process_state, &input)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - found_eof = 1; - found_eol = 1; - break; - - case SL_PP_IDENTIFIER: - sl_pp_token_buffer_unget(&context->tokens, &input); - if (sl_pp_macro_expand(context, &context->tokens, NULL, &context->process_state, - context->if_value ? sl_pp_macro_expand_normal : sl_pp_macro_expand_mute)) { - return -1; - } - break; - - default: - if (context->if_value) { - if (sl_pp_process_out(&context->process_state, &input)) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - } - } - } - } - - if (found_eof) { - if (context->if_ptr != SL_PP_MAX_IF_NESTING) { - strcpy(context->error_msg, "expected `#endif' directive"); - return -1; - } - } - } -} - -int -sl_pp_process(struct sl_pp_context *context, - struct sl_pp_token_info **output) -{ - struct sl_pp_process_state state; - - memset(&state, 0, sizeof(state)); - for (;;) { - struct sl_pp_token_info input; - - if (sl_pp_process_get(context, &input)) { - free(state.out); - return -1; - } - if (sl_pp_process_out(&state, &input)) { - free(state.out); - return -1; - } - if (input.token == SL_PP_EOF) { - *output = state.out; - return 0; - } - } -} diff --git a/src/glsl/pp/sl_pp_process.h b/src/glsl/pp/sl_pp_process.h deleted file mode 100644 index 04e9be4398..0000000000 --- a/src/glsl/pp/sl_pp_process.h +++ /dev/null @@ -1,113 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#ifndef SL_PP_PROCESS_H -#define SL_PP_PROCESS_H - -struct sl_pp_context; -struct sl_pp_token_buffer; - -struct sl_pp_process_state { - struct sl_pp_token_info *out; - unsigned int out_len; - unsigned int out_max; -}; - -int -sl_pp_process_define(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last); - -int -sl_pp_process_undef(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last); - -int -sl_pp_process_if(struct sl_pp_context *context, - struct sl_pp_token_buffer *input); - -int -sl_pp_process_ifdef(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last); - -int -sl_pp_process_ifndef(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last); - -int -sl_pp_process_elif(struct sl_pp_context *context, - struct sl_pp_token_buffer *buffer); - -int -sl_pp_process_else(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last); - -int -sl_pp_process_endif(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last); - -void -sl_pp_process_error(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last); - -int -sl_pp_process_pragma(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last, - struct sl_pp_process_state *state); - -int -sl_pp_process_extension(struct sl_pp_context *context, - const struct sl_pp_token_info *input, - unsigned int first, - unsigned int last, - struct sl_pp_process_state *state); - -int -sl_pp_process_line(struct sl_pp_context *context, - struct sl_pp_token_buffer *buffer, - struct sl_pp_process_state *state); - -int -sl_pp_process_out(struct sl_pp_process_state *state, - const struct sl_pp_token_info *token); - -#endif /* SL_PP_PROCESS_H */ diff --git a/src/glsl/pp/sl_pp_public.h b/src/glsl/pp/sl_pp_public.h deleted file mode 100644 index 66ced6cf58..0000000000 --- a/src/glsl/pp/sl_pp_public.h +++ /dev/null @@ -1,79 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#ifndef SL_PP_PUBLIC_H -#define SL_PP_PUBLIC_H - -struct sl_pp_context; -struct sl_pp_purify_options; -struct sl_pp_token_info; - -struct sl_pp_context * -sl_pp_context_create(const char *input, - const struct sl_pp_purify_options *options); - -void -sl_pp_context_destroy(struct sl_pp_context *context); - -const char * -sl_pp_context_error_message(const struct sl_pp_context *context); - -void -sl_pp_context_error_position(const struct sl_pp_context *context, - unsigned int *file, - unsigned int *line); - -int -sl_pp_context_add_extension(struct sl_pp_context *context, - const char *name); - -int -sl_pp_context_add_predefined(struct sl_pp_context *context, - const char *name, - const char *value); - -int -sl_pp_context_add_unique_str(struct sl_pp_context *context, - const char *str); - -const char * -sl_pp_context_cstr(const struct sl_pp_context *context, - int offset); - -int -sl_pp_version(struct sl_pp_context *context, - unsigned int *version); - -int -sl_pp_process_get(struct sl_pp_context *context, - struct sl_pp_token_info *output); - -int -sl_pp_process(struct sl_pp_context *context, - struct sl_pp_token_info **output); - -#endif /* SL_PP_PUBLIC_H */ diff --git a/src/glsl/pp/sl_pp_purify.c b/src/glsl/pp/sl_pp_purify.c deleted file mode 100644 index acc000cf3d..0000000000 --- a/src/glsl/pp/sl_pp_purify.c +++ /dev/null @@ -1,302 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include "sl_pp_purify.h" - - -/* - * Preprocessor purifier performs the following tasks. - * - Convert all variants of newlines into a Unix newline. - * - Merge continued lines into a single long line. - * - Remove line comments and replace block comments with whitespace. - */ - - -static unsigned int -_purify_newline(const char *input, - char *out, - unsigned int *current_line) -{ - if (input[0] == '\n') { - *out = '\n'; - (*current_line)++; - if (input[1] == '\r') { - /* - * The GLSL spec is not explicit about whether this - * combination is a valid newline or not. - * Let's assume it is acceptable. - */ - return 2; - } - return 1; - } - if (input[0] == '\r') { - *out = '\n'; - (*current_line)++; - if (input[1] == '\n') { - return 2; - } - return 1; - } - *out = input[0]; - return 1; -} - - -static unsigned int -_purify_backslash(const char *input, - char *out, - unsigned int *current_line) -{ - unsigned int eaten = 0; - - for (;;) { - if (input[0] == '\\') { - char next; - unsigned int next_eaten; - unsigned int next_line = *current_line; - - eaten++; - input++; - - next_eaten = _purify_newline(input, &next, &next_line); - if (next == '\n') { - /* - * If this is really a line continuation sequence, eat - * it and do not exit the loop. - */ - eaten += next_eaten; - input += next_eaten; - *current_line = next_line; - } else { - /* - * It is an error to put anything between a backslash - * and a newline and still expect it to behave like a line - * continuation sequence. - * Even if it is an innocent whitespace. - */ - *out = '\\'; - break; - } - } else { - eaten += _purify_newline(input, out, current_line); - break; - } - } - return eaten; -} - - -static void -_report_error(char *buf, - unsigned int cbbuf, - const char *msg, - ...) -{ - va_list args; - - va_start(args, msg); - vsnprintf(buf, cbbuf, msg, args); - va_end(args); -} - - -void -sl_pp_purify_state_init(struct sl_pp_purify_state *state, - const char *input, - const struct sl_pp_purify_options *options) -{ - state->options = *options; - state->input = input; - state->current_line = 1; - state->inside_c_comment = 0; -} - - -static unsigned int -_purify_comment(struct sl_pp_purify_state *state, - char *output, - unsigned int *current_line, - char *errormsg, - unsigned int cberrormsg) -{ - for (;;) { - unsigned int eaten; - char next; - - eaten = _purify_backslash(state->input, &next, current_line); - state->input += eaten; - while (next == '*') { - eaten = _purify_backslash(state->input, &next, current_line); - state->input += eaten; - if (next == '/') { - *output = ' '; - state->inside_c_comment = 0; - return 1; - } - } - if (next == '\n') { - *output = '\n'; - state->inside_c_comment = 1; - return 1; - } - if (next == '\0') { - _report_error(errormsg, cberrormsg, "expected `*/' but end of translation unit found"); - return 0; - } - } -} - - -unsigned int -sl_pp_purify_getc(struct sl_pp_purify_state *state, - char *output, - unsigned int *current_line, - char *errormsg, - unsigned int cberrormsg) -{ - unsigned int eaten; - - if (state->inside_c_comment) { - return _purify_comment(state, output, current_line, errormsg, cberrormsg); - } - - eaten = _purify_backslash(state->input, output, current_line); - state->input += eaten; - if (*output == '/') { - char next; - unsigned int next_line = *current_line; - - eaten = _purify_backslash(state->input, &next, &next_line); - if (next == '/') { - state->input += eaten; - *current_line = next_line; - - /* Replace a line comment with either a newline or nil. */ - for (;;) { - eaten = _purify_backslash(state->input, &next, current_line); - state->input += eaten; - if (next == '\n' || next == '\0') { - *output = next; - return eaten; - } - } - } else if (next == '*') { - state->input += eaten; - *current_line = next_line; - - return _purify_comment(state, output, current_line, errormsg, cberrormsg); - } - } - return eaten; -} - - -struct out_buf { - char *out; - unsigned int len; - unsigned int capacity; - unsigned int current_line; - char *errormsg; - unsigned int cberrormsg; -}; - - -static int -_out_buf_putc(struct out_buf *obuf, - char c) -{ - if (obuf->len >= obuf->capacity) { - unsigned int new_max = obuf->capacity; - - if (new_max < 0x100) { - new_max = 0x100; - } else if (new_max < 0x10000) { - new_max *= 2; - } else { - new_max += 0x10000; - } - - obuf->out = realloc(obuf->out, new_max); - if (!obuf->out) { - _report_error(obuf->errormsg, obuf->cberrormsg, "out of memory"); - return -1; - } - obuf->capacity = new_max; - } - - obuf->out[obuf->len++] = c; - - return 0; -} - - -int -sl_pp_purify(const char *input, - const struct sl_pp_purify_options *options, - char **output, - char *errormsg, - unsigned int cberrormsg, - unsigned int *errorline) -{ - struct out_buf obuf; - struct sl_pp_purify_state state; - - obuf.out = NULL; - obuf.len = 0; - obuf.capacity = 0; - obuf.current_line = 1; - obuf.errormsg = errormsg; - obuf.cberrormsg = cberrormsg; - - sl_pp_purify_state_init(&state, input, options); - - for (;;) { - unsigned int eaten; - char c; - - eaten = sl_pp_purify_getc(&state, &c, &obuf.current_line, errormsg, cberrormsg); - if (!eaten) { - *errorline = obuf.current_line; - return -1; - } - if (_out_buf_putc(&obuf, c)) { - *errorline = obuf.current_line; - return -1; - } - - if (c == '\0') { - break; - } - } - - *output = obuf.out; - return 0; -} diff --git a/src/glsl/pp/sl_pp_purify.h b/src/glsl/pp/sl_pp_purify.h deleted file mode 100644 index c0f55cbfd8..0000000000 --- a/src/glsl/pp/sl_pp_purify.h +++ /dev/null @@ -1,63 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#ifndef SL_PP_PURIFY_H -#define SL_PP_PURIFY_H - -struct sl_pp_purify_options { - unsigned int preserve_columns:1; - unsigned int tab_width:4; -}; - -int -sl_pp_purify(const char *input, - const struct sl_pp_purify_options *options, - char **output, - char *errormsg, - unsigned int cberrormsg, - unsigned int *errorline); - -struct sl_pp_purify_state { - struct sl_pp_purify_options options; - const char *input; - unsigned int current_line; - unsigned int inside_c_comment:1; -}; - -void -sl_pp_purify_state_init(struct sl_pp_purify_state *state, - const char *input, - const struct sl_pp_purify_options *options); - -unsigned int -sl_pp_purify_getc(struct sl_pp_purify_state *state, - char *output, - unsigned int *current_line, - char *errormsg, - unsigned int cberrormsg); - -#endif /* SL_PP_PURIFY_H */ diff --git a/src/glsl/pp/sl_pp_token.c b/src/glsl/pp/sl_pp_token.c deleted file mode 100644 index a708978700..0000000000 --- a/src/glsl/pp/sl_pp_token.c +++ /dev/null @@ -1,854 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include "sl_pp_public.h" -#include "sl_pp_context.h" -#include "sl_pp_token.h" - - -#define PURE_ERROR 256 - -static int -_pure_getc(struct sl_pp_context *context) -{ - char c; - - if (context->getc_buf_size) { - return context->getc_buf[--context->getc_buf_size]; - } - - if (sl_pp_purify_getc(&context->pure, &c, &context->error_line, context->error_msg, sizeof(context->error_msg)) == 0) { - return PURE_ERROR; - } - return c; -} - - -static void -_pure_ungetc(struct sl_pp_context *context, - int c) -{ - assert(c != PURE_ERROR); - - if (context->getc_buf_size == context->getc_buf_capacity) { - context->getc_buf_capacity += 64; - context->getc_buf = realloc(context->getc_buf, context->getc_buf_capacity * sizeof(char)); - assert(context->getc_buf); - } - - context->getc_buf[context->getc_buf_size++] = (char)c; -} - - -struct lookahead_state { - char buf[256]; - unsigned int pos; - struct sl_pp_context *context; -}; - - -static void -_lookahead_init(struct lookahead_state *lookahead, - struct sl_pp_context *context) -{ - lookahead->pos = 0; - lookahead->context = context; -} - - -static unsigned int -_lookahead_tell(const struct lookahead_state *lookahead) -{ - return lookahead->pos; -} - - -static const void * -_lookahead_buf(const struct lookahead_state *lookahead) -{ - return lookahead->buf; -} - - -static void -_lookahead_revert(struct lookahead_state *lookahead, - unsigned int pos) -{ - assert(pos <= lookahead->pos); - - while (lookahead->pos > pos) { - _pure_ungetc(lookahead->context, lookahead->buf[--lookahead->pos]); - } -} - - -static int -_lookahead_getc(struct lookahead_state *lookahead) -{ - int c; - - assert(lookahead->pos < sizeof(lookahead->buf) / sizeof(lookahead->buf[0])); - - c = _pure_getc(lookahead->context); - if (c != PURE_ERROR) { - lookahead->buf[lookahead->pos++] = (char)c; - } - return c; -} - - -static int -_is_identifier_char(char c) -{ - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; -} - - -static int -_tokenise_identifier(struct sl_pp_context *context, - struct sl_pp_token_info *out) -{ - int c; - char identifier[256]; /* XXX: Remove this artifical limit. */ - unsigned int i = 0; - - out->token = SL_PP_IDENTIFIER; - out->data.identifier = -1; - - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - identifier[i++] = (char)c; - for (;;) { - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - - if (_is_identifier_char((char)c)) { - if (i >= sizeof(identifier) / sizeof(char) - 1) { - strcpy(context->error_msg, "out of memory"); - _pure_ungetc(context, c); - while (i) { - _pure_ungetc(context, identifier[--i]); - } - return -1; - } - identifier[i++] = (char)c; - } else { - _pure_ungetc(context, c); - break; - } - } - identifier[i] = '\0'; - - out->data.identifier = sl_pp_context_add_unique_str(context, identifier); - if (out->data.identifier == -1) { - while (i) { - _pure_ungetc(context, identifier[--i]); - } - return -1; - } - - return 0; -} - - -/* - * Return the number of consecutive decimal digits in the input stream. - */ -static unsigned int -_parse_float_digits(struct lookahead_state *lookahead) -{ - unsigned int eaten; - - for (eaten = 0;; eaten++) { - unsigned int pos = _lookahead_tell(lookahead); - char c = _lookahead_getc(lookahead); - - if (c < '0' || c > '9') { - _lookahead_revert(lookahead, pos); - break; - } - } - return eaten; -} - - -/* - * Try to match one of the following patterns for the fractional part - * of a floating point number. - * - * digits . [digits] - * . digits - * - * Return 0 if the pattern could not be matched, otherwise the number - * of eaten characters from the input stream. - */ -static unsigned int -_parse_float_frac(struct lookahead_state *lookahead) -{ - unsigned int pos; - int c; - unsigned int eaten; - - pos = _lookahead_tell(lookahead); - c = _lookahead_getc(lookahead); - if (c == '.') { - eaten = _parse_float_digits(lookahead); - if (eaten) { - return eaten + 1; - } - _lookahead_revert(lookahead, pos); - return 0; - } - - _lookahead_revert(lookahead, pos); - eaten = _parse_float_digits(lookahead); - if (eaten) { - c = _lookahead_getc(lookahead); - if (c == '.') { - return eaten + 1 + _parse_float_digits(lookahead); - } - } - - _lookahead_revert(lookahead, pos); - return 0; -} - - -/* - * Try to match the following pattern for the exponential part - * of a floating point number. - * - * (e|E) [(+|-)] digits - * - * Return 0 if the pattern could not be matched, otherwise the number - * of eaten characters from the input stream. - */ -static unsigned int -_parse_float_exp(struct lookahead_state *lookahead) -{ - unsigned int pos, pos2; - int c; - unsigned int eaten, digits; - - pos = _lookahead_tell(lookahead); - c = _lookahead_getc(lookahead); - if (c != 'e' && c != 'E') { - _lookahead_revert(lookahead, pos); - return 0; - } - - pos2 = _lookahead_tell(lookahead); - c = _lookahead_getc(lookahead); - if (c == '-' || c == '+') { - eaten = 2; - } else { - _lookahead_revert(lookahead, pos2); - eaten = 1; - } - - digits = _parse_float_digits(lookahead); - if (!digits) { - _lookahead_revert(lookahead, pos); - return 0; - } - - return eaten + digits; -} - - -/* - * Try to match one of the following patterns for a floating point number. - * - * fract [exp] [(f|F)] - * digits exp [(f|F)] - * - * Return 0 if the pattern could not be matched, otherwise the number - * of eaten characters from the input stream. - */ -static unsigned int -_parse_float(struct lookahead_state *lookahead) -{ - unsigned int eaten; - - eaten = _parse_float_frac(lookahead); - if (eaten) { - unsigned int pos; - int c; - - eaten += _parse_float_exp(lookahead); - - pos = _lookahead_tell(lookahead); - c = _lookahead_getc(lookahead); - if (c == 'f' || c == 'F') { - eaten++; - } else { - _lookahead_revert(lookahead, pos); - } - - return eaten; - } - - eaten = _parse_float_digits(lookahead); - if (eaten) { - unsigned int exponent; - - exponent = _parse_float_exp(lookahead); - if (exponent) { - unsigned int pos; - int c; - - eaten += exponent; - - pos = _lookahead_tell(lookahead); - c = _lookahead_getc(lookahead); - if (c == 'f' || c == 'F') { - eaten++; - } else { - _lookahead_revert(lookahead, pos); - } - - return eaten; - } - } - - _lookahead_revert(lookahead, 0); - return 0; -} - - -static unsigned int -_parse_hex(struct lookahead_state *lookahead) -{ - int c; - unsigned int n; - - c = _lookahead_getc(lookahead); - if (c != '0') { - _lookahead_revert(lookahead, 0); - return 0; - } - - c = _lookahead_getc(lookahead); - if (c != 'x' && c != 'X') { - _lookahead_revert(lookahead, 0); - return 0; - } - - for (n = 2;;) { - unsigned int pos = _lookahead_tell(lookahead); - - c = _lookahead_getc(lookahead); - if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { - n++; - } else { - _lookahead_revert(lookahead, pos); - break; - } - } - - if (n > 2) { - return n; - } - - _lookahead_revert(lookahead, 0); - return 0; -} - - -static unsigned int -_parse_oct(struct lookahead_state *lookahead) -{ - int c; - unsigned int n; - - c = _lookahead_getc(lookahead); - if (c != '0') { - _lookahead_revert(lookahead, 0); - return 0; - } - - for (n = 1;;) { - unsigned int pos = _lookahead_tell(lookahead); - - c = _lookahead_getc(lookahead); - if ((c >= '0' && c <= '7')) { - n++; - } else { - _lookahead_revert(lookahead, pos); - break; - } - } - - return n; -} - - -static unsigned int -_parse_dec(struct lookahead_state *lookahead) -{ - unsigned int n = 0; - - for (;;) { - unsigned int pos = _lookahead_tell(lookahead); - int c = _lookahead_getc(lookahead); - - if ((c >= '0' && c <= '9')) { - n++; - } else { - _lookahead_revert(lookahead, pos); - break; - } - } - - return n; -} - - -static int -_tokenise_number(struct sl_pp_context *context, - struct sl_pp_token_info *out) -{ - struct lookahead_state lookahead; - unsigned int eaten; - unsigned int is_float = 0; - unsigned int pos; - int c; - char number[256]; /* XXX: Remove this artifical limit. */ - - _lookahead_init(&lookahead, context); - - eaten = _parse_float(&lookahead); - if (!eaten) { - eaten = _parse_hex(&lookahead); - if (!eaten) { - eaten = _parse_oct(&lookahead); - if (!eaten) { - eaten = _parse_dec(&lookahead); - } - } - } else { - is_float = 1; - } - - if (!eaten) { - strcpy(context->error_msg, "expected a number"); - return -1; - } - - pos = _lookahead_tell(&lookahead); - c = _lookahead_getc(&lookahead); - _lookahead_revert(&lookahead, pos); - - if (_is_identifier_char(c)) { - strcpy(context->error_msg, "expected a number"); - _lookahead_revert(&lookahead, 0); - return -1; - } - - if (eaten > sizeof(number) - 1) { - strcpy(context->error_msg, "out of memory"); - _lookahead_revert(&lookahead, 0); - return -1; - } - - assert(_lookahead_tell(&lookahead) == eaten); - - memcpy(number, _lookahead_buf(&lookahead), eaten); - number[eaten] = '\0'; - - if (is_float) { - out->token = SL_PP_FLOAT; - out->data._float = sl_pp_context_add_unique_str(context, number); - if (out->data._float == -1) { - _lookahead_revert(&lookahead, 0); - return -1; - } - } else { - out->token = SL_PP_UINT; - out->data._uint = sl_pp_context_add_unique_str(context, number); - if (out->data._uint == -1) { - _lookahead_revert(&lookahead, 0); - return -1; - } - } - - return 0; -} - - -int -sl_pp_token_get(struct sl_pp_context *context, - struct sl_pp_token_info *out) -{ - int c = _pure_getc(context); - - switch (c) { - case ' ': - case '\t': - out->token = SL_PP_WHITESPACE; - break; - - case '\n': - out->token = SL_PP_NEWLINE; - break; - - case '#': - out->token = SL_PP_HASH; - break; - - case ',': - out->token = SL_PP_COMMA; - break; - - case ';': - out->token = SL_PP_SEMICOLON; - break; - - case '{': - out->token = SL_PP_LBRACE; - break; - - case '}': - out->token = SL_PP_RBRACE; - break; - - case '(': - out->token = SL_PP_LPAREN; - break; - - case ')': - out->token = SL_PP_RPAREN; - break; - - case '[': - out->token = SL_PP_LBRACKET; - break; - - case ']': - out->token = SL_PP_RBRACKET; - break; - - case '.': - { - int c2 = _pure_getc(context); - - if (c2 == PURE_ERROR) { - return -1; - } - if (c2 >= '0' && c2 <= '9') { - _pure_ungetc(context, c2); - _pure_ungetc(context, c); - if (_tokenise_number(context, out)) { - return -1; - } - } else { - _pure_ungetc(context, c2); - out->token = SL_PP_DOT; - } - } - break; - - case '+': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '+') { - out->token = SL_PP_INCREMENT; - } else if (c == '=') { - out->token = SL_PP_ADDASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_PLUS; - } - break; - - case '-': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '-') { - out->token = SL_PP_DECREMENT; - } else if (c == '=') { - out->token = SL_PP_SUBASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_MINUS; - } - break; - - case '~': - out->token = SL_PP_BITNOT; - break; - - case '!': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '=') { - out->token = SL_PP_NOTEQUAL; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_NOT; - } - break; - - case '*': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '=') { - out->token = SL_PP_MULASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_STAR; - } - break; - - case '/': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '=') { - out->token = SL_PP_DIVASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_SLASH; - } - break; - - case '%': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '=') { - out->token = SL_PP_MODASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_MODULO; - } - break; - - case '<': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '<') { - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '=') { - out->token = SL_PP_LSHIFTASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_LSHIFT; - } - } else if (c == '=') { - out->token = SL_PP_LESSEQUAL; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_LESS; - } - break; - - case '>': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '>') { - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '=') { - out->token = SL_PP_RSHIFTASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_RSHIFT; - } - } else if (c == '=') { - out->token = SL_PP_GREATEREQUAL; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_GREATER; - } - break; - - case '=': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '=') { - out->token = SL_PP_EQUAL; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_ASSIGN; - } - break; - - case '&': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '&') { - out->token = SL_PP_AND; - } else if (c == '=') { - out->token = SL_PP_BITANDASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_BITAND; - } - break; - - case '^': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '^') { - out->token = SL_PP_XOR; - } else if (c == '=') { - out->token = SL_PP_BITXORASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_BITXOR; - } - break; - - case '|': - c = _pure_getc(context); - if (c == PURE_ERROR) { - return -1; - } - if (c == '|') { - out->token = SL_PP_OR; - } else if (c == '=') { - out->token = SL_PP_BITORASSIGN; - } else { - _pure_ungetc(context, c); - out->token = SL_PP_BITOR; - } - break; - - case '?': - out->token = SL_PP_QUESTION; - break; - - case ':': - out->token = SL_PP_COLON; - break; - - case '\0': - out->token = SL_PP_EOF; - break; - - case PURE_ERROR: - return -1; - - default: - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') { - _pure_ungetc(context, c); - if (_tokenise_identifier(context, out)) { - return -1; - } - } else if (c >= '0' && c <= '9') { - _pure_ungetc(context, c); - if (_tokenise_number(context, out)) { - return -1; - } - } else { - out->data.other = c; - out->token = SL_PP_OTHER; - } - } - - return 0; -} - - -int -sl_pp_tokenise(struct sl_pp_context *context, - struct sl_pp_token_info **output) -{ - struct sl_pp_token_info *out = NULL; - unsigned int out_len = 0; - unsigned int out_max = 0; - - for (;;) { - struct sl_pp_token_info info; - - if (sl_pp_token_buffer_get(&context->tokens, &info)) { - free(out); - return -1; - } - - if (out_len >= out_max) { - unsigned int new_max = out_max; - - if (new_max < 0x100) { - new_max = 0x100; - } else if (new_max < 0x10000) { - new_max *= 2; - } else { - new_max += 0x10000; - } - - out = realloc(out, new_max * sizeof(struct sl_pp_token_info)); - if (!out) { - strcpy(context->error_msg, "out of memory"); - return -1; - } - out_max = new_max; - } - - out[out_len++] = info; - - if (info.token == SL_PP_EOF) { - break; - } - } - - *output = out; - return 0; -} diff --git a/src/glsl/pp/sl_pp_token.h b/src/glsl/pp/sl_pp_token.h deleted file mode 100644 index a12b193401..0000000000 --- a/src/glsl/pp/sl_pp_token.h +++ /dev/null @@ -1,133 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#ifndef SL_PP_TOKEN_H -#define SL_PP_TOKEN_H - - -struct sl_pp_context; - -enum sl_pp_token { - SL_PP_WHITESPACE, - SL_PP_NEWLINE, - SL_PP_HASH, /* # */ - - SL_PP_COMMA, /* , */ - SL_PP_SEMICOLON, /* ; */ - SL_PP_LBRACE, /* { */ - SL_PP_RBRACE, /* } */ - SL_PP_LPAREN, /* ( */ - SL_PP_RPAREN, /* ) */ - SL_PP_LBRACKET, /* [ */ - SL_PP_RBRACKET, /* ] */ - SL_PP_DOT, /* . */ - SL_PP_INCREMENT, /* ++ */ - SL_PP_ADDASSIGN, /* += */ - SL_PP_PLUS, /* + */ - SL_PP_DECREMENT, /* -- */ - SL_PP_SUBASSIGN, /* -= */ - SL_PP_MINUS, /* - */ - SL_PP_BITNOT, /* ~ */ - SL_PP_NOTEQUAL, /* != */ - SL_PP_NOT, /* ! */ - SL_PP_MULASSIGN, /* *= */ - SL_PP_STAR, /* * */ - SL_PP_DIVASSIGN, /* /= */ - SL_PP_SLASH, /* / */ - SL_PP_MODASSIGN, /* %= */ - SL_PP_MODULO, /* % */ - SL_PP_LSHIFTASSIGN, /* <<= */ - SL_PP_LSHIFT, /* << */ - SL_PP_LESSEQUAL, /* <= */ - SL_PP_LESS, /* < */ - SL_PP_RSHIFTASSIGN, /* >>= */ - SL_PP_RSHIFT, /* >> */ - SL_PP_GREATEREQUAL, /* >= */ - SL_PP_GREATER, /* > */ - SL_PP_EQUAL, /* == */ - SL_PP_ASSIGN, /* = */ - SL_PP_AND, /* && */ - SL_PP_BITANDASSIGN, /* &= */ - SL_PP_BITAND, /* & */ - SL_PP_XOR, /* ^^ */ - SL_PP_BITXORASSIGN, /* ^= */ - SL_PP_BITXOR, /* ^ */ - SL_PP_OR, /* || */ - SL_PP_BITORASSIGN, /* |= */ - SL_PP_BITOR, /* | */ - SL_PP_QUESTION, /* ? */ - SL_PP_COLON, /* : */ - - SL_PP_IDENTIFIER, - - SL_PP_UINT, - SL_PP_FLOAT, - - SL_PP_OTHER, - - SL_PP_PRAGMA_OPTIMIZE, - SL_PP_PRAGMA_DEBUG, - - SL_PP_EXTENSION_REQUIRE, - SL_PP_EXTENSION_ENABLE, - SL_PP_EXTENSION_WARN, - SL_PP_EXTENSION_DISABLE, - - SL_PP_LINE, - - SL_PP_EOF -}; - -union sl_pp_token_data { - int identifier; - int _uint; - int _float; - char other; - int pragma; - int extension; - struct { - unsigned int lineno: 24; - unsigned int fileno: 8; - } line; -}; - -struct sl_pp_token_info { - enum sl_pp_token token; - union sl_pp_token_data data; -}; - -struct sl_pp_purify_options; - -int -sl_pp_token_get(struct sl_pp_context *context, - struct sl_pp_token_info *out); - -int -sl_pp_tokenise(struct sl_pp_context *context, - struct sl_pp_token_info **output); - -#endif /* SL_PP_TOKEN_H */ diff --git a/src/glsl/pp/sl_pp_token_util.c b/src/glsl/pp/sl_pp_token_util.c deleted file mode 100644 index 43be49670b..0000000000 --- a/src/glsl/pp/sl_pp_token_util.c +++ /dev/null @@ -1,183 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <assert.h> -#include <stdlib.h> -#include "sl_pp_token_util.h" -#include "sl_pp_token.h" - - -int -sl_pp_token_buffer_init(struct sl_pp_token_buffer *buffer, - struct sl_pp_context *context) -{ - buffer->context = context; - buffer->size = 0; - buffer->capacity = 64; - buffer->tokens = malloc(buffer->capacity * sizeof(struct sl_pp_token_info)); - if (!buffer->tokens) { - return -1; - } - return 0; -} - -void -sl_pp_token_buffer_destroy(struct sl_pp_token_buffer *buffer) -{ - free(buffer->tokens); -} - -int -sl_pp_token_buffer_get(struct sl_pp_token_buffer *buffer, - struct sl_pp_token_info *out) -{ - /* Pop from stack first if not empty. */ - if (buffer->size) { - *out = buffer->tokens[--buffer->size]; - return 0; - } - - assert(buffer->context); - return sl_pp_token_get(buffer->context, out); -} - -void -sl_pp_token_buffer_unget(struct sl_pp_token_buffer *buffer, - const struct sl_pp_token_info *in) -{ - /* Resize if needed. */ - if (buffer->size == buffer->capacity) { - buffer->capacity += 64; - buffer->tokens = realloc(buffer->tokens, - buffer->capacity * sizeof(struct sl_pp_token_info)); - assert(buffer->tokens); - } - - /* Push token on stack. */ - buffer->tokens[buffer->size++] = *in; -} - -int -sl_pp_token_buffer_skip_white(struct sl_pp_token_buffer *buffer, - struct sl_pp_token_info *out) -{ - if (sl_pp_token_buffer_get(buffer, out)) { - return -1; - } - - while (out->token == SL_PP_WHITESPACE) { - if (sl_pp_token_buffer_get(buffer, out)) { - return -1; - } - } - - return 0; -} - - - -int -sl_pp_token_peek_init(struct sl_pp_token_peek *peek, - struct sl_pp_token_buffer *buffer) -{ - peek->buffer = buffer; - peek->size = 0; - peek->capacity = 64; - peek->tokens = malloc(peek->capacity * sizeof(struct sl_pp_token_info)); - if (!peek->tokens) { - return -1; - } - return 0; -} - -void -sl_pp_token_peek_destroy(struct sl_pp_token_peek *peek) -{ - /* Abort. */ - while (peek->size) { - sl_pp_token_buffer_unget(peek->buffer, &peek->tokens[--peek->size]); - } - free(peek->tokens); -} - -int -sl_pp_token_peek_get(struct sl_pp_token_peek *peek, - struct sl_pp_token_info *out) -{ - /* Get token from buffer. */ - if (sl_pp_token_buffer_get(peek->buffer, out)) { - return -1; - } - - /* Save it. */ - if (peek->size == peek->capacity) { - peek->capacity += 64; - peek->tokens = realloc(peek->tokens, - peek->capacity * sizeof(struct sl_pp_token_info)); - assert(peek->tokens); - } - peek->tokens[peek->size++] = *out; - return 0; -} - -void -sl_pp_token_peek_commit(struct sl_pp_token_peek *peek) -{ - peek->size = 0; -} - -int -sl_pp_token_peek_to_buffer(const struct sl_pp_token_peek *peek, - struct sl_pp_token_buffer *buffer) -{ - unsigned int i; - - if (sl_pp_token_buffer_init(buffer, NULL)) { - return -1; - } - for (i = peek->size; i > 0; i--) { - sl_pp_token_buffer_unget(buffer, &peek->tokens[i - 1]); - } - return 0; -} - -int -sl_pp_token_peek_skip_white(struct sl_pp_token_peek *peek, - struct sl_pp_token_info *out) -{ - if (sl_pp_token_peek_get(peek, out)) { - return -1; - } - - while (out->token == SL_PP_WHITESPACE) { - if (sl_pp_token_peek_get(peek, out)) { - return -1; - } - } - - return 0; -} diff --git a/src/glsl/pp/sl_pp_token_util.h b/src/glsl/pp/sl_pp_token_util.h deleted file mode 100644 index 35d72101ca..0000000000 --- a/src/glsl/pp/sl_pp_token_util.h +++ /dev/null @@ -1,98 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#ifndef SL_PP_TOKEN_UTIL_H -#define SL_PP_TOKEN_UTIL_H - -struct sl_pp_context; - -/* - * A token buffer allows one to get and unget a token - * from a preprocessor context. - */ -struct sl_pp_token_buffer { - struct sl_pp_context *context; - unsigned int size; - unsigned int capacity; - struct sl_pp_token_info *tokens; -}; - -int -sl_pp_token_buffer_init(struct sl_pp_token_buffer *buffer, - struct sl_pp_context *context); - -void -sl_pp_token_buffer_destroy(struct sl_pp_token_buffer *buffer); - -int -sl_pp_token_buffer_get(struct sl_pp_token_buffer *buffer, - struct sl_pp_token_info *out); - -void -sl_pp_token_buffer_unget(struct sl_pp_token_buffer *buffer, - const struct sl_pp_token_info *in); - -int -sl_pp_token_buffer_skip_white(struct sl_pp_token_buffer *buffer, - struct sl_pp_token_info *out); - - -/* - * A token peek allows one to get a number of tokens from a buffer - * and then either commit the operation or abort it, - * effectively ungetting the peeked tokens. - */ -struct sl_pp_token_peek { - struct sl_pp_token_buffer *buffer; - unsigned int size; - unsigned int capacity; - struct sl_pp_token_info *tokens; -}; - -int -sl_pp_token_peek_init(struct sl_pp_token_peek *peek, - struct sl_pp_token_buffer *buffer); - -void -sl_pp_token_peek_destroy(struct sl_pp_token_peek *peek); - -int -sl_pp_token_peek_get(struct sl_pp_token_peek *peek, - struct sl_pp_token_info *out); - -void -sl_pp_token_peek_commit(struct sl_pp_token_peek *peek); - -int -sl_pp_token_peek_to_buffer(const struct sl_pp_token_peek *peek, - struct sl_pp_token_buffer *buffer); - -int -sl_pp_token_peek_skip_white(struct sl_pp_token_peek *peek, - struct sl_pp_token_info *out); - -#endif /* SL_PP_TOKEN_UTIL_H */ diff --git a/src/glsl/pp/sl_pp_version.c b/src/glsl/pp/sl_pp_version.c deleted file mode 100644 index 6735c05e8a..0000000000 --- a/src/glsl/pp/sl_pp_version.c +++ /dev/null @@ -1,162 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include <stdlib.h> -#include <string.h> -#include "sl_pp_public.h" -#include "sl_pp_context.h" -#include "sl_pp_token.h" - - -int -sl_pp_version(struct sl_pp_context *context, - unsigned int *version) -{ - struct sl_pp_token_peek peek; - unsigned int line = context->line; - - /* Default values if `#version' is not present. */ - *version = 110; - - if (sl_pp_token_peek_init(&peek, &context->tokens)) { - return -1; - } - - /* There can be multiple `#version' directives present. - * Accept the value of the last one. - */ - for (;;) { - struct sl_pp_token_info input; - int found_hash = 0; - int found_version = 0; - int found_number = 0; - int found_end = 0; - - /* Skip whitespace and newlines and seek for hash. */ - while (!found_hash) { - if (sl_pp_token_peek_get(&peek, &input)) { - sl_pp_token_peek_destroy(&peek); - return -1; - } - - switch (input.token) { - case SL_PP_NEWLINE: - line++; - break; - - case SL_PP_WHITESPACE: - break; - - case SL_PP_HASH: - found_hash = 1; - break; - - default: - sl_pp_token_peek_destroy(&peek); - return 0; - } - } - - /* Skip whitespace and seek for `version'. */ - while (!found_version) { - if (sl_pp_token_peek_get(&peek, &input)) { - sl_pp_token_peek_destroy(&peek); - return -1; - } - - switch (input.token) { - case SL_PP_WHITESPACE: - break; - - case SL_PP_IDENTIFIER: - if (input.data.identifier != context->dict.version) { - sl_pp_token_peek_destroy(&peek); - return 0; - } - found_version = 1; - break; - - default: - sl_pp_token_peek_destroy(&peek); - return 0; - } - } - - sl_pp_token_peek_commit(&peek); - - /* Skip whitespace and seek for version number. */ - while (!found_number) { - if (sl_pp_token_buffer_get(&context->tokens, &input)) { - sl_pp_token_peek_destroy(&peek); - return -1; - } - - switch (input.token) { - case SL_PP_WHITESPACE: - break; - - case SL_PP_UINT: - *version = atoi(sl_pp_context_cstr(context, input.data._uint)); - found_number = 1; - break; - - default: - strcpy(context->error_msg, "expected version number after `#version'"); - sl_pp_token_peek_destroy(&peek); - return -1; - } - } - - /* Skip whitespace and seek for either newline or eof. */ - while (!found_end) { - if (sl_pp_token_buffer_get(&context->tokens, &input)) { - sl_pp_token_peek_destroy(&peek); - return -1; - } - - switch (input.token) { - case SL_PP_WHITESPACE: - break; - - case SL_PP_NEWLINE: - line++; - /* pass thru */ - case SL_PP_EOF: - context->line = line; - found_end = 1; - break; - - default: - strcpy(context->error_msg, "expected end of line after version number"); - sl_pp_token_peek_destroy(&peek); - return -1; - } - } - } - - /* Should not get here. */ -} diff --git a/src/mesa/slang/library/slang_builtin_120_fragment.gc b/src/glsl/program.h index 7d516046a1..893169b6cc 100644 --- a/src/mesa/slang/library/slang_builtin_120_fragment.gc +++ b/src/glsl/program.h @@ -1,8 +1,7 @@ /* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2006 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * Copyright © 2010 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -22,9 +21,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -// -// From Shader Spec, ver. 1.20, rev. 6 -// - -varying vec2 gl_PointCoord; +#include "main/core.h" +extern void +link_shaders(GLcontext *ctx, struct gl_shader_program *prog); diff --git a/src/glsl/s_expression.cpp b/src/glsl/s_expression.cpp new file mode 100644 index 0000000000..4458c48d6b --- /dev/null +++ b/src/glsl/s_expression.cpp @@ -0,0 +1,140 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <assert.h> +#include "s_expression.h" + +s_symbol::s_symbol(const char *tmp, size_t n) +{ + this->str = talloc_strndup (this, tmp, n); + assert(this->str != NULL); +} + +s_list::s_list() +{ +} + +unsigned +s_list::length() const +{ + unsigned i = 0; + foreach_iter(exec_list_iterator, it, this->subexpressions) { + i++; + } + return i; +} + +static s_expression * +read_atom(void *ctx, const char *& src) +{ + s_expression *expr = NULL; + + // Skip leading spaces. + src += strspn(src, " \v\t\r\n"); + + size_t n = strcspn(src, "( \v\t\r\n)"); + if (n == 0) + return NULL; // no atom + + // Check if the atom is a number. + char *float_end = NULL; + double f = strtod(src, &float_end); + if (float_end != src) { + char *int_end = NULL; + int i = strtol(src, &int_end, 10); + // If strtod matched more characters, it must have a decimal part + if (float_end > int_end) + expr = new(ctx) s_float(f); + else + expr = new(ctx) s_int(i); + } else { + // Not a number; return a symbol. + expr = new(ctx) s_symbol(src, n); + } + + src += n; + + return expr; +} + +s_expression * +s_expression::read_expression(void *ctx, const char *&src) +{ + assert(src != NULL); + + s_expression *atom = read_atom(ctx, src); + if (atom != NULL) + return atom; + + // Skip leading spaces. + src += strspn(src, " \v\t\r\n"); + if (src[0] == '(') { + ++src; + + s_list *list = new(ctx) s_list; + s_expression *expr; + + while ((expr = read_expression(ctx, src)) != NULL) { + list->subexpressions.push_tail(expr); + } + src += strspn(src, " \v\t\r\n"); + if (src[0] != ')') { + printf("Unclosed expression (check your parenthesis).\n"); + return NULL; + } + ++src; + return list; + } + return NULL; +} + +void s_int::print() +{ + printf("%d", this->val); +} + +void s_float::print() +{ + printf("%f", this->val); +} + +void s_symbol::print() +{ + printf("%s", this->str); +} + +void s_list::print() +{ + printf("("); + foreach_iter(exec_list_iterator, it, this->subexpressions) { + s_expression *expr = (s_expression*) it.get(); + expr->print(); + printf(" "); + } + printf(")"); +} + diff --git a/src/glsl/s_expression.h b/src/glsl/s_expression.h new file mode 100644 index 0000000000..aa22475a1b --- /dev/null +++ b/src/glsl/s_expression.h @@ -0,0 +1,142 @@ +/* -*- c++ -*- */ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef S_EXPRESSION_H +#define S_EXPRESSION_H + +#include "list.h" + +#define SX_AS_(t,x) ((x) && ((s_expression*) x)->is_##t()) ? ((s_##t*) (x)) \ + : NULL +#define SX_AS_LIST(x) SX_AS_(list, x) +#define SX_AS_SYMBOL(x) SX_AS_(symbol, x) +#define SX_AS_NUMBER(x) SX_AS_(number, x) +#define SX_AS_INT(x) SX_AS_(int, x) + +/* For our purposes, S-Expressions are: + * - <int> + * - <float> + * - symbol + * - (expr1 expr2 ... exprN) where exprN is an S-Expression + * + * Unlike LISP/Scheme, we do not support (foo . bar) pairs. + */ +class s_expression : public exec_node +{ +public: + /** + * Read an S-Expression from the given string. + * Advances the supplied pointer to just after the expression read. + * + * Any allocation will be performed with 'ctx' as the talloc owner. + */ + static s_expression *read_expression(void *ctx, const char *&src); + + /** + * Print out an S-Expression. Useful for debugging. + */ + virtual void print() = 0; + + virtual bool is_list() const { return false; } + virtual bool is_symbol() const { return false; } + virtual bool is_number() const { return false; } + virtual bool is_int() const { return false; } + +protected: + s_expression() { } +}; + +/* Atoms */ + +class s_number : public s_expression +{ +public: + bool is_number() const { return true; } + + virtual float fvalue() = 0; + +protected: + s_number() { } +}; + +class s_int : public s_number +{ +public: + s_int(int x) : val(x) { } + + bool is_int() const { return true; } + + float fvalue() { return float(this->val); } + int value() { return this->val; } + + void print(); + +private: + int val; +}; + +class s_float : public s_number +{ +public: + s_float(float x) : val(x) { } + + float fvalue() { return this->val; } + + void print(); + +private: + float val; +}; + +class s_symbol : public s_expression +{ +public: + s_symbol(const char *, size_t); + + bool is_symbol() const { return true; } + + const char *value() { return this->str; } + + void print(); + +private: + char *str; +}; + +/* Lists of expressions: (expr1 ... exprN) */ +class s_list : public s_expression +{ +public: + s_list(); + + virtual bool is_list() const { return true; } + unsigned length() const; + + void print(); + + exec_list subexpressions; +}; + +#endif /* S_EXPRESSION_H */ diff --git a/src/glsl/tests/array-01.glsl b/src/glsl/tests/array-01.glsl new file mode 100644 index 0000000000..d14135fb3a --- /dev/null +++ b/src/glsl/tests/array-01.glsl @@ -0,0 +1,3 @@ +#version 120 +/* FAIL - array size type must be int */ +uniform vec4 [3.2] a; diff --git a/src/glsl/tests/array-02.glsl b/src/glsl/tests/array-02.glsl new file mode 100644 index 0000000000..d743617158 --- /dev/null +++ b/src/glsl/tests/array-02.glsl @@ -0,0 +1,3 @@ +#version 120 +/* FAIL - array size type must be scalar */ +uniform vec4 [ivec4(3)] a; diff --git a/src/glsl/tests/array-03.glsl b/src/glsl/tests/array-03.glsl new file mode 100644 index 0000000000..0026913f01 --- /dev/null +++ b/src/glsl/tests/array-03.glsl @@ -0,0 +1,3 @@ +#version 120 +/* PASS */ +uniform vec4 [3] a; diff --git a/src/glsl/tests/array-04.glsl b/src/glsl/tests/array-04.glsl new file mode 100644 index 0000000000..70f434d8ab --- /dev/null +++ b/src/glsl/tests/array-04.glsl @@ -0,0 +1,2 @@ +/* FAIL - array size type must be int */ +uniform vec4 a[3.2]; diff --git a/src/glsl/tests/array-05.glsl b/src/glsl/tests/array-05.glsl new file mode 100644 index 0000000000..168704096b --- /dev/null +++ b/src/glsl/tests/array-05.glsl @@ -0,0 +1,2 @@ +/* FAIL - array size type must be scalar */ +uniform vec4 a[ivec4(3)]; diff --git a/src/glsl/tests/array-06.glsl b/src/glsl/tests/array-06.glsl new file mode 100644 index 0000000000..46b43795be --- /dev/null +++ b/src/glsl/tests/array-06.glsl @@ -0,0 +1,2 @@ +/* PASS */ +uniform vec4 a[3]; diff --git a/src/glsl/tests/array-07.glsl b/src/glsl/tests/array-07.glsl new file mode 100644 index 0000000000..161ffbf2f2 --- /dev/null +++ b/src/glsl/tests/array-07.glsl @@ -0,0 +1,2 @@ +/* FAIL - array size must be > 0 */ +uniform vec4 a[0]; diff --git a/src/glsl/tests/array-08.glsl b/src/glsl/tests/array-08.glsl new file mode 100644 index 0000000000..4bf0c6bd51 --- /dev/null +++ b/src/glsl/tests/array-08.glsl @@ -0,0 +1,2 @@ +/* FAIL - array size must be > 0 */ +uniform vec4 a[-1]; diff --git a/src/glsl/tests/array-09.glsl b/src/glsl/tests/array-09.glsl new file mode 100644 index 0000000000..cad6d0e54e --- /dev/null +++ b/src/glsl/tests/array-09.glsl @@ -0,0 +1,9 @@ +#version 120 +/* PASS */ + +void main() +{ + vec4 a[2] = vec4 [2] (vec4(1.0), vec4(2.0)); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/array-10.glsl b/src/glsl/tests/array-10.glsl new file mode 100644 index 0000000000..019aa21150 --- /dev/null +++ b/src/glsl/tests/array-10.glsl @@ -0,0 +1,11 @@ +/* FAIL - array constructors forbidden in GLSL 1.10 + * + * This can also generate an error because the 'vec4[]' style syntax is + * illegal in GLSL 1.10. + */ +void main() +{ + vec4 a[2] = vec4 [2] (vec4(1.0), vec4(2.0)); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/array-11.glsl b/src/glsl/tests/array-11.glsl new file mode 100644 index 0000000000..51d94e9477 --- /dev/null +++ b/src/glsl/tests/array-11.glsl @@ -0,0 +1,9 @@ +#version 120 +/* PASS */ + +void main() +{ + vec4 a[] = vec4 [] (vec4(1.0), vec4(2.0)); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/array-12.glsl b/src/glsl/tests/array-12.glsl new file mode 100644 index 0000000000..7fc9579452 --- /dev/null +++ b/src/glsl/tests/array-12.glsl @@ -0,0 +1,11 @@ +#version 120 +/* FAIL - array must have an implicit or explicit size */ + +void main() +{ + vec4 a[]; + + a = vec4 [2] (vec4(1.0), vec4(2.0)); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/array-13.glsl b/src/glsl/tests/array-13.glsl new file mode 100644 index 0000000000..cc7e29a5f7 --- /dev/null +++ b/src/glsl/tests/array-13.glsl @@ -0,0 +1,11 @@ +#version 120 +/* PASS */ + +void main() +{ + vec4 a[2]; + + a = vec4 [] (vec4(1.0), vec4(2.0)); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/attribute-01.glsl b/src/glsl/tests/attribute-01.glsl new file mode 100644 index 0000000000..18e9e4468a --- /dev/null +++ b/src/glsl/tests/attribute-01.glsl @@ -0,0 +1,7 @@ +/* FAIL - attribute cannot have type int */ +attribute int i; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-02.glsl b/src/glsl/tests/attribute-02.glsl new file mode 100644 index 0000000000..6b6df74d25 --- /dev/null +++ b/src/glsl/tests/attribute-02.glsl @@ -0,0 +1,7 @@ +/* FAIL - attribute cannot have type ivec2 */ +attribute ivec2 i; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-03.glsl b/src/glsl/tests/attribute-03.glsl new file mode 100644 index 0000000000..870de9e814 --- /dev/null +++ b/src/glsl/tests/attribute-03.glsl @@ -0,0 +1,7 @@ +/* FAIL - attribute cannot have type ivec3 */ +attribute ivec3 i; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-04.glsl b/src/glsl/tests/attribute-04.glsl new file mode 100644 index 0000000000..14af2fcaad --- /dev/null +++ b/src/glsl/tests/attribute-04.glsl @@ -0,0 +1,7 @@ +/* FAIL - attribute cannot have type ivec4 */ +attribute ivec4 i; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-05.glsl b/src/glsl/tests/attribute-05.glsl new file mode 100644 index 0000000000..18822c7854 --- /dev/null +++ b/src/glsl/tests/attribute-05.glsl @@ -0,0 +1,7 @@ +/* FAIL - attribute cannot have type bool */ +attribute bool i; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-06.glsl b/src/glsl/tests/attribute-06.glsl new file mode 100644 index 0000000000..f18027b81a --- /dev/null +++ b/src/glsl/tests/attribute-06.glsl @@ -0,0 +1,7 @@ +/* FAIL - attribute cannot have type bvec2 */ +attribute bvec2 i; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-07.glsl b/src/glsl/tests/attribute-07.glsl new file mode 100644 index 0000000000..0af13ba84b --- /dev/null +++ b/src/glsl/tests/attribute-07.glsl @@ -0,0 +1,7 @@ +/* FAIL - attribute cannot have type bvec3 */ +attribute bvec3 i; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-08.glsl b/src/glsl/tests/attribute-08.glsl new file mode 100644 index 0000000000..b069c04d1b --- /dev/null +++ b/src/glsl/tests/attribute-08.glsl @@ -0,0 +1,7 @@ +/* FAIL - attribute cannot have type bvec4 */ +attribute bvec4 i; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-09.glsl b/src/glsl/tests/attribute-09.glsl new file mode 100644 index 0000000000..6a607244b9 --- /dev/null +++ b/src/glsl/tests/attribute-09.glsl @@ -0,0 +1,7 @@ +/* FAIL - attribute cannot have array type in GLSL 1.10 */ +attribute vec4 i[10]; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-10.glsl b/src/glsl/tests/attribute-10.glsl new file mode 100644 index 0000000000..6f5ef63a01 --- /dev/null +++ b/src/glsl/tests/attribute-10.glsl @@ -0,0 +1,8 @@ +#version 120 +/* FAIL - attribute cannot have array type in GLSL 1.20 */ +attribute vec4 i[10]; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/attribute-11.glsl b/src/glsl/tests/attribute-11.glsl new file mode 100644 index 0000000000..47cb5a0583 --- /dev/null +++ b/src/glsl/tests/attribute-11.glsl @@ -0,0 +1,8 @@ +#version 130 +/* FAIL - attribute cannot have array type in GLSL 1.30 */ +attribute vec4 i[10]; + +void main() +{ + gl_Position = vec4(1.0); +} diff --git a/src/glsl/tests/condition-01.glsl b/src/glsl/tests/condition-01.glsl new file mode 100644 index 0000000000..d89c313117 --- /dev/null +++ b/src/glsl/tests/condition-01.glsl @@ -0,0 +1,8 @@ +/* FAIL - :? condition is not bool scalar */ + +uniform bvec4 a; + +void main() +{ + gl_Position = (a) ? vec4(1.0, 0.0, 0.0, 1.0) : vec4(0.0, 1.0, 0.0, 1.0); +} diff --git a/src/glsl/tests/condition-02.glsl b/src/glsl/tests/condition-02.glsl new file mode 100644 index 0000000000..cbd0e18d9a --- /dev/null +++ b/src/glsl/tests/condition-02.glsl @@ -0,0 +1,8 @@ +/* FAIL - :? condition is not bool scalar */ + +uniform float a; + +void main() +{ + gl_Position = (a) ? vec4(1.0, 0.0, 0.0, 1.0) : vec4(0.0, 1.0, 0.0, 1.0); +} diff --git a/src/glsl/tests/condition-03.glsl b/src/glsl/tests/condition-03.glsl new file mode 100644 index 0000000000..9af5d7aa47 --- /dev/null +++ b/src/glsl/tests/condition-03.glsl @@ -0,0 +1,8 @@ +/* PASS */ + +uniform bool a; + +void main() +{ + gl_Position = (a) ? vec4(1.0, 0.0, 0.0, 1.0) : vec4(0.0, 1.0, 0.0, 1.0); +} diff --git a/src/glsl/tests/condition-04.glsl b/src/glsl/tests/condition-04.glsl new file mode 100644 index 0000000000..f440b7e995 --- /dev/null +++ b/src/glsl/tests/condition-04.glsl @@ -0,0 +1,8 @@ +/* FAIL - type of second two operands must match */ + +uniform bool a; + +void main() +{ + gl_Position = (a) ? vec4(1.0, 0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); +} diff --git a/src/glsl/tests/condition-05.glsl b/src/glsl/tests/condition-05.glsl new file mode 100644 index 0000000000..3dff18f519 --- /dev/null +++ b/src/glsl/tests/condition-05.glsl @@ -0,0 +1,13 @@ +#version 120 +/* PASS */ + +uniform bool a; +uniform int b; + +void main() +{ + float x; + + x = (a) ? 2.0 : b; + gl_Position = vec4(x); +} diff --git a/src/glsl/tests/constructor-01.glsl b/src/glsl/tests/constructor-01.glsl new file mode 100644 index 0000000000..fdfaf89866 --- /dev/null +++ b/src/glsl/tests/constructor-01.glsl @@ -0,0 +1,6 @@ +/* PASS */ + +void main() +{ + gl_Position = vec4(1.0, 1.0, 1.0, 0.0);; +} diff --git a/src/glsl/tests/constructor-02.glsl b/src/glsl/tests/constructor-02.glsl new file mode 100644 index 0000000000..47acbe9db1 --- /dev/null +++ b/src/glsl/tests/constructor-02.glsl @@ -0,0 +1,7 @@ +/* FAIL - cannot construct samplers */ +void main() +{ + int i; + + i = sampler2D(0); +} diff --git a/src/glsl/tests/constructor-03.glsl b/src/glsl/tests/constructor-03.glsl new file mode 100644 index 0000000000..07ec225633 --- /dev/null +++ b/src/glsl/tests/constructor-03.glsl @@ -0,0 +1,12 @@ +/* FAIL - cannot construct a matrix from a matrix in GLSL 1.10 */ + +uniform mat2 a; + +void main() +{ + mat2 b; + + b = mat2(a); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/constructor-04.glsl b/src/glsl/tests/constructor-04.glsl new file mode 100644 index 0000000000..19d5e011de --- /dev/null +++ b/src/glsl/tests/constructor-04.glsl @@ -0,0 +1,14 @@ +#version 120 +/* FAIL - matrix must be only parameter to matrix constructor */ + +uniform mat2 a; +uniform float x; + +void main() +{ + mat2 b; + + b = mat2(a, x); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/constructor-05.glsl b/src/glsl/tests/constructor-05.glsl new file mode 100644 index 0000000000..9c74f75a40 --- /dev/null +++ b/src/glsl/tests/constructor-05.glsl @@ -0,0 +1,13 @@ +/* FAIL - too few components supplied to constructor */ + +uniform vec2 a; +uniform float x; + +void main() +{ + mat2 b; + + b = mat2(a, x); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/constructor-06.glsl b/src/glsl/tests/constructor-06.glsl new file mode 100644 index 0000000000..d77a5f9e89 --- /dev/null +++ b/src/glsl/tests/constructor-06.glsl @@ -0,0 +1,13 @@ +#version 120 +/* PASS */ + +uniform mat2 a; + +void main() +{ + mat2 b; + + b = mat2(a); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/constructor-07.glsl b/src/glsl/tests/constructor-07.glsl new file mode 100644 index 0000000000..92322506ed --- /dev/null +++ b/src/glsl/tests/constructor-07.glsl @@ -0,0 +1,13 @@ +/* PASS */ + +uniform ivec2 a; +uniform ivec2 b; + +void main() +{ + mat2 c; + + c = mat2(a, b); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/constructor-08.glsl b/src/glsl/tests/constructor-08.glsl new file mode 100644 index 0000000000..27153f0cda --- /dev/null +++ b/src/glsl/tests/constructor-08.glsl @@ -0,0 +1,13 @@ +/* PASS */ + +uniform float a; +uniform float b; + +void main() +{ + ivec2 c; + + c = ivec2(a, b); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/constructor-09.glsl b/src/glsl/tests/constructor-09.glsl new file mode 100644 index 0000000000..1985699b30 --- /dev/null +++ b/src/glsl/tests/constructor-09.glsl @@ -0,0 +1,26 @@ +/* PASS */ + +uniform int a; +uniform float b; +uniform bool c; + +void main() +{ + float x; + int y; + bool z; + + x = float(a); + x = float(b); + x = float(c); + + y = int(a); + y = int(b); + y = int(c); + + z = bool(a); + z = bool(b); + z = bool(c); + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/function-01.glsl b/src/glsl/tests/function-01.glsl new file mode 100644 index 0000000000..0eaa2397ab --- /dev/null +++ b/src/glsl/tests/function-01.glsl @@ -0,0 +1,16 @@ +/* FAIL - no function named 'foo' exists */ + +vec4 bar(float x, float y, float z, float w) +{ + vec4 v; + v.x = x; + v.y = y; + v.z = z; + v.w = w; + return v; +} + +void main() +{ + gl_Position = foo(1.0, 1.0, 1.0, 0.0); +} diff --git a/src/glsl/tests/function-02.glsl b/src/glsl/tests/function-02.glsl new file mode 100644 index 0000000000..941fcc1ef7 --- /dev/null +++ b/src/glsl/tests/function-02.glsl @@ -0,0 +1,16 @@ +/* FAIL - no version of 'foo' matches the call to 'foo' */ + +vec4 foo(float x, float y, float z, float w) +{ + vec4 v; + v.x = x; + v.y = y; + v.z = z; + v.w = w; + return v; +} + +void main() +{ + gl_Position = foo(1.0, 1.0, 1.0); +} diff --git a/src/glsl/tests/function-03.glsl b/src/glsl/tests/function-03.glsl new file mode 100644 index 0000000000..b0da42f8e9 --- /dev/null +++ b/src/glsl/tests/function-03.glsl @@ -0,0 +1,16 @@ +/* PASS */ + +vec4 foo(in float x, in float y, float z, float w) +{ + vec4 v; + v.x = x; + v.y = y; + v.z = z; + v.w = w; + return v; +} + +void main() +{ + gl_Position = foo(1.0, 1.0, 1.0, 0.0); +} diff --git a/src/glsl/tests/function-04.glsl b/src/glsl/tests/function-04.glsl new file mode 100644 index 0000000000..dfc0d2b7a6 --- /dev/null +++ b/src/glsl/tests/function-04.glsl @@ -0,0 +1,15 @@ +/* FAIL - type mismatch in assignment */ + +vec3 foo(float x, float y, float z) +{ + vec3 v; + v.x = x; + v.y = y; + v.z = z; + return v; +} + +void main() +{ + gl_Position = foo(1.0, 1.0, 1.0); +} diff --git a/src/glsl/tests/function-05.glsl b/src/glsl/tests/function-05.glsl new file mode 100644 index 0000000000..43365bf606 --- /dev/null +++ b/src/glsl/tests/function-05.glsl @@ -0,0 +1,26 @@ +/* PASS */ + +vec4 foo(in float x, in float y, float z, float w) +{ + vec4 v; + v.x = x; + v.y = y; + v.z = z; + v.w = w; + return v; +} + +vec4 foo(in float x) +{ + vec4 v; + v.x = x; + v.y = x; + v.z = x; + v.w = x; +} + +void main() +{ + gl_Position = foo(1.0, 1.0, 1.0, 0.0); + gl_Position = foo(2.0); +} diff --git a/src/glsl/tests/if-01.glsl b/src/glsl/tests/if-01.glsl new file mode 100644 index 0000000000..ca9abd54f7 --- /dev/null +++ b/src/glsl/tests/if-01.glsl @@ -0,0 +1,11 @@ +/* FAIL - if-statement condition is not bool scalar */ + +uniform bvec4 a; + +void main() +{ + if (a) + gl_Position = vec4(1.0, 0.0, 0.0, 1.0); + else + gl_Position = vec4(0.0, 1.0, 0.0, 1.0); +} diff --git a/src/glsl/tests/if-02.glsl b/src/glsl/tests/if-02.glsl new file mode 100644 index 0000000000..7adccea043 --- /dev/null +++ b/src/glsl/tests/if-02.glsl @@ -0,0 +1,11 @@ +/* FAIL - if-statement condition is not bool scalar */ + +uniform float a; + +void main() +{ + if (a) + gl_Position = vec4(1.0, 0.0, 0.0, 1.0); + else + gl_Position = vec4(0.0, 1.0, 0.0, 1.0); +} diff --git a/src/glsl/tests/if-03.glsl b/src/glsl/tests/if-03.glsl new file mode 100644 index 0000000000..179618c716 --- /dev/null +++ b/src/glsl/tests/if-03.glsl @@ -0,0 +1,11 @@ +/* PASS */ + +uniform bool a; + +void main() +{ + if (a) + gl_Position = vec4(1.0, 0.0, 0.0, 1.0); + else + gl_Position = vec4(0.0, 1.0, 0.0, 1.0); +} diff --git a/src/glsl/tests/if-04.glsl b/src/glsl/tests/if-04.glsl new file mode 100644 index 0000000000..7b711fb7ed --- /dev/null +++ b/src/glsl/tests/if-04.glsl @@ -0,0 +1,11 @@ +/* PASS */ + +uniform bvec4 a; + +void main() +{ + if (a.x) + gl_Position = vec4(1.0, 0.0, 0.0, 1.0); + else + gl_Position = vec4(0.0, 1.0, 0.0, 1.0); +} diff --git a/src/glsl/tests/matrix-01.glsl b/src/glsl/tests/matrix-01.glsl new file mode 100644 index 0000000000..f46416c8f6 --- /dev/null +++ b/src/glsl/tests/matrix-01.glsl @@ -0,0 +1,6 @@ +/* FAIL - non-square matrices are not available in GLSL 1.10 */ + +void main() +{ + mat2x3 m; +} diff --git a/src/glsl/tests/matrix-02.glsl b/src/glsl/tests/matrix-02.glsl new file mode 100644 index 0000000000..0630722b79 --- /dev/null +++ b/src/glsl/tests/matrix-02.glsl @@ -0,0 +1,6 @@ +/* FAIL - non-square matrices are not available in GLSL 1.10 */ + +void main() +{ + mat2x4 m; +} diff --git a/src/glsl/tests/matrix-03.glsl b/src/glsl/tests/matrix-03.glsl new file mode 100644 index 0000000000..925dc80625 --- /dev/null +++ b/src/glsl/tests/matrix-03.glsl @@ -0,0 +1,6 @@ +/* FAIL - non-square matrices are not available in GLSL 1.10 */ + +void main() +{ + mat3x2 m; +} diff --git a/src/glsl/tests/matrix-04.glsl b/src/glsl/tests/matrix-04.glsl new file mode 100644 index 0000000000..5275619b31 --- /dev/null +++ b/src/glsl/tests/matrix-04.glsl @@ -0,0 +1,6 @@ +/* FAIL - non-square matrices are not available in GLSL 1.10 */ + +void main() +{ + mat3x4 m; +} diff --git a/src/glsl/tests/matrix-05.glsl b/src/glsl/tests/matrix-05.glsl new file mode 100644 index 0000000000..74e1fd2514 --- /dev/null +++ b/src/glsl/tests/matrix-05.glsl @@ -0,0 +1,6 @@ +/* FAIL - non-square matrices are not available in GLSL 1.10 */ + +void main() +{ + mat4x2 m; +} diff --git a/src/glsl/tests/matrix-06.glsl b/src/glsl/tests/matrix-06.glsl new file mode 100644 index 0000000000..0a512b8523 --- /dev/null +++ b/src/glsl/tests/matrix-06.glsl @@ -0,0 +1,6 @@ +/* FAIL - non-square matrices are not available in GLSL 1.10 */ + +void main() +{ + mat4x3 m; +} diff --git a/src/glsl/tests/matrix-07.glsl b/src/glsl/tests/matrix-07.glsl new file mode 100644 index 0000000000..0b59aa69d5 --- /dev/null +++ b/src/glsl/tests/matrix-07.glsl @@ -0,0 +1,27 @@ +/* PASS */ + +uniform mat2 a; +uniform mat2 b; +uniform mat2 c; +uniform mat2 d; +uniform mat3 e; +uniform mat3 f; +uniform mat3 g; +uniform mat3 h; +uniform mat4 i; +uniform mat4 j; +uniform mat4 k; +uniform mat4 l; + +void main() +{ + mat2 x; + mat3 y; + mat4 z; + + x = a * b + c / d; + y = e * f + g / h; + z = i * j + k / l; + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/matrix-08.glsl b/src/glsl/tests/matrix-08.glsl new file mode 100644 index 0000000000..38138d22de --- /dev/null +++ b/src/glsl/tests/matrix-08.glsl @@ -0,0 +1,19 @@ +#version 120 +/* PASS */ + +uniform mat2x3 a; +uniform mat3x2 b; +uniform mat3x3 c; +uniform mat3x3 d; + +void main() +{ + mat3x3 x; + + /* Multiplying a 2 column, 3 row matrix with a 3 column, 2 row matrix + * results in a 3 column, 3 row matrix. + */ + x = (a * b) + c / d; + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/matrix-09.glsl b/src/glsl/tests/matrix-09.glsl new file mode 100644 index 0000000000..18afbcacea --- /dev/null +++ b/src/glsl/tests/matrix-09.glsl @@ -0,0 +1,11 @@ +/* FAIL - matrix-to-matrix constructors are not available in GLSL 1.10 */ + +uniform mat3 a; + +void main() +{ + mat2 m; + + m = mat2(a); + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/matrix-10.glsl b/src/glsl/tests/matrix-10.glsl new file mode 100644 index 0000000000..20b55180cb --- /dev/null +++ b/src/glsl/tests/matrix-10.glsl @@ -0,0 +1,12 @@ +#version 120 +/* PASS */ + +uniform mat3 a; + +void main() +{ + mat2 m; + + m = mat2(a); + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/parameters-01.glsl b/src/glsl/tests/parameters-01.glsl new file mode 100644 index 0000000000..b485106e9d --- /dev/null +++ b/src/glsl/tests/parameters-01.glsl @@ -0,0 +1,11 @@ +/* FAIL: redefinition of a() */ + +void a() +{ + ; +} + +void a() +{ + ; +} diff --git a/src/glsl/tests/parameters-02.glsl b/src/glsl/tests/parameters-02.glsl new file mode 100644 index 0000000000..7ff5f59ab7 --- /dev/null +++ b/src/glsl/tests/parameters-02.glsl @@ -0,0 +1,11 @@ +/* PASS */ + +void a() +{ + ; +} + +void a(float x) +{ + ; +} diff --git a/src/glsl/tests/parameters-03.glsl b/src/glsl/tests/parameters-03.glsl new file mode 100644 index 0000000000..7ec30f80cc --- /dev/null +++ b/src/glsl/tests/parameters-03.glsl @@ -0,0 +1,9 @@ +/* FAIL - x is redeclared in the function body at the same scope as the + * parameter + */ +void a(float x, float y) +{ + float x; + + x = y; +} diff --git a/src/glsl/tests/qualifier-01.glsl b/src/glsl/tests/qualifier-01.glsl new file mode 100644 index 0000000000..54ec3572a2 --- /dev/null +++ b/src/glsl/tests/qualifier-01.glsl @@ -0,0 +1,3 @@ +#version 130 +/* FAIL - inout only allowed in parameter list */ +inout vec4 foo; diff --git a/src/glsl/tests/qualifier-02.glsl b/src/glsl/tests/qualifier-02.glsl new file mode 100644 index 0000000000..b635d52aa2 --- /dev/null +++ b/src/glsl/tests/qualifier-02.glsl @@ -0,0 +1,2 @@ +/* FAIL - in only allowed in parameter list in GLSL 1.10 */ +in foo; diff --git a/src/glsl/tests/qualifier-03.glsl b/src/glsl/tests/qualifier-03.glsl new file mode 100644 index 0000000000..7e448034a7 --- /dev/null +++ b/src/glsl/tests/qualifier-03.glsl @@ -0,0 +1,2 @@ +/* FAIL - out only allowed in parameter list in GLSL 1.10 */ +out vec4 foo; diff --git a/src/glsl/tests/qualifier-04.glsl b/src/glsl/tests/qualifier-04.glsl new file mode 100644 index 0000000000..d03cafc1db --- /dev/null +++ b/src/glsl/tests/qualifier-04.glsl @@ -0,0 +1,3 @@ +#version 130 +/* PASS */ +in vec4 foo; diff --git a/src/glsl/tests/qualifier-05.glsl b/src/glsl/tests/qualifier-05.glsl new file mode 100644 index 0000000000..15281f3384 --- /dev/null +++ b/src/glsl/tests/qualifier-05.glsl @@ -0,0 +1,3 @@ +#version 130 +/* PASS */ +out vec4 foo; diff --git a/src/glsl/tests/qualifier-06.glsl b/src/glsl/tests/qualifier-06.glsl new file mode 100644 index 0000000000..1907a087c8 --- /dev/null +++ b/src/glsl/tests/qualifier-06.glsl @@ -0,0 +1,7 @@ +/* FAIL - in only allowed in parameter list in GLSL 1.10 */ +void main() +{ + in vec4 foo; + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/qualifier-07.glsl b/src/glsl/tests/qualifier-07.glsl new file mode 100644 index 0000000000..12568a57db --- /dev/null +++ b/src/glsl/tests/qualifier-07.glsl @@ -0,0 +1,7 @@ +/* FAIL - out only allowed in parameter list in GLSL 1.10 */ +void main() +{ + out vec4 foo; + + gl_Position = gl_Vertex; +} diff --git a/src/glsl/tests/swiz-01.glsl b/src/glsl/tests/swiz-01.glsl new file mode 100644 index 0000000000..3268fa178c --- /dev/null +++ b/src/glsl/tests/swiz-01.glsl @@ -0,0 +1,11 @@ +/* PASS */ +#version 120 + +void main() +{ + float a; + vec4 b; + + b.x = 6.0; + a = b.x; +} diff --git a/src/glsl/tests/swiz-02.glsl b/src/glsl/tests/swiz-02.glsl new file mode 100644 index 0000000000..e3f043c47b --- /dev/null +++ b/src/glsl/tests/swiz-02.glsl @@ -0,0 +1,11 @@ +/* FAIL: assignment of a vec2 to a float */ +#version 120 + +void main() +{ + float a; + vec4 b; + + b.x = 6.0; + a = b.xy; +} diff --git a/src/glsl/tests/void-01.glsl b/src/glsl/tests/void-01.glsl new file mode 100644 index 0000000000..5719edc0b6 --- /dev/null +++ b/src/glsl/tests/void-01.glsl @@ -0,0 +1,2 @@ +/* FAIL - cannot declare a variable as having type `void' */ +void foo; diff --git a/src/glut/glx/glut_init.c b/src/glut/glx/glut_init.c index 842aefc93c..213819e751 100644 --- a/src/glut/glx/glut_init.c +++ b/src/glut/glx/glut_init.c @@ -44,7 +44,7 @@ unsigned int __glutDisplayMode = GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH; char *__glutDisplayString = NULL; int __glutConnectionFD; -XSizeHints __glutSizeHints = {0}; +XSizeHints __glutSizeHints; int __glutInitWidth = 300, __glutInitHeight = 300; int __glutInitX = -1, __glutInitY = -1; GLboolean __glutForceDirect = GL_FALSE, diff --git a/src/glx/Makefile b/src/glx/Makefile index 9a22d0c547..ba5708ffed 100644 --- a/src/glx/Makefile +++ b/src/glx/Makefile @@ -71,8 +71,9 @@ default: depend $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) # Make libGL $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME): $(OBJECTS) $(GLAPI_LIB) Makefile - $(MKLIB) -o $(GL_LIB) -linker '$(CC)' -ldflags '$(LDFLAGS)' \ - -major 1 -minor 2 $(MKLIB_OPTIONS) \ + $(MKLIB) -o $(GL_LIB) -linker '$(CXX)' -ldflags '$(LDFLAGS)' \ + -major 1 -minor 2 \ + -cplusplus $(MKLIB_OPTIONS) \ -install $(TOP)/$(LIB_DIR) -id $(INSTALL_LIB_DIR)/lib$(GL_LIB).1.dylib \ $(GL_LIB_DEPS) $(OBJECTS) $(GLAPI_LIB) diff --git a/src/mapi/glapi/gen/glX_proto_send.py b/src/mapi/glapi/gen/glX_proto_send.py index 0ca0ff92a6..bd41c9e667 100644 --- a/src/mapi/glapi/gen/glX_proto_send.py +++ b/src/mapi/glapi/gen/glX_proto_send.py @@ -895,13 +895,13 @@ static int NoOp(void) * Create and initialize a new GL dispatch table. The table is initialized * with GLX indirect rendering protocol functions. */ -__GLapi * __glXNewIndirectAPI( void ) +struct _glapi_table * __glXNewIndirectAPI( void ) { - __GLapi *glAPI; + struct _glapi_table *glAPI; GLuint entries; entries = _glapi_get_dispatch_table_size(); - glAPI = (__GLapi *) Xmalloc(entries * sizeof(void *)); + glAPI = (struct _glapi_table *) Xmalloc(entries * sizeof(void *)); /* first, set all entries to point to no-op functions */ { diff --git a/src/mapi/glapi/glapi.h b/src/mapi/glapi/glapi.h index a74884d595..a0bb078106 100644 --- a/src/mapi/glapi/glapi.h +++ b/src/mapi/glapi/glapi.h @@ -44,10 +44,30 @@ #ifndef _GLAPI_H #define _GLAPI_H -#ifndef MAPI_GLAPI_CURRENT -#define MAPI_GLAPI_CURRENT + +/* opengl.dll does not export _glapi_* */ +#if defined(_WIN32) +#define _GLAPI_NO_EXPORTS #endif +#ifdef _GLAPI_NO_EXPORTS +# define _GLAPI_EXPORT +#else /* _GLAPI_NO_EXPORTS */ +# ifdef _WIN32 +# ifdef _GLAPI_DLL_EXPORTS +# define _GLAPI_EXPORT __declspec(dllexport) +# else +# define _GLAPI_EXPORT __declspec(dllimport) +# endif +# elif defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) +# define _GLAPI_EXPORT __attribute__((visibility("default"))) +# else +# define _GLAPI_EXPORT +# endif +#endif /* _GLAPI_NO_EXPORTS */ + + +/* Is this needed? It is incomplete anyway. */ #ifdef USE_MGL_NAMESPACE #define _glapi_set_dispatch _mglapi_set_dispatch #define _glapi_get_dispatch _mglapi_get_dispatch @@ -57,32 +77,106 @@ #define _glapi_Context _mglapi_Context #endif -#include "mapi/u_current.h" #include "glapi/glthread.h" typedef void (*_glapi_proc)(void); +struct _glapi_table; + + +#if defined (GLX_USE_TLS) + +_GLAPI_EXPORT extern __thread struct _glapi_table * _glapi_tls_Dispatch + __attribute__((tls_model("initial-exec"))); + +_GLAPI_EXPORT extern __thread void * _glapi_tls_Context + __attribute__((tls_model("initial-exec"))); + +_GLAPI_EXPORT extern const struct _glapi_table *_glapi_Dispatch; +_GLAPI_EXPORT extern const void *_glapi_Context; + +# define GET_DISPATCH() _glapi_tls_Dispatch +# define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) _glapi_tls_Context + +#else + +_GLAPI_EXPORT extern struct _glapi_table *_glapi_Dispatch; +_GLAPI_EXPORT extern void *_glapi_Context; + +# ifdef THREADS + +# define GET_DISPATCH() \ + (likely(_glapi_Dispatch) ? _glapi_Dispatch : _glapi_get_dispatch()) + +# define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) \ + (likely(_glapi_Context) ? _glapi_Context : _glapi_get_context()) + +# else + +# define GET_DISPATCH() _glapi_Dispatch +# define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) _glapi_Context + +# endif + +#endif /* defined (GLX_USE_TLS) */ + + +void +_glapi_destroy_multithread(void); + -#define GET_DISPATCH() ((struct _glapi_table *) u_current_get()) -#define GET_CURRENT_CONTEXT(C) GLcontext *C = (GLcontext *) u_current_get_user() +_GLAPI_EXPORT void +_glapi_check_multithread(void); -PUBLIC unsigned int + +_GLAPI_EXPORT void +_glapi_set_context(void *context); + + +_GLAPI_EXPORT void * +_glapi_get_context(void); + + +_GLAPI_EXPORT void +_glapi_set_dispatch(struct _glapi_table *dispatch); + + +_GLAPI_EXPORT struct _glapi_table * +_glapi_get_dispatch(void); + + +_GLAPI_EXPORT unsigned int _glapi_get_dispatch_table_size(void); -PUBLIC int +_GLAPI_EXPORT int _glapi_add_dispatch( const char * const * function_names, const char * parameter_signature ); -PUBLIC int +_GLAPI_EXPORT int _glapi_get_proc_offset(const char *funcName); -PUBLIC _glapi_proc +_GLAPI_EXPORT _glapi_proc _glapi_get_proc_address(const char *funcName); -PUBLIC const char * +_GLAPI_EXPORT const char * _glapi_get_proc_name(unsigned int offset); -#endif +_GLAPI_EXPORT unsigned long +_glthread_GetID(void); + + +/* + * These stubs are kept so that the old DRI drivers still load. + */ +_GLAPI_EXPORT void +_glapi_noop_enable_warnings(unsigned char enable); + + +_GLAPI_EXPORT void +_glapi_set_warning_func(_glapi_proc func); + + +#endif /* _GLAPI_H */ diff --git a/src/mapi/glapi/glapi_dispatch.c b/src/mapi/glapi/glapi_dispatch.c index ae59140ad3..7421a36d35 100644 --- a/src/mapi/glapi/glapi_dispatch.c +++ b/src/mapi/glapi/glapi_dispatch.c @@ -37,18 +37,9 @@ * \author Brian Paul <brian@precisioninsight.com> */ -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#include "glapi/mesa.h" -#else -#include "main/glheader.h" -#include "main/compiler.h" -#endif - -#include "glapi/glapi.h" +#include "glapi/glapi_priv.h" #include "glapi/glapitable.h" #include "glapi/glapidispatch.h" -#include "glapi/glthread.h" #if !(defined(USE_X86_ASM) || defined(USE_X86_64_ASM) || defined(USE_SPARC_ASM)) diff --git a/src/mapi/glapi/glapi_entrypoint.c b/src/mapi/glapi/glapi_entrypoint.c index 82c68c27c8..993ccb94c2 100644 --- a/src/mapi/glapi/glapi_entrypoint.c +++ b/src/mapi/glapi/glapi_entrypoint.c @@ -29,15 +29,6 @@ */ -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#include "glapi/mesa.h" -#else -#include "main/glheader.h" -#include "main/compiler.h" -#endif - -#include "glapi/glapi.h" #include "glapi/glapi_priv.h" #include "mapi/u_execmem.h" diff --git a/src/mapi/glapi/glapi_getproc.c b/src/mapi/glapi/glapi_getproc.c index 3c134f929d..dc4905b64e 100644 --- a/src/mapi/glapi/glapi_getproc.c +++ b/src/mapi/glapi/glapi_getproc.c @@ -30,15 +30,6 @@ */ -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#include "glapi/mesa.h" -#else -#include "main/glheader.h" -#include "main/compiler.h" -#endif - -#include "glapi/glapi.h" #include "glapi/glapi_priv.h" #include "glapi/glapitable.h" #include "glapi/glapioffsets.h" diff --git a/src/mapi/glapi/glapi_nop.c b/src/mapi/glapi/glapi_nop.c index 9709551ee7..9b09297150 100644 --- a/src/mapi/glapi/glapi_nop.c +++ b/src/mapi/glapi/glapi_nop.c @@ -38,28 +38,11 @@ -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#include "glapi/mesa.h" -#else -#include "main/compiler.h" -#include "main/glheader.h" -#endif - -#include "glapi/glapi.h" - - -/* - * These stubs are kept so that the old DRI drivers still load. - */ -PUBLIC void -_glapi_noop_enable_warnings(GLboolean enable); +#include "glapi/glapi_priv.h" -PUBLIC void -_glapi_set_warning_func(_glapi_proc func); void -_glapi_noop_enable_warnings(GLboolean enable) +_glapi_noop_enable_warnings(unsigned char enable) { } diff --git a/src/mapi/glapi/glapi_priv.h b/src/mapi/glapi/glapi_priv.h index 1c2a704211..89f81c723e 100644 --- a/src/mapi/glapi/glapi_priv.h +++ b/src/mapi/glapi/glapi_priv.h @@ -26,9 +26,30 @@ #ifndef _GLAPI_PRIV_H #define _GLAPI_PRIV_H -#include "glthread.h" -#include "glapi.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#include "glapi/mesa.h" +#else /* HAVE_DIX_CONFIG_H */ +#define GL_GLEXT_PROTOTYPES +#include "GL/gl.h" +#include "GL/glext.h" + +#ifndef GL_FIXED +typedef int GLfixed; +typedef int GLclampx; +#endif + +#ifndef GL_OES_EGL_image +typedef void *GLeglImageOES; +#endif + +#endif /* HAVE_DIX_CONFIG_H */ +#include "glapi/glapi.h" /* getproc */ diff --git a/src/mapi/glapi/glthread.c b/src/mapi/glapi/glthread.c index 9dbc0e9a56..00915380f9 100644 --- a/src/mapi/glapi/glthread.c +++ b/src/mapi/glapi/glthread.c @@ -1,4 +1,4 @@ -#include "glthread.h" +#include "glapi/glapi.h" unsigned long _glthread_GetID(void) diff --git a/src/mapi/glapi/glthread.h b/src/mapi/glapi/glthread.h index 54292706ac..fc4ece7c33 100644 --- a/src/mapi/glapi/glthread.h +++ b/src/mapi/glapi/glthread.h @@ -17,7 +17,4 @@ typedef struct u_tsd _glthread_TSD; typedef u_mutex _glthread_Mutex; -PUBLIC unsigned long -_glthread_GetID(void); - -#endif /* THREADS_H */ +#endif /* GLTHREAD_H */ diff --git a/src/mapi/mapi/entry_x86-64_tls.h b/src/mapi/mapi/entry_x86-64_tls.h index d4c9907b89..0f6e8125e8 100644 --- a/src/mapi/mapi/entry_x86-64_tls.h +++ b/src/mapi/mapi/entry_x86-64_tls.h @@ -33,7 +33,7 @@ __asm__(".text"); __asm__("x86_64_current_tls:\n\t" - "movq _glapi_tls_Dispatch@GOTTPOFF(%rip), %rax\n\t" + "movq u_current_table_tls@GOTTPOFF(%rip), %rax\n\t" "ret"); #define STUB_ASM_ENTRY(func) \ @@ -43,7 +43,7 @@ __asm__("x86_64_current_tls:\n\t" func ":" #define STUB_ASM_CODE(slot) \ - "movq _glapi_tls_Dispatch@GOTTPOFF(%rip), %rax\n\t" \ + "movq u_current_table_tls@GOTTPOFF(%rip), %rax\n\t" \ "movq %fs:(%rax), %r11\n\t" \ "jmp *(8 * " slot ")(%r11)" diff --git a/src/mapi/mapi/entry_x86_tls.h b/src/mapi/mapi/entry_x86_tls.h index de0498181d..ff2b9575f6 100644 --- a/src/mapi/mapi/entry_x86_tls.h +++ b/src/mapi/mapi/entry_x86_tls.h @@ -37,7 +37,7 @@ __asm__("x86_current_tls:\n\t" "1:\n\t" "popl %eax\n\t" "addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %eax\n\t" - "movl _glapi_tls_Dispatch@GOTNTPOFF(%eax), %eax\n\t" + "movl u_current_table_tls@GOTNTPOFF(%eax), %eax\n\t" "ret"); #ifndef GLX_X86_READONLY_TEXT diff --git a/src/mapi/mapi/entry_x86_tsd.h b/src/mapi/mapi/entry_x86_tsd.h index d31e0676f0..fbf4ec5497 100644 --- a/src/mapi/mapi/entry_x86_tsd.h +++ b/src/mapi/mapi/entry_x86_tsd.h @@ -41,12 +41,12 @@ __asm__(".text"); func ":" #define STUB_ASM_CODE(slot) \ - "movl _glapi_Dispatch, %eax\n\t" \ + "movl u_current_table, %eax\n\t" \ "testl %eax, %eax\n\t" \ "je 1f\n\t" \ "jmp *(4 * " slot ")(%eax)\n" \ "1:\n\t" \ - "call _glapi_get_dispatch\n\t" \ + "call u_current_get_internal\n\t"\ "jmp *(4 * " slot ")(%eax)" #define MAPI_TMP_STUB_ASM_GCC diff --git a/src/mapi/mapi/mapi.h b/src/mapi/mapi/mapi.h index 8832b3dfb6..c7e43e22e9 100644 --- a/src/mapi/mapi/mapi.h +++ b/src/mapi/mapi/mapi.h @@ -31,26 +31,36 @@ #include "u_compiler.h" +#ifdef _WIN32 +#ifdef MAPI_DLL_EXPORTS +#define MAPI_EXPORT __declspec(dllexport) +#else +#define MAPI_EXPORT __declspec(dllimport) +#endif +#else /* _WIN32 */ +#define MAPI_EXPORT PUBLIC +#endif + typedef void (*mapi_proc)(void); struct mapi_table; -PUBLIC void +MAPI_EXPORT void mapi_init(const char *spec); -PUBLIC mapi_proc +MAPI_EXPORT mapi_proc mapi_get_proc_address(const char *name); -PUBLIC struct mapi_table * +MAPI_EXPORT struct mapi_table * mapi_table_create(void); -PUBLIC void +MAPI_EXPORT void mapi_table_destroy(struct mapi_table *tbl); -PUBLIC void +MAPI_EXPORT void mapi_table_fill(struct mapi_table *tbl, const mapi_proc *procs); -PUBLIC void +MAPI_EXPORT void mapi_table_make_current(const struct mapi_table *tbl); #endif /* _MAPI_H_ */ diff --git a/src/mapi/mapi/u_current.c b/src/mapi/mapi/u_current.c index 91547c4830..ed9ccfe229 100644 --- a/src/mapi/mapi/u_current.c +++ b/src/mapi/mapi/u_current.c @@ -99,25 +99,25 @@ extern void (*__glapi_noop_table[])(void); /*@{*/ #if defined(GLX_USE_TLS) -__thread struct _glapi_table *_glapi_tls_Dispatch +__thread struct mapi_table *u_current_table_tls __attribute__((tls_model("initial-exec"))) - = (struct _glapi_table *) table_noop_array; + = (struct mapi_table *) table_noop_array; -__thread void * _glapi_tls_Context +__thread void *u_current_user_tls __attribute__((tls_model("initial-exec"))); -const struct _glapi_table *_glapi_Dispatch; -const void *_glapi_Context; +const struct mapi_table *u_current_table; +const void *u_current_user; #else -struct _glapi_table *_glapi_Dispatch = - (struct _glapi_table *) table_noop_array; -void *_glapi_Context; +struct mapi_table *u_current_table = + (struct mapi_table *) table_noop_array; +void *u_current_user; #ifdef THREADS -struct u_tsd _gl_DispatchTSD; -static struct u_tsd ContextTSD; +struct u_tsd u_current_table_tsd; +static struct u_tsd u_current_user_tsd; static int ThreadSafe; #endif /* THREADS */ @@ -126,11 +126,11 @@ static int ThreadSafe; void -_glapi_destroy_multithread(void) +u_current_destroy(void) { #if defined(THREADS) && defined(WIN32_THREADS) - u_tsd_destroy(&_gl_DispatchTSD); - u_tsd_destroy(&ContextTSD); + u_tsd_destroy(&u_current_table_tsd); + u_tsd_destroy(&u_current_user_tsd); #endif } @@ -138,10 +138,10 @@ _glapi_destroy_multithread(void) #if defined(THREADS) && !defined(GLX_USE_TLS) static void -_glapi_init_multithread(void) +u_current_init_tsd(void) { - u_tsd_init(&_gl_DispatchTSD); - u_tsd_init(&ContextTSD); + u_tsd_init(&u_current_table_tsd); + u_tsd_init(&u_current_user_tsd); } /** @@ -162,7 +162,7 @@ u_mutex_declare_static(ThreadCheckMutex); * in order to test if multiple threads are being used. */ void -_glapi_check_multithread(void) +u_current_init(void) { static unsigned long knownID; static int firstCall = 1; @@ -172,15 +172,15 @@ _glapi_check_multithread(void) CHECK_MULTITHREAD_LOCK(); if (firstCall) { - _glapi_init_multithread(); + u_current_init_tsd(); knownID = u_thread_self(); firstCall = 0; } else if (knownID != u_thread_self()) { ThreadSafe = 1; - _glapi_set_dispatch(NULL); - _glapi_set_context(NULL); + u_current_set_internal(NULL); + u_current_set_user_internal(NULL); } CHECK_MULTITHREAD_UNLOCK(); } @@ -188,7 +188,7 @@ _glapi_check_multithread(void) #else void -_glapi_check_multithread(void) +u_current_init(void) { } @@ -202,15 +202,17 @@ _glapi_check_multithread(void) * void from the real context pointer type. */ void -_glapi_set_context(void *context) +u_current_set_user_internal(void *ptr) { + u_current_init(); + #if defined(GLX_USE_TLS) - _glapi_tls_Context = context; + u_current_user_tls = ptr; #elif defined(THREADS) - u_tsd_set(&ContextTSD, context); - _glapi_Context = (ThreadSafe) ? NULL : context; + u_tsd_set(&u_current_user_tsd, ptr); + u_current_user = (ThreadSafe) ? NULL : ptr; #else - _glapi_Context = context; + u_current_user = ptr; #endif } @@ -220,16 +222,16 @@ _glapi_set_context(void *context) * void to the real context pointer type. */ void * -_glapi_get_context(void) +u_current_get_user_internal(void) { #if defined(GLX_USE_TLS) - return _glapi_tls_Context; + return u_current_user_tls; #elif defined(THREADS) return (ThreadSafe) - ? u_tsd_get(&ContextTSD) - : _glapi_Context; + ? u_tsd_get(&u_current_user_tsd) + : u_current_user; #else - return _glapi_Context; + return u_current_user; #endif } @@ -239,36 +241,37 @@ _glapi_get_context(void) * table (__glapi_noop_table). */ void -_glapi_set_dispatch(struct _glapi_table *dispatch) +u_current_set_internal(struct mapi_table *tbl) { + u_current_init(); + stub_init_once(); - if (!dispatch) - dispatch = (struct _glapi_table *) table_noop_array; + if (!tbl) + tbl = (struct mapi_table *) table_noop_array; #if defined(GLX_USE_TLS) - _glapi_tls_Dispatch = dispatch; + u_current_table_tls = tbl; #elif defined(THREADS) - u_tsd_set(&_gl_DispatchTSD, (void *) dispatch); - _glapi_Dispatch = (ThreadSafe) ? NULL : dispatch; + u_tsd_set(&u_current_table_tsd, (void *) tbl); + u_current_table = (ThreadSafe) ? NULL : tbl; #else - _glapi_Dispatch = dispatch; + u_current_table = tbl; #endif } /** * Return pointer to current dispatch table for calling thread. */ -struct _glapi_table * -_glapi_get_dispatch(void) +struct mapi_table * +u_current_get_internal(void) { #if defined(GLX_USE_TLS) - return _glapi_tls_Dispatch; + return u_current_table_tls; #elif defined(THREADS) - return (ThreadSafe) - ? (struct _glapi_table *) u_tsd_get(&_gl_DispatchTSD) - : _glapi_Dispatch; + return (struct mapi_table *) ((ThreadSafe) ? + u_tsd_get(&u_current_table_tsd) : (void *) u_current_table); #else - return _glapi_Dispatch; + return u_current_table; #endif } diff --git a/src/mapi/mapi/u_current.h b/src/mapi/mapi/u_current.h index a6256f5b51..62e54c6c93 100644 --- a/src/mapi/mapi/u_current.h +++ b/src/mapi/mapi/u_current.h @@ -1,93 +1,102 @@ #ifndef _U_CURRENT_H_ #define _U_CURRENT_H_ -#include "u_compiler.h" - #ifdef MAPI_GLAPI_CURRENT -#define GLAPI_EXPORT PUBLIC -#else -#define GLAPI_EXPORT -#endif -/* - * Unlike other utility functions, we need to keep the old names (_glapi_*) for - * ABI compatibility. The desired functions are wrappers to the old ones. - */ +#include "glapi/glapi.h" + +/* ugly renames to match glapi.h */ +#define mapi_table _glapi_table + +#define u_current_table_tls _glapi_tls_Dispatch +#define u_current_user_tls _glapi_tls_Context +#define u_current_table _glapi_Dispatch +#define u_current_user _glapi_Context + +#define u_current_destroy _glapi_destroy_multithread +#define u_current_init _glapi_check_multithread +#define u_current_set_internal _glapi_set_dispatch +#define u_current_get_internal _glapi_get_dispatch +#define u_current_set_user_internal _glapi_set_context +#define u_current_get_user_internal _glapi_get_context + +#define u_current_table_tsd _gl_DispatchTSD + +#else /* MAPI_GLAPI_CURRENT */ + +#include "u_compiler.h" -struct _glapi_table; +struct mapi_table; #ifdef GLX_USE_TLS -GLAPI_EXPORT extern __thread struct _glapi_table *_glapi_tls_Dispatch +extern __thread struct mapi_table *u_current_table_tls __attribute__((tls_model("initial-exec"))); -GLAPI_EXPORT extern __thread void *_glapi_tls_Context +extern __thread void *u_current_user_tls __attribute__((tls_model("initial-exec"))); -GLAPI_EXPORT extern const struct _glapi_table *_glapi_Dispatch; -GLAPI_EXPORT extern const void *_glapi_Context; +extern const struct mapi_table *u_current_table; +extern const void *u_current_user; #else /* GLX_USE_TLS */ -GLAPI_EXPORT extern struct _glapi_table *_glapi_Dispatch; -GLAPI_EXPORT extern void *_glapi_Context; +extern struct mapi_table *u_current_table; +extern void *u_current_user; #endif /* GLX_USE_TLS */ -GLAPI_EXPORT void -_glapi_check_multithread(void); - -GLAPI_EXPORT void -_glapi_set_context(void *context); +void +u_current_init(void); -GLAPI_EXPORT void * -_glapi_get_context(void); +void +u_current_destroy(void); -GLAPI_EXPORT void -_glapi_set_dispatch(struct _glapi_table *dispatch); +void +u_current_set_internal(struct mapi_table *tbl); -GLAPI_EXPORT struct _glapi_table * -_glapi_get_dispatch(void); +struct mapi_table * +u_current_get_internal(void); void -_glapi_destroy_multithread(void); - +u_current_set_user_internal(void *ptr); -struct mapi_table; +void * +u_current_get_user_internal(void); static INLINE void u_current_set(const struct mapi_table *tbl) { - _glapi_check_multithread(); - _glapi_set_dispatch((struct _glapi_table *) tbl); + u_current_set_internal((struct mapi_table *) tbl); } static INLINE const struct mapi_table * u_current_get(void) { #ifdef GLX_USE_TLS - return (const struct mapi_table *) _glapi_tls_Dispatch; + return (const struct mapi_table *) u_current_table_tls; #else - return (const struct mapi_table *) (likely(_glapi_Dispatch) ? - _glapi_Dispatch : _glapi_get_dispatch()); + return (likely(u_current_table) ? + (const struct mapi_table *) u_current_table : u_current_get_internal()); #endif } static INLINE void u_current_set_user(void *ptr) { - _glapi_check_multithread(); - _glapi_set_context(ptr); + u_current_set_internal(ptr); } static INLINE void * u_current_get_user(void) { #ifdef GLX_USE_TLS - return _glapi_tls_Context; + return u_current_user_tls; #else - return likely(_glapi_Context) ? _glapi_Context : _glapi_get_context(); + return likely(u_current_user) ? u_current_user : u_current_get_user_internal(); #endif } -#endif /* GLX_USE_TLS */ +#endif /* MAPI_GLAPI_CURRENT */ + +#endif /* _U_CURRENT_H_ */ diff --git a/src/mapi/vgapi/SConscript b/src/mapi/vgapi/SConscript index bf51264ab9..20d7f2744d 100644 --- a/src/mapi/vgapi/SConscript +++ b/src/mapi/vgapi/SConscript @@ -18,6 +18,7 @@ if env['platform'] != 'winddk': env.Append(CPPDEFINES = [ 'MAPI_ABI_HEADER=\\"vgapi/vgapi_tmp.h\\"', + 'MAPI_DLL_EXPORTS', 'KHRONOS_DLL_EXPORTS', ]) diff --git a/src/mesa/Makefile b/src/mesa/Makefile index 7073c92240..ef31fd24f0 100644 --- a/src/mesa/Makefile +++ b/src/mesa/Makefile @@ -42,35 +42,53 @@ MESA_GALLIUM_OBJECTS := $(addprefix $(MESA_OBJ_DIR)/, $(MESA_GALLIUM_OBJECTS)) MESA_INCLUDES := $(INCLUDE_DIRS) ES1_INCLUDES := -I$(TOP)/src/mapi/es1api $(INCLUDE_DIRS) ES2_INCLUDES := -I$(TOP)/src/mapi/es2api $(INCLUDE_DIRS) - +MESA_INCLUDES := -I$(TOP)/src/glsl $(MESA_INCLUDES) +ES1_INCLUDES := -I$(TOP)/src/glsl $(ES1_INCLUDES) +ES2_INCLUDES := -I$(TOP)/src/glsl $(ES2_INCLUDES) +# For symbol_table.h in glsl compiler headers. +MESA_INCLUDES := -I$(TOP)/src/mesa/shader $(MESA_INCLUDES) define mesa-cc-c @mkdir -p $(dir $@) $(CC) -c -o $@ $< $($(1)_CPPFLAGS) $($(1)_INCLUDES) $(CFLAGS) endef +define mesa-cxx-c + @mkdir -p $(dir $@) + $(CXX) -c -o $@ $< $($(1)_CPPFLAGS) $($(1)_INCLUDES) $(CXXFLAGS) +endef + $(MESA_OBJ_DIR)/%.o: %.c $(call mesa-cc-c,MESA) +$(MESA_OBJ_DIR)/%.o: %.cpp + $(call mesa-cxx-c,MESA) + $(MESA_OBJ_DIR)/%.o: %.S $(call mesa-cc-c,MESA) $(ES1_OBJ_DIR)/%.o: %.c $(call mesa-cc-c,ES1) +$(ES1_OBJ_DIR)/%.o: %.cpp + $(call mesa-cxx-c,ES1) + $(ES1_OBJ_DIR)/%.o: %.S $(call mesa-cc-c,ES1) $(ES2_OBJ_DIR)/%.o: %.c $(call mesa-cc-c,ES2) +$(ES2_OBJ_DIR)/%.o: %.cpp + $(call mesa-cxx-c,ES2) + $(ES2_OBJ_DIR)/%.o: %.S $(call mesa-cc-c,ES2) # Default: build dependencies, then asm_subdirs, GLSL built-in lib, # then convenience libs (.a) and finally the device drivers: -default: $(DEPENDS) asm_subdirs glsl_builtin \ +default: $(DEPENDS) asm_subdirs \ $(MESA_LIBS) $(ES1_LIBS) $(ES2_LIBS) driver_subdirs main/api_exec_es1.c: main/APIspec.xml main/es_generator.py main/APIspecutil.py main/APIspec.py @@ -121,12 +139,6 @@ asm_subdirs: ###################################################################### -# GLSL built-in library -glsl_builtin: - (cd slang/library && $(MAKE)) || exit 1 ; - - -###################################################################### # Dependency generation depend: $(ALL_SOURCES) @@ -241,7 +253,6 @@ clean: clean-es1 clean-es2 -rm -f depend depend.bak libmesa.a libmesagallium.a -rm -f drivers/*/*.o -rm -f *.pc - -rm -f slang/library/*_gc.h -@cd drivers/dri && $(MAKE) clean -@cd drivers/x11 && $(MAKE) clean -@cd drivers/osmesa && $(MAKE) clean diff --git a/src/mesa/SConscript b/src/mesa/SConscript index d31b957234..28598f4a17 100644 --- a/src/mesa/SConscript +++ b/src/mesa/SConscript @@ -10,6 +10,7 @@ if env['platform'] != 'winddk': env.Append(CPPPATH = [ '#/src/mapi', + '#/src/glsl', '#/src/mesa', ]) @@ -19,6 +20,7 @@ if env['platform'] != 'winddk': 'BUILD_GL32', # declare gl* as __declspec(dllexport) in Mesa headers 'WIN32_THREADS', # use Win32 thread API ]) + env.Prepend(CPPPATH = ['#src/talloc']) # # Source files @@ -51,6 +53,7 @@ if env['platform'] != 'winddk': 'main/dlist.c', 'main/dlopen.c', 'main/drawpix.c', + 'main/drawtex.c', 'main/enable.c', 'main/enums.c', 'main/eval.c', @@ -104,6 +107,7 @@ if env['platform'] != 'winddk': 'main/texgetimage.c', 'main/teximage.c', 'main/texobj.c', + 'main/texpal.c', 'main/texparam.c', 'main/texrender.c', 'main/texstate.c', @@ -174,6 +178,7 @@ if env['platform'] != 'winddk': 'state_tracker/st_cb_condrender.c', 'state_tracker/st_cb_flush.c', 'state_tracker/st_cb_drawpixels.c', + 'state_tracker/st_cb_drawtex.c', 'state_tracker/st_cb_eglimage.c', 'state_tracker/st_cb_fbo.c', 'state_tracker/st_cb_feedback.c', @@ -201,6 +206,7 @@ if env['platform'] != 'winddk': program_sources = [ 'program/arbprogparse.c', 'program/hash_table.c', + 'program/ir_to_mesa.cpp', 'program/lex.yy.c', 'program/nvfragparse.c', 'program/nvvertparse.c', @@ -221,36 +227,13 @@ if env['platform'] != 'winddk': 'program/symbol_table.c', ] - slang_sources = [ - 'slang/slang_builtin.c', - 'slang/slang_codegen.c', - 'slang/slang_compile.c', - 'slang/slang_compile_function.c', - 'slang/slang_compile_operation.c', - 'slang/slang_compile_struct.c', - 'slang/slang_compile_variable.c', - 'slang/slang_emit.c', - 'slang/slang_ir.c', - 'slang/slang_label.c', - 'slang/slang_link.c', - 'slang/slang_log.c', - 'slang/slang_mem.c', - 'slang/slang_print.c', - 'slang/slang_simplify.c', - 'slang/slang_storage.c', - 'slang/slang_typeinfo.c', - 'slang/slang_vartable.c', - 'slang/slang_utility.c', - ] - mesa_sources = ( main_sources + math_sources + program_sources + vbo_sources + vf_sources + - statetracker_sources + - slang_sources + statetracker_sources ) # @@ -328,8 +311,6 @@ if env['platform'] != 'winddk': # build dir) to the include path env.Append(CPPPATH = [matypes[0].dir]) - SConscript('slang/library/SConscript') - # # Libraries # diff --git a/src/mesa/drivers/dri/Makefile.template b/src/mesa/drivers/dri/Makefile.template index 8cb25439e4..a00018cafa 100644 --- a/src/mesa/drivers/dri/Makefile.template +++ b/src/mesa/drivers/dri/Makefile.template @@ -17,6 +17,7 @@ COMMON_SOURCES = $(COMMON_GALLIUM_SOURCES) \ INCLUDES = $(SHARED_INCLUDES) $(EXPAT_INCLUDES) OBJECTS = $(C_SOURCES:.c=.o) \ + $(CXX_SOURCES:.cpp=.o) \ $(ASM_SOURCES:.S=.o) @@ -33,12 +34,16 @@ SHARED_INCLUDES = \ $(LIBDRM_CFLAGS) CFLAGS += $(API_DEFINES) +CXXFLAGS += $(API_DEFINES) ##### RULES ##### .c.o: $(CC) -c $(INCLUDES) $(CFLAGS) $(DRIVER_DEFINES) $< -o $@ +.cpp.o: + $(CC) -c $(INCLUDES) $(CXXFLAGS) $(DRIVER_DEFINES) $< -o $@ + .S.o: $(CC) -c $(INCLUDES) $(CFLAGS) $(DRIVER_DEFINES) $< -o $@ @@ -54,9 +59,9 @@ lib: symlinks subdirs depend $(LIBNAME): $(OBJECTS) $(MESA_MODULES) $(EXTRA_MODULES) Makefile \ $(TOP)/src/mesa/drivers/dri/Makefile.template $(TOP)/src/mesa/drivers/dri/common/dri_test.o - $(MKLIB) -o $@.tmp -noprefix -linker '$(CC)' -ldflags '$(LDFLAGS)' \ + $(MKLIB) -o $@.tmp -noprefix -linker '$(CXX)' -ldflags '$(LDFLAGS)' \ $(OBJECTS) $(MESA_MODULES) $(EXTRA_MODULES) $(DRI_LIB_DEPS) - $(CC) $(CFLAGS) -o $@.test $(TOP)/src/mesa/drivers/dri/common/dri_test.o $@.tmp $(DRI_LIB_DEPS) + $(CXX) $(CFLAGS) -o $@.test $(TOP)/src/mesa/drivers/dri/common/dri_test.o $@.tmp $(DRI_LIB_DEPS) @rm -f $@.test mv -f $@.tmp $@ diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c index dce84ef0de..a581c6663f 100644 --- a/src/mesa/drivers/dri/common/dri_util.c +++ b/src/mesa/drivers/dri/common/dri_util.c @@ -32,6 +32,7 @@ #include "drm_sarea.h" #include "utils.h" #include "xmlpool.h" +#include "../glsl/glsl_parser_extras.h" PUBLIC const char __dri2ConfigOptions[] = DRI_CONF_BEGIN @@ -707,6 +708,8 @@ static void driDestroyScreen(__DRIscreen *psp) * stream open to the X-server anymore. */ + _mesa_destroy_shader_compiler(); + if (psp->DriverAPI.DestroyScreen) (*psp->DriverAPI.DestroyScreen)(psp); @@ -714,6 +717,9 @@ static void driDestroyScreen(__DRIscreen *psp) (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); (void)drmCloseOnce(psp->fd); + } else { + driDestroyOptionCache(&psp->optionCache); + driDestroyOptionInfo(&psp->optionInfo); } free(psp); @@ -839,7 +845,6 @@ dri2CreateNewScreen(int scrn, int fd, static const __DRIextension *emptyExtensionList[] = { NULL }; __DRIscreen *psp; drmVersionPtr version; - driOptionCache options; if (driDriverAPI.InitScreen2 == NULL) return NULL; @@ -873,8 +878,10 @@ dri2CreateNewScreen(int scrn, int fd, psp->DriverAPI = driDriverAPI; - driParseOptionInfo(&options, __dri2ConfigOptions, __dri2NConfigOptions); - driParseConfigFiles(&psp->optionCache, &options, psp->myNum, "dri2"); + driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, + __dri2NConfigOptions); + driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, + "dri2"); return psp; } diff --git a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h index bc647ff813..5096d22cad 100644 --- a/src/mesa/drivers/dri/common/dri_util.h +++ b/src/mesa/drivers/dri/common/dri_util.h @@ -513,7 +513,11 @@ struct __DRIscreenRec { * * This pointer is never touched by the DRI layer. */ +#ifdef __cplusplus + void *priv; +#else void *private; +#endif /* Extensions provided by the loader. */ const __DRIgetDrawableInfoExtension *getDrawableInfo; @@ -532,6 +536,7 @@ struct __DRIscreenRec { /* The lock actually in use, old sarea or DRI2 */ drmLock *lock; + driOptionCache optionInfo; driOptionCache optionCache; unsigned int api_mask; }; diff --git a/src/mesa/drivers/dri/i915/i830_context.c b/src/mesa/drivers/dri/i915/i830_context.c index d52ea9812f..8ddce6d82a 100644 --- a/src/mesa/drivers/dri/i915/i830_context.c +++ b/src/mesa/drivers/dri/i915/i830_context.c @@ -27,7 +27,6 @@ #include "i830_context.h" #include "main/imports.h" -#include "texmem.h" #include "tnl/tnl.h" #include "tnl/t_vertex.h" #include "tnl/t_context.h" diff --git a/src/mesa/drivers/dri/i915/i915_context.c b/src/mesa/drivers/dri/i915/i915_context.c index b3fe1c05d6..d8715cf026 100644 --- a/src/mesa/drivers/dri/i915/i915_context.c +++ b/src/mesa/drivers/dri/i915/i915_context.c @@ -174,6 +174,8 @@ i915CreateContext(int api, ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; + ctx->Shader.EmitNoIfs = GL_TRUE; + ctx->Const.MaxDrawBuffers = 1; _tnl_init_vertices(ctx, ctx->Const.MaxArrayLockSize + 12, diff --git a/src/mesa/drivers/dri/i915/i915_fragprog.c b/src/mesa/drivers/dri/i915/i915_fragprog.c index f1505dc5e7..4a2e6209d0 100644 --- a/src/mesa/drivers/dri/i915/i915_fragprog.c +++ b/src/mesa/drivers/dri/i915/i915_fragprog.c @@ -143,6 +143,20 @@ src_vector(struct i915_fragment_program *p, } break; + case PROGRAM_OUTPUT: + switch (source->Index) { + case FRAG_RESULT_COLOR: + src = UREG(REG_TYPE_OC, 0); + break; + case FRAG_RESULT_DEPTH: + src = UREG(REG_TYPE_OD, 0); + break; + default: + i915_program_error(p, "Bad source->Index: %d", source->Index); + return 0; + } + break; + /* Various paramters and env values. All emitted to * hardware as program constants. */ @@ -472,6 +486,18 @@ upload_program(struct i915_fragment_program *p) swizzle(tmp, X, X, X, X)); break; + case OPCODE_DP2: + src0 = src_vector(p, &inst->SrcReg[0], program); + src1 = src_vector(p, &inst->SrcReg[1], program); + i915_emit_arith(p, + A0_DP3, + get_result_vector(p, inst), + get_result_flags(inst), 0, + swizzle(src0, X, Y, ZERO, ZERO), + swizzle(src1, X, Y, ZERO, ZERO), + 0); + break; + case OPCODE_DP3: EMIT_2ARG_ARITH(A0_DP3); break; @@ -957,6 +983,41 @@ upload_program(struct i915_fragment_program *p) 0); break; + case OPCODE_SSG: + dst = get_result_vector(p, inst); + flags = get_result_flags(inst); + src0 = src_vector(p, &inst->SrcReg[0], program); + tmp = i915_get_utemp(p); + + /* tmp = (src < 0.0) */ + i915_emit_arith(p, + A0_SLT, + tmp, + flags, 0, + src0, + swizzle(src0, ZERO, ZERO, ZERO, ZERO), + 0); + + /* dst = (0.0 < src) */ + i915_emit_arith(p, + A0_SLT, + dst, + flags, 0, + swizzle(src0, ZERO, ZERO, ZERO, ZERO), + src0, + 0); + + /* dst = (src > 0.0) - (src < 0.0) */ + i915_emit_arith(p, + A0_ADD, + dst, + flags, 0, + dst, + negate(tmp, 1, 1, 1, 1), + 0); + + break; + case OPCODE_SUB: src0 = src_vector(p, &inst->SrcReg[0], program); src1 = src_vector(p, &inst->SrcReg[1], program); diff --git a/src/mesa/drivers/dri/i965/Makefile b/src/mesa/drivers/dri/i965/Makefile index e381a5c714..bea48e1313 100644 --- a/src/mesa/drivers/dri/i965/Makefile +++ b/src/mesa/drivers/dri/i965/Makefile @@ -104,6 +104,11 @@ C_SOURCES = \ $(COMMON_SOURCES) \ $(DRIVER_SOURCES) +CXX_SOURCES = \ + brw_fs.cpp \ + brw_fs_channel_expressions.cpp \ + brw_fs_vector_splitting.cpp + ASM_SOURCES = DRIVER_DEFINES = -I../intel diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c index 6d064b822e..d2b20165f9 100644 --- a/src/mesa/drivers/dri/i965/brw_context.c +++ b/src/mesa/drivers/dri/i965/brw_context.c @@ -144,7 +144,8 @@ GLboolean brwCreateContext( int api, brw->CMD_VF_STATISTICS = CMD_VF_STATISTICS_GM45; brw->CMD_PIPELINE_SELECT = CMD_PIPELINE_SELECT_GM45; brw->has_surface_tile_offset = GL_TRUE; - brw->has_compr4 = GL_TRUE; + if (intel->gen < 6) + brw->has_compr4 = GL_TRUE; brw->has_aa_line_parameters = GL_TRUE; brw->has_pln = GL_TRUE; } else { @@ -153,7 +154,11 @@ GLboolean brwCreateContext( int api, } /* WM maximum threads is number of EUs times number of threads per EU. */ - if (intel->gen == 5) { + if (intel->gen >= 6) { + brw->urb.size = 1024; + brw->vs_max_threads = 60; + brw->wm_max_threads = 80; + } else if (intel->gen == 5) { brw->urb.size = 1024; brw->vs_max_threads = 72; brw->wm_max_threads = 12 * 6; diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h index cc4e6638e8..703a7de78d 100644 --- a/src/mesa/drivers/dri/i965/brw_context.h +++ b/src/mesa/drivers/dri/i965/brw_context.h @@ -179,6 +179,16 @@ struct brw_fragment_program { GLbitfield tex_units_used; }; +struct brw_shader { + struct gl_shader base; + + /** Shader IR transformed for native compile, at link time. */ + struct exec_list *ir; +}; + +struct brw_shader_program { + struct gl_shader_program base; +}; /* Data about a particular attempt to compile a program. Note that * there can be many of these, each in a different GL state @@ -654,7 +664,13 @@ struct brw_context drm_intel_bo *prog_bo; drm_intel_bo *state_bo; - drm_intel_bo *const_bo; + drm_intel_bo *const_bo; /* pull constant buffer. */ + /** + * This is the push constant BO on gen6. + * + * Pre-gen6, push constants live in the CURBE. + */ + drm_intel_bo *push_const_bo; } wm; @@ -686,7 +702,13 @@ struct brw_context #define BRW_PACKCOLOR8888(r,g,b,a) ((r<<24) | (g<<16) | (b<<8) | a) - +struct brw_instruction_info { + char *name; + int nsrc; + int ndst; + GLboolean is_arith; +}; +extern const struct brw_instruction_info brw_opcodes[128]; /*====================================================================== * brw_vtbl.c diff --git a/src/mesa/drivers/dri/i965/brw_defines.h b/src/mesa/drivers/dri/i965/brw_defines.h index f7a68cead7..6b8e9e05d0 100644 --- a/src/mesa/drivers/dri/i965/brw_defines.h +++ b/src/mesa/drivers/dri/i965/brw_defines.h @@ -686,6 +686,9 @@ #define BRW_SAMPLER_MESSAGE_SAMPLE_BIAS_GEN5 1 #define BRW_SAMPLER_MESSAGE_SAMPLE_LOD_GEN5 2 #define BRW_SAMPLER_MESSAGE_SAMPLE_COMPARE_GEN5 3 +#define BRW_SAMPLER_MESSAGE_SAMPLE_DERIVS_GEN5 4 +#define BRW_SAMPLER_MESSAGE_SAMPLE_BIAS_COMPARE_GEN5 5 +#define BRW_SAMPLER_MESSAGE_SAMPLE_LOD_COMPARE_GEN5 6 /* for GEN5 only */ #define BRW_SAMPLER_SIMD_MODE_SIMD4X2 0 diff --git a/src/mesa/drivers/dri/i965/brw_disasm.c b/src/mesa/drivers/dri/i965/brw_disasm.c index d230714536..f74a236834 100644 --- a/src/mesa/drivers/dri/i965/brw_disasm.c +++ b/src/mesa/drivers/dri/i965/brw_disasm.c @@ -159,6 +159,11 @@ char *saturate[2] = { [1] = ".sat" }; +char *accwr[2] = { + [0] = "", + [1] = "AccWrEnable" +}; + char *exec_size[8] = { [0] = "1", [1] = "2", @@ -206,6 +211,7 @@ char *compr_ctrl[4] = { [0] = "", [1] = "sechalf", [2] = "compr", + [3] = "compr4", }; char *dep_ctrl[4] = { @@ -235,6 +241,16 @@ char *reg_encoding[8] = { [7] = "F" }; +int reg_type_size[8] = { + [0] = 4, + [1] = 4, + [2] = 2, + [3] = 2, + [4] = 1, + [5] = 1, + [7] = 4 +}; + char *imm_encoding[8] = { [0] = "UD", [1] = "D", @@ -423,6 +439,11 @@ static int print_opcode (FILE *file, int id) static int reg (FILE *file, GLuint _reg_file, GLuint _reg_nr) { int err = 0; + + /* Clear the Compr4 instruction compression bit. */ + if (_reg_file == BRW_MESSAGE_REGISTER_FILE) + _reg_nr &= ~(1 << 7); + if (_reg_file == BRW_ARCHITECTURE_REGISTER_FILE) { switch (_reg_nr & 0xf0) { case BRW_ARF_NULL: @@ -476,7 +497,8 @@ static int dest (FILE *file, struct brw_instruction *inst) if (err == -1) return 0; if (inst->bits1.da1.dest_subreg_nr) - format (file, ".%d", inst->bits1.da1.dest_subreg_nr); + format (file, ".%d", inst->bits1.da1.dest_subreg_nr / + reg_type_size[inst->bits1.da1.dest_reg_type]); format (file, "<%d>", inst->bits1.da1.dest_horiz_stride); err |= control (file, "dest reg encoding", reg_encoding, inst->bits1.da1.dest_reg_type, NULL); } @@ -484,7 +506,8 @@ static int dest (FILE *file, struct brw_instruction *inst) { string (file, "g[a0"); if (inst->bits1.ia1.dest_subreg_nr) - format (file, ".%d", inst->bits1.ia1.dest_subreg_nr); + format (file, ".%d", inst->bits1.ia1.dest_subreg_nr / + reg_type_size[inst->bits1.ia1.dest_reg_type]); if (inst->bits1.ia1.dest_indirect_offset) format (file, " %d", inst->bits1.ia1.dest_indirect_offset); string (file, "]"); @@ -500,7 +523,8 @@ static int dest (FILE *file, struct brw_instruction *inst) if (err == -1) return 0; if (inst->bits1.da16.dest_subreg_nr) - format (file, ".%d", inst->bits1.da16.dest_subreg_nr); + format (file, ".%d", inst->bits1.da16.dest_subreg_nr / + reg_type_size[inst->bits1.da16.dest_reg_type]); string (file, "<1>"); err |= control (file, "writemask", writemask, inst->bits1.da16.dest_writemask, NULL); err |= control (file, "dest reg encoding", reg_encoding, inst->bits1.da16.dest_reg_type, NULL); @@ -541,7 +565,7 @@ static int src_da1 (FILE *file, GLuint type, GLuint _reg_file, if (err == -1) return 0; if (sub_reg_num) - format (file, ".%d", sub_reg_num); + format (file, ".%d", sub_reg_num / reg_type_size[type]); /* use formal style like spec */ src_align1_region (file, _vert_stride, _width, _horiz_stride); err |= control (file, "src reg encoding", reg_encoding, type, NULL); return err; @@ -595,11 +619,12 @@ static int src_da16 (FILE *file, if (err == -1) return 0; if (_subreg_nr) - format (file, ".%d", _subreg_nr); + /* bit4 for subreg number byte addressing. Make this same meaning as + in da1 case, so output looks consistent. */ + format (file, ".%d", 16 / reg_type_size[_reg_type]); string (file, "<"); err |= control (file, "vert stride", vert_stride, _vert_stride, NULL); string (file, ",4,1>"); - err |= control (file, "src da16 reg type", reg_encoding, _reg_type, NULL); /* * Three kinds of swizzle display: * identity - nothing printed @@ -863,12 +888,25 @@ int brw_disasm (FILE *file, struct brw_instruction *inst, int gen) inst->bits3.math.precision, &space); break; case BRW_MESSAGE_TARGET_SAMPLER: - format (file, " (%d, %d, ", - inst->bits3.sampler.binding_table_index, - inst->bits3.sampler.sampler); - err |= control (file, "sampler target format", sampler_target_format, - inst->bits3.sampler.return_format, NULL); - string (file, ")"); + if (gen >= 5) { + format (file, " (%d, %d, %d, %d)", + inst->bits3.sampler_gen5.binding_table_index, + inst->bits3.sampler_gen5.sampler, + inst->bits3.sampler_gen5.msg_type, + inst->bits3.sampler_gen5.simd_mode); + } else if (0 /* FINISHME: is_g4x */) { + format (file, " (%d, %d)", + inst->bits3.sampler_g4x.binding_table_index, + inst->bits3.sampler_g4x.sampler); + } else { + format (file, " (%d, %d, ", + inst->bits3.sampler.binding_table_index, + inst->bits3.sampler.sampler); + err |= control (file, "sampler target format", + sampler_target_format, + inst->bits3.sampler.return_format, NULL); + string (file, ")"); + } break; case BRW_MESSAGE_TARGET_DATAPORT_READ: if (gen >= 6) { @@ -929,6 +967,11 @@ int brw_disasm (FILE *file, struct brw_instruction *inst, int gen) inst->bits3.urb.used, &space); err |= control (file, "urb complete", urb_complete, inst->bits3.urb.complete, &space); + if (gen >= 5) { + format (file, " mlen %d, rlen %d\n", + inst->bits3.urb_gen5.msg_length, + inst->bits3.urb_gen5.response_length); + } break; case BRW_MESSAGE_TARGET_THREAD_SPAWNER: break; @@ -957,8 +1000,19 @@ int brw_disasm (FILE *file, struct brw_instruction *inst, int gen) err |= control(file, "access mode", access_mode, inst->header.access_mode, &space); err |= control (file, "mask control", mask_ctrl, inst->header.mask_control, &space); err |= control (file, "dependency control", dep_ctrl, inst->header.dependency_control, &space); - err |= control (file, "compression control", compr_ctrl, inst->header.compression_control, &space); + + if (inst->header.compression_control == BRW_COMPRESSION_COMPRESSED && + opcode[inst->header.opcode].ndst > 0 && + inst->bits1.da1.dest_reg_file == BRW_MESSAGE_REGISTER_FILE && + inst->bits1.da1.dest_reg_nr & (1 << 7)) { + format (file, " compr4"); + } else { + err |= control (file, "compression control", compr_ctrl, + inst->header.compression_control, &space); + } err |= control (file, "thread control", thread_ctrl, inst->header.thread_control, &space); + if (gen >= 6) + err |= control (file, "acc write control", accwr, inst->header.acc_wr_control, &space); if (inst->header.opcode == BRW_OPCODE_SEND) err |= control (file, "end of thread", end_of_thread, inst->bits3.generic.end_of_thread, &space); diff --git a/src/mesa/drivers/dri/i965/brw_draw_upload.c b/src/mesa/drivers/dri/i965/brw_draw_upload.c index f07aab86e9..249e874ab1 100644 --- a/src/mesa/drivers/dri/i965/brw_draw_upload.c +++ b/src/mesa/drivers/dri/i965/brw_draw_upload.c @@ -476,7 +476,7 @@ static void brw_emit_vertices(struct brw_context *brw) if (brw->vb.nr_enabled == 0) { BEGIN_BATCH(3); OUT_BATCH((CMD_VERTEX_ELEMENT << 16) | 1); - if (IS_GEN6(intel->intelScreen->deviceID)) { + if (intel->gen >= 6) { OUT_BATCH((0 << GEN6_VE0_INDEX_SHIFT) | GEN6_VE0_VALID | (BRW_SURFACEFORMAT_R32G32B32A32_FLOAT << BRW_VE0_FORMAT_SHIFT) | @@ -553,7 +553,7 @@ static void brw_emit_vertices(struct brw_context *brw) break; } - if (IS_GEN6(intel->intelScreen->deviceID)) { + if (intel->gen >= 6) { OUT_BATCH((i << GEN6_VE0_INDEX_SHIFT) | GEN6_VE0_VALID | (format << BRW_VE0_FORMAT_SHIFT) | diff --git a/src/mesa/drivers/dri/i965/brw_eu.c b/src/mesa/drivers/dri/i965/brw_eu.c index 4e7c1226ad..2ff39e8e64 100644 --- a/src/mesa/drivers/dri/i965/brw_eu.c +++ b/src/mesa/drivers/dri/i965/brw_eu.c @@ -85,6 +85,12 @@ void brw_set_saturate( struct brw_compile *p, GLuint value ) p->current->header.saturate = value; } +void brw_set_acc_write_control(struct brw_compile *p, GLuint value) +{ + if (p->brw->intel.gen >= 6) + p->current->header.acc_wr_control = value; +} + void brw_push_insn_state( struct brw_compile *p ) { assert(p->current != &p->stack[BRW_EU_MAX_INSN_STACK-1]); diff --git a/src/mesa/drivers/dri/i965/brw_eu.h b/src/mesa/drivers/dri/i965/brw_eu.h index ffdddd0a38..c63db16460 100644 --- a/src/mesa/drivers/dri/i965/brw_eu.h +++ b/src/mesa/drivers/dri/i965/brw_eu.h @@ -633,6 +633,8 @@ static INLINE struct brw_reg brw_swizzle( struct brw_reg reg, GLuint z, GLuint w) { + assert(reg.file != BRW_IMMEDIATE_VALUE); + reg.dw1.bits.swizzle = BRW_SWIZZLE4(BRW_GET_SWZ(reg.dw1.bits.swizzle, x), BRW_GET_SWZ(reg.dw1.bits.swizzle, y), BRW_GET_SWZ(reg.dw1.bits.swizzle, z), @@ -650,6 +652,7 @@ static INLINE struct brw_reg brw_swizzle1( struct brw_reg reg, static INLINE struct brw_reg brw_writemask( struct brw_reg reg, GLuint mask ) { + assert(reg.file != BRW_IMMEDIATE_VALUE); reg.dw1.bits.writemask &= mask; return reg; } @@ -657,6 +660,7 @@ static INLINE struct brw_reg brw_writemask( struct brw_reg reg, static INLINE struct brw_reg brw_set_writemask( struct brw_reg reg, GLuint mask ) { + assert(reg.file != BRW_IMMEDIATE_VALUE); reg.dw1.bits.writemask = mask; return reg; } @@ -766,6 +770,7 @@ void brw_set_compression_control( struct brw_compile *p, GLboolean control ); void brw_set_predicate_control_flag_value( struct brw_compile *p, GLuint value ); void brw_set_predicate_control( struct brw_compile *p, GLuint pc ); void brw_set_conditionalmod( struct brw_compile *p, GLuint conditional ); +void brw_set_acc_write_control(struct brw_compile *p, GLuint value); void brw_init_compile( struct brw_context *, struct brw_compile *p ); const GLuint *brw_get_program( struct brw_compile *p, GLuint *sz ); @@ -840,6 +845,7 @@ void brw_ff_sync(struct brw_compile *p, GLboolean eot); void brw_fb_WRITE(struct brw_compile *p, + int dispatch_width, struct brw_reg dest, GLuint msg_reg_nr, struct brw_reg src0, @@ -925,8 +931,8 @@ struct brw_instruction *brw_DO(struct brw_compile *p, struct brw_instruction *brw_WHILE(struct brw_compile *p, struct brw_instruction *patch_insn); -struct brw_instruction *brw_BREAK(struct brw_compile *p); -struct brw_instruction *brw_CONT(struct brw_compile *p); +struct brw_instruction *brw_BREAK(struct brw_compile *p, int pop_count); +struct brw_instruction *brw_CONT(struct brw_compile *p, int pop_count); /* Forward jumps: */ void brw_land_fwd_jump(struct brw_compile *p, diff --git a/src/mesa/drivers/dri/i965/brw_eu_emit.c b/src/mesa/drivers/dri/i965/brw_eu_emit.c index 0d5d17f501..0906150613 100644 --- a/src/mesa/drivers/dri/i965/brw_eu_emit.c +++ b/src/mesa/drivers/dri/i965/brw_eu_emit.c @@ -75,6 +75,8 @@ static void brw_set_dest( struct brw_instruction *insn, else { insn->bits1.da16.dest_subreg_nr = dest.subnr / 16; insn->bits1.da16.dest_writemask = dest.dw1.bits.writemask; + /* even ignored in da16, still need to set as '01' */ + insn->bits1.da16.dest_horiz_stride = 1; } } else { @@ -90,6 +92,8 @@ static void brw_set_dest( struct brw_instruction *insn, } else { insn->bits1.ia16.dest_indirect_offset = dest.dw1.bits.indirect_offset; + /* even ignored in da16, still need to set as '01' */ + insn->bits1.ia16.dest_horiz_stride = 1; } } @@ -368,9 +372,23 @@ static void brw_set_dp_write_message( struct brw_context *brw, GLuint send_commit_msg) { struct intel_context *intel = &brw->intel; - brw_set_src1(insn, brw_imm_d(0)); + brw_set_src1(insn, brw_imm_ud(0)); - if (intel->gen == 5) { + if (intel->gen >= 6) { + insn->bits3.dp_render_cache.binding_table_index = binding_table_index; + insn->bits3.dp_render_cache.msg_control = msg_control; + insn->bits3.dp_render_cache.pixel_scoreboard_clear = pixel_scoreboard_clear; + insn->bits3.dp_render_cache.msg_type = msg_type; + insn->bits3.dp_render_cache.send_commit_msg = send_commit_msg; + insn->bits3.dp_render_cache.header_present = 0; /* XXX */ + insn->bits3.dp_render_cache.response_length = response_length; + insn->bits3.dp_render_cache.msg_length = msg_length; + insn->bits3.dp_render_cache.end_of_thread = end_of_thread; + insn->header.destreg__conditionalmod = BRW_MESSAGE_TARGET_DATAPORT_WRITE; + /* XXX really need below? */ + insn->bits2.send_gen5.sfid = BRW_MESSAGE_TARGET_DATAPORT_WRITE; + insn->bits2.send_gen5.end_of_thread = end_of_thread; + } else if (intel->gen == 5) { insn->bits3.dp_write_gen5.binding_table_index = binding_table_index; insn->bits3.dp_write_gen5.msg_control = msg_control; insn->bits3.dp_write_gen5.pixel_scoreboard_clear = pixel_scoreboard_clear; @@ -759,7 +777,7 @@ void brw_ENDIF(struct brw_compile *p, } } -struct brw_instruction *brw_BREAK(struct brw_compile *p) +struct brw_instruction *brw_BREAK(struct brw_compile *p, int pop_count) { struct brw_instruction *insn; insn = next_insn(p, BRW_OPCODE_BREAK); @@ -770,10 +788,11 @@ struct brw_instruction *brw_BREAK(struct brw_compile *p) insn->header.execution_size = BRW_EXECUTE_8; /* insn->header.mask_control = BRW_MASK_DISABLE; */ insn->bits3.if_else.pad0 = 0; + insn->bits3.if_else.pop_count = pop_count; return insn; } -struct brw_instruction *brw_CONT(struct brw_compile *p) +struct brw_instruction *brw_CONT(struct brw_compile *p, int pop_count) { struct brw_instruction *insn; insn = next_insn(p, BRW_OPCODE_CONTINUE); @@ -784,6 +803,7 @@ struct brw_instruction *brw_CONT(struct brw_compile *p) insn->header.execution_size = BRW_EXECUTE_8; /* insn->header.mask_control = BRW_MASK_DISABLE; */ insn->bits3.if_else.pad0 = 0; + insn->bits3.if_else.pop_count = pop_count; return insn; } @@ -1332,6 +1352,7 @@ void brw_dp_READ_4_vs_relative(struct brw_compile *p, void brw_fb_WRITE(struct brw_compile *p, + int dispatch_width, struct brw_reg dest, GLuint msg_reg_nr, struct brw_reg src0, @@ -1340,22 +1361,40 @@ void brw_fb_WRITE(struct brw_compile *p, GLuint response_length, GLboolean eot) { - struct brw_instruction *insn = next_insn(p, BRW_OPCODE_SEND); - + struct intel_context *intel = &p->brw->intel; + struct brw_instruction *insn; + GLuint msg_control, msg_type; + + insn = next_insn(p, BRW_OPCODE_SEND); insn->header.predicate_control = 0; /* XXX */ - insn->header.compression_control = BRW_COMPRESSION_NONE; - insn->header.destreg__conditionalmod = msg_reg_nr; - + insn->header.compression_control = BRW_COMPRESSION_NONE; + + if (intel->gen >= 6) { + /* headerless version, just submit color payload */ + src0 = brw_message_reg(msg_reg_nr); + + msg_type = BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE_GEN6; + } else { + insn->header.destreg__conditionalmod = msg_reg_nr; + + msg_type = BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE; + } + + if (dispatch_width == 16) + msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE; + else + msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01; + brw_set_dest(insn, dest); brw_set_src0(insn, src0); brw_set_dp_write_message(p->brw, insn, binding_table_index, - BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE, /* msg_control */ - BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE, /* msg_type */ + msg_control, + msg_type, msg_length, 1, /* pixel scoreboard */ - response_length, + response_length, eot, 0 /* send_commit_msg */); } diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp new file mode 100644 index 0000000000..34c5d5262f --- /dev/null +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -0,0 +1,1924 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * + */ + +extern "C" { + +#include <sys/types.h> + +#include "main/macros.h" +#include "main/shaderobj.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/prog_optimize.h" +#include "program/hash_table.h" +#include "brw_context.h" +#include "brw_eu.h" +#include "brw_wm.h" +#include "talloc.h" +} +#include "../glsl/glsl_types.h" +#include "../glsl/ir_optimization.h" +#include "../glsl/ir_print_visitor.h" + +enum register_file { + ARF = BRW_ARCHITECTURE_REGISTER_FILE, + GRF = BRW_GENERAL_REGISTER_FILE, + MRF = BRW_MESSAGE_REGISTER_FILE, + IMM = BRW_IMMEDIATE_VALUE, + FIXED_HW_REG, /* a struct brw_reg */ + UNIFORM, /* prog_data->params[hw_reg] */ + BAD_FILE +}; + +enum fs_opcodes { + FS_OPCODE_FB_WRITE = 256, + FS_OPCODE_RCP, + FS_OPCODE_RSQ, + FS_OPCODE_SQRT, + FS_OPCODE_EXP2, + FS_OPCODE_LOG2, + FS_OPCODE_POW, + FS_OPCODE_SIN, + FS_OPCODE_COS, + FS_OPCODE_DDX, + FS_OPCODE_DDY, + FS_OPCODE_LINTERP, + FS_OPCODE_TEX, + FS_OPCODE_TXB, + FS_OPCODE_TXL, + FS_OPCODE_DISCARD, +}; + +static int using_new_fs = -1; + +struct gl_shader * +brw_new_shader(GLcontext *ctx, GLuint name, GLuint type) +{ + struct brw_shader *shader; + + shader = talloc_zero(NULL, struct brw_shader); + if (shader) { + shader->base.Type = type; + shader->base.Name = name; + _mesa_init_shader(ctx, &shader->base); + } + + return &shader->base; +} + +struct gl_shader_program * +brw_new_shader_program(GLcontext *ctx, GLuint name) +{ + struct brw_shader_program *prog; + prog = talloc_zero(NULL, struct brw_shader_program); + if (prog) { + prog->base.Name = name; + _mesa_init_shader_program(ctx, &prog->base); + } + return &prog->base; +} + +GLboolean +brw_compile_shader(GLcontext *ctx, struct gl_shader *shader) +{ + if (!_mesa_ir_compile_shader(ctx, shader)) + return GL_FALSE; + + return GL_TRUE; +} + +GLboolean +brw_link_shader(GLcontext *ctx, struct gl_shader_program *prog) +{ + if (using_new_fs == -1) + using_new_fs = getenv("INTEL_NEW_FS") != NULL; + + for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { + struct brw_shader *shader = (struct brw_shader *)prog->_LinkedShaders[i]; + + if (using_new_fs && shader->base.Type == GL_FRAGMENT_SHADER) { + void *mem_ctx = talloc_new(NULL); + bool progress; + + if (shader->ir) + talloc_free(shader->ir); + shader->ir = new(shader) exec_list; + clone_ir_list(mem_ctx, shader->ir, shader->base.ir); + + do_mat_op_to_vec(shader->ir); + do_mod_to_fract(shader->ir); + do_div_to_mul_rcp(shader->ir); + do_sub_to_add_neg(shader->ir); + do_explog_to_explog2(shader->ir); + + brw_do_channel_expressions(shader->ir); + brw_do_vector_splitting(shader->ir); + + do { + progress = false; + + progress = do_common_optimization(shader->ir, true) || progress; + } while (progress); + + validate_ir_tree(shader->ir); + + reparent_ir(shader->ir, shader->ir); + talloc_free(mem_ctx); + } + } + + if (!_mesa_ir_link_shader(ctx, prog)) + return GL_FALSE; + + return GL_TRUE; +} + +static int +type_size(const struct glsl_type *type) +{ + unsigned int size, i; + + switch (type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + return type->components(); + case GLSL_TYPE_ARRAY: + /* FINISHME: uniform/varying arrays. */ + return type_size(type->fields.array) * type->length; + case GLSL_TYPE_STRUCT: + size = 0; + for (i = 0; i < type->length; i++) { + size += type_size(type->fields.structure[i].type); + } + return size; + case GLSL_TYPE_SAMPLER: + /* Samplers take up no register space, since they're baked in at + * link time. + */ + return 0; + default: + assert(!"not reached"); + return 0; + } +} + +class fs_reg { +public: + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *node; + + node = talloc_size(ctx, size); + assert(node != NULL); + + return node; + } + + /** Generic unset register constructor. */ + fs_reg() + { + this->file = BAD_FILE; + this->reg = 0; + this->reg_offset = 0; + this->hw_reg = -1; + this->negate = 0; + this->abs = 0; + } + + /** Immediate value constructor. */ + fs_reg(float f) + { + this->file = IMM; + this->reg = 0; + this->hw_reg = 0; + this->type = BRW_REGISTER_TYPE_F; + this->imm.f = f; + this->negate = 0; + this->abs = 0; + } + + /** Immediate value constructor. */ + fs_reg(int32_t i) + { + this->file = IMM; + this->reg = 0; + this->hw_reg = 0; + this->type = BRW_REGISTER_TYPE_D; + this->imm.i = i; + this->negate = 0; + this->abs = 0; + } + + /** Immediate value constructor. */ + fs_reg(uint32_t u) + { + this->file = IMM; + this->reg = 0; + this->hw_reg = 0; + this->type = BRW_REGISTER_TYPE_UD; + this->imm.u = u; + this->negate = 0; + this->abs = 0; + } + + /** Fixed brw_reg Immediate value constructor. */ + fs_reg(struct brw_reg fixed_hw_reg) + { + this->file = FIXED_HW_REG; + this->fixed_hw_reg = fixed_hw_reg; + this->reg = 0; + this->hw_reg = 0; + this->type = fixed_hw_reg.type; + this->negate = 0; + this->abs = 0; + } + + fs_reg(enum register_file file, int hw_reg); + fs_reg(class fs_visitor *v, const struct glsl_type *type); + + /** Register file: ARF, GRF, MRF, IMM. */ + enum register_file file; + /** Abstract register number. 0 = fixed hw reg */ + int reg; + /** Offset within the abstract register. */ + int reg_offset; + /** HW register number. Generally unset until register allocation. */ + int hw_reg; + /** Register type. BRW_REGISTER_TYPE_* */ + int type; + bool negate; + bool abs; + struct brw_reg fixed_hw_reg; + + /** Value for file == BRW_IMMMEDIATE_FILE */ + union { + int32_t i; + uint32_t u; + float f; + } imm; +}; + +static const fs_reg reg_undef; +static const fs_reg reg_null(ARF, BRW_ARF_NULL); + +class fs_inst : public exec_node { +public: + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *node; + + node = talloc_zero_size(ctx, size); + assert(node != NULL); + + return node; + } + + void init() + { + this->opcode = BRW_OPCODE_NOP; + this->saturate = false; + this->conditional_mod = BRW_CONDITIONAL_NONE; + this->predicated = false; + this->sampler = 0; + this->shadow_compare = false; + } + + fs_inst() + { + init(); + } + + fs_inst(int opcode) + { + init(); + this->opcode = opcode; + } + + fs_inst(int opcode, fs_reg dst, fs_reg src0) + { + init(); + this->opcode = opcode; + this->dst = dst; + this->src[0] = src0; + } + + fs_inst(int opcode, fs_reg dst, fs_reg src0, fs_reg src1) + { + init(); + this->opcode = opcode; + this->dst = dst; + this->src[0] = src0; + this->src[1] = src1; + } + + fs_inst(int opcode, fs_reg dst, fs_reg src0, fs_reg src1, fs_reg src2) + { + init(); + this->opcode = opcode; + this->dst = dst; + this->src[0] = src0; + this->src[1] = src1; + this->src[2] = src2; + } + + int opcode; /* BRW_OPCODE_* or FS_OPCODE_* */ + fs_reg dst; + fs_reg src[3]; + bool saturate; + bool predicated; + int conditional_mod; /**< BRW_CONDITIONAL_* */ + + int mlen; /** SEND message length */ + int sampler; + bool shadow_compare; + + /** @{ + * Annotation for the generated IR. One of the two can be set. + */ + ir_instruction *ir; + const char *annotation; + /** @} */ +}; + +class fs_visitor : public ir_visitor +{ +public: + + fs_visitor(struct brw_wm_compile *c, struct brw_shader *shader) + { + this->c = c; + this->p = &c->func; + this->brw = p->brw; + this->intel = &brw->intel; + this->ctx = &intel->ctx; + this->mem_ctx = talloc_new(NULL); + this->shader = shader; + this->fail = false; + this->next_abstract_grf = 1; + this->variable_ht = hash_table_ctor(0, + hash_table_pointer_hash, + hash_table_pointer_compare); + + this->frag_color = NULL; + this->frag_data = NULL; + this->frag_depth = NULL; + this->first_non_payload_grf = 0; + + this->current_annotation = NULL; + this->annotation_string = NULL; + this->annotation_ir = NULL; + } + ~fs_visitor() + { + talloc_free(this->mem_ctx); + hash_table_dtor(this->variable_ht); + } + + fs_reg *variable_storage(ir_variable *var); + + void visit(ir_variable *ir); + void visit(ir_assignment *ir); + void visit(ir_dereference_variable *ir); + void visit(ir_dereference_record *ir); + void visit(ir_dereference_array *ir); + void visit(ir_expression *ir); + void visit(ir_texture *ir); + void visit(ir_if *ir); + void visit(ir_constant *ir); + void visit(ir_swizzle *ir); + void visit(ir_return *ir); + void visit(ir_loop *ir); + void visit(ir_loop_jump *ir); + void visit(ir_discard *ir); + void visit(ir_call *ir); + void visit(ir_function *ir); + void visit(ir_function_signature *ir); + + fs_inst *emit(fs_inst inst); + void assign_curb_setup(); + void assign_urb_setup(); + void assign_regs(); + void generate_code(); + void generate_fb_write(fs_inst *inst); + void generate_linterp(fs_inst *inst, struct brw_reg dst, + struct brw_reg *src); + void generate_tex(fs_inst *inst, struct brw_reg dst, struct brw_reg src); + void generate_math(fs_inst *inst, struct brw_reg dst, struct brw_reg *src); + void generate_discard(fs_inst *inst); + + void emit_dummy_fs(); + void emit_interpolation(); + void emit_pinterp(int location); + void emit_fb_writes(); + + struct brw_reg interp_reg(int location, int channel); + + struct brw_context *brw; + struct intel_context *intel; + GLcontext *ctx; + struct brw_wm_compile *c; + struct brw_compile *p; + struct brw_shader *shader; + void *mem_ctx; + exec_list instructions; + int next_abstract_grf; + struct hash_table *variable_ht; + ir_variable *frag_color, *frag_data, *frag_depth; + int first_non_payload_grf; + + /** @{ debug annotation info */ + const char *current_annotation; + ir_instruction *base_ir; + const char **annotation_string; + ir_instruction **annotation_ir; + /** @} */ + + bool fail; + + /* Result of last visit() method. */ + fs_reg result; + + fs_reg pixel_x; + fs_reg pixel_y; + fs_reg pixel_w; + fs_reg delta_x; + fs_reg delta_y; + fs_reg interp_attrs[64]; + + int grf_used; + +}; + +/** Fixed HW reg constructor. */ +fs_reg::fs_reg(enum register_file file, int hw_reg) +{ + this->file = file; + this->reg = 0; + this->reg_offset = 0; + this->hw_reg = hw_reg; + this->type = BRW_REGISTER_TYPE_F; + this->negate = 0; + this->abs = 0; +} + +/** Automatic reg constructor. */ +fs_reg::fs_reg(class fs_visitor *v, const struct glsl_type *type) +{ + this->file = GRF; + this->reg = v->next_abstract_grf; + this->reg_offset = 0; + v->next_abstract_grf += type_size(type); + this->hw_reg = -1; + this->negate = 0; + this->abs = 0; + + switch (type->base_type) { + case GLSL_TYPE_FLOAT: + this->type = BRW_REGISTER_TYPE_F; + break; + case GLSL_TYPE_INT: + case GLSL_TYPE_BOOL: + this->type = BRW_REGISTER_TYPE_D; + break; + case GLSL_TYPE_UINT: + this->type = BRW_REGISTER_TYPE_UD; + break; + default: + assert(!"not reached"); + this->type = BRW_REGISTER_TYPE_F; + break; + } +} + +fs_reg * +fs_visitor::variable_storage(ir_variable *var) +{ + return (fs_reg *)hash_table_find(this->variable_ht, var); +} + +void +fs_visitor::visit(ir_variable *ir) +{ + fs_reg *reg = NULL; + + if (strcmp(ir->name, "gl_FragColor") == 0) { + this->frag_color = ir; + } else if (strcmp(ir->name, "gl_FragData") == 0) { + this->frag_data = ir; + } else if (strcmp(ir->name, "gl_FragDepth") == 0) { + this->frag_depth = ir; + assert(!"FINISHME: this hangs currently."); + } + + if (ir->mode == ir_var_in) { + reg = &this->interp_attrs[ir->location]; + } + + if (ir->mode == ir_var_uniform) { + const float *vec_values; + int param_index = c->prog_data.nr_params; + + /* FINISHME: This is wildly incomplete. */ + assert(ir->type->is_scalar() || ir->type->is_vector() || + ir->type->is_sampler()); + + const struct gl_program *fp = &this->brw->fragment_program->Base; + /* Our support for uniforms is piggy-backed on the struct + * gl_fragment_program, because that's where the values actually + * get stored, rather than in some global gl_shader_program uniform + * store. + */ + vec_values = fp->Parameters->ParameterValues[ir->location]; + for (unsigned int i = 0; i < ir->type->vector_elements; i++) { + c->prog_data.param[c->prog_data.nr_params++] = &vec_values[i]; + } + + reg = new(this->mem_ctx) fs_reg(UNIFORM, param_index); + } + + if (!reg) + reg = new(this->mem_ctx) fs_reg(this, ir->type); + + hash_table_insert(this->variable_ht, reg, ir); +} + +void +fs_visitor::visit(ir_dereference_variable *ir) +{ + fs_reg *reg = variable_storage(ir->var); + this->result = *reg; +} + +void +fs_visitor::visit(ir_dereference_record *ir) +{ + assert(!"FINISHME"); +} + +void +fs_visitor::visit(ir_dereference_array *ir) +{ + ir_constant *index; + int element_size; + + ir->array->accept(this); + index = ir->array_index->as_constant(); + + if (ir->type->is_matrix()) { + element_size = ir->type->vector_elements; + } else { + element_size = type_size(ir->type); + } + + if (index) { + assert(this->result.file == UNIFORM || + (this->result.file == GRF && + this->result.reg != 0)); + this->result.reg_offset += index->value.i[0] * element_size; + } else { + assert(!"FINISHME: non-constant matrix column"); + } +} + +void +fs_visitor::visit(ir_expression *ir) +{ + unsigned int operand; + fs_reg op[2], temp; + fs_reg result; + fs_inst *inst; + + for (operand = 0; operand < ir->get_num_operands(); operand++) { + ir->operands[operand]->accept(this); + if (this->result.file == BAD_FILE) { + ir_print_visitor v; + printf("Failed to get tree for expression operand:\n"); + ir->operands[operand]->accept(&v); + this->fail = true; + } + op[operand] = this->result; + + /* Matrix expression operands should have been broken down to vector + * operations already. + */ + assert(!ir->operands[operand]->type->is_matrix()); + /* And then those vector operands should have been broken down to scalar. + */ + assert(!ir->operands[operand]->type->is_vector()); + } + + /* Storage for our result. If our result goes into an assignment, it will + * just get copy-propagated out, so no worries. + */ + this->result = fs_reg(this, ir->type); + + switch (ir->operation) { + case ir_unop_logic_not: + emit(fs_inst(BRW_OPCODE_ADD, this->result, op[0], fs_reg(-1))); + break; + case ir_unop_neg: + op[0].negate = ~op[0].negate; + this->result = op[0]; + break; + case ir_unop_abs: + op[0].abs = true; + this->result = op[0]; + break; + case ir_unop_sign: + temp = fs_reg(this, ir->type); + + emit(fs_inst(BRW_OPCODE_MOV, this->result, fs_reg(0.0f))); + + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], fs_reg(0.0f))); + inst->conditional_mod = BRW_CONDITIONAL_G; + inst = emit(fs_inst(BRW_OPCODE_MOV, this->result, fs_reg(1.0f))); + inst->predicated = true; + + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], fs_reg(0.0f))); + inst->conditional_mod = BRW_CONDITIONAL_L; + inst = emit(fs_inst(BRW_OPCODE_MOV, this->result, fs_reg(-1.0f))); + inst->predicated = true; + + break; + case ir_unop_rcp: + emit(fs_inst(FS_OPCODE_RCP, this->result, op[0])); + break; + + case ir_unop_exp2: + emit(fs_inst(FS_OPCODE_EXP2, this->result, op[0])); + break; + case ir_unop_log2: + emit(fs_inst(FS_OPCODE_LOG2, this->result, op[0])); + break; + case ir_unop_exp: + case ir_unop_log: + assert(!"not reached: should be handled by ir_explog_to_explog2"); + break; + case ir_unop_sin: + emit(fs_inst(FS_OPCODE_SIN, this->result, op[0])); + break; + case ir_unop_cos: + emit(fs_inst(FS_OPCODE_COS, this->result, op[0])); + break; + + case ir_unop_dFdx: + emit(fs_inst(FS_OPCODE_DDX, this->result, op[0])); + break; + case ir_unop_dFdy: + emit(fs_inst(FS_OPCODE_DDY, this->result, op[0])); + break; + + case ir_binop_add: + emit(fs_inst(BRW_OPCODE_ADD, this->result, op[0], op[1])); + break; + case ir_binop_sub: + assert(!"not reached: should be handled by ir_sub_to_add_neg"); + break; + + case ir_binop_mul: + emit(fs_inst(BRW_OPCODE_MUL, this->result, op[0], op[1])); + break; + case ir_binop_div: + assert(!"not reached: should be handled by ir_div_to_mul_rcp"); + break; + case ir_binop_mod: + assert(!"ir_binop_mod should have been converted to b * fract(a/b)"); + break; + + case ir_binop_less: + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_L; + emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1))); + break; + case ir_binop_greater: + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_G; + emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1))); + break; + case ir_binop_lequal: + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_LE; + emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1))); + break; + case ir_binop_gequal: + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_GE; + emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1))); + break; + case ir_binop_equal: + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_Z; + emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1))); + break; + case ir_binop_nequal: + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_NZ; + emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1))); + break; + + case ir_binop_logic_xor: + emit(fs_inst(BRW_OPCODE_XOR, this->result, op[0], op[1])); + break; + + case ir_binop_logic_or: + emit(fs_inst(BRW_OPCODE_OR, this->result, op[0], op[1])); + break; + + case ir_binop_logic_and: + emit(fs_inst(BRW_OPCODE_AND, this->result, op[0], op[1])); + break; + + case ir_binop_dot: + case ir_binop_cross: + case ir_unop_any: + assert(!"not reached: should be handled by brw_channel_expressions"); + break; + + case ir_unop_sqrt: + emit(fs_inst(FS_OPCODE_SQRT, this->result, op[0])); + break; + + case ir_unop_rsq: + emit(fs_inst(FS_OPCODE_RSQ, this->result, op[0])); + break; + + case ir_unop_i2f: + case ir_unop_b2f: + case ir_unop_b2i: + emit(fs_inst(BRW_OPCODE_MOV, this->result, op[0])); + break; + case ir_unop_f2i: + emit(fs_inst(BRW_OPCODE_RNDZ, this->result, op[0])); + break; + case ir_unop_f2b: + case ir_unop_i2b: + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], fs_reg(0.0f))); + inst->conditional_mod = BRW_CONDITIONAL_NZ; + + case ir_unop_trunc: + emit(fs_inst(BRW_OPCODE_RNDD, this->result, op[0])); + break; + case ir_unop_ceil: + op[0].negate = ~op[0].negate; + inst = emit(fs_inst(BRW_OPCODE_RNDD, this->result, op[0])); + this->result.negate = true; + break; + case ir_unop_floor: + inst = emit(fs_inst(BRW_OPCODE_RNDD, this->result, op[0])); + break; + case ir_unop_fract: + inst = emit(fs_inst(BRW_OPCODE_FRC, this->result, op[0])); + break; + + case ir_binop_min: + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_L; + + inst = emit(fs_inst(BRW_OPCODE_SEL, this->result, op[0], op[1])); + inst->predicated = true; + break; + case ir_binop_max: + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_G; + + inst = emit(fs_inst(BRW_OPCODE_SEL, this->result, op[0], op[1])); + inst->predicated = true; + break; + + case ir_binop_pow: + inst = emit(fs_inst(FS_OPCODE_POW, this->result, op[0], op[1])); + break; + + case ir_unop_bit_not: + case ir_unop_u2f: + case ir_binop_lshift: + case ir_binop_rshift: + case ir_binop_bit_and: + case ir_binop_bit_xor: + case ir_binop_bit_or: + assert(!"GLSL 1.30 features unsupported"); + break; + } +} + +void +fs_visitor::visit(ir_assignment *ir) +{ + struct fs_reg l, r; + int i; + int write_mask; + fs_inst *inst; + + /* FINISHME: arrays on the lhs */ + ir->lhs->accept(this); + l = this->result; + + ir->rhs->accept(this); + r = this->result; + + /* FINISHME: This should really set to the correct maximal writemask for each + * FINISHME: component written (in the loops below). This case can only + * FINISHME: occur for matrices, arrays, and structures. + */ + if (ir->write_mask == 0) { + assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector()); + write_mask = WRITEMASK_XYZW; + } else { + assert(ir->lhs->type->is_vector() || ir->lhs->type->is_scalar()); + write_mask = ir->write_mask; + } + + assert(l.file != BAD_FILE); + assert(r.file != BAD_FILE); + + if (ir->condition) { + /* Get the condition bool into the predicate. */ + ir->condition->accept(this); + inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, fs_reg(0))); + inst->conditional_mod = BRW_CONDITIONAL_NZ; + } + + for (i = 0; i < type_size(ir->lhs->type); i++) { + if (i >= 4 || (write_mask & (1 << i))) { + inst = emit(fs_inst(BRW_OPCODE_MOV, l, r)); + if (ir->condition) + inst->predicated = true; + } + l.reg_offset++; + r.reg_offset++; + } +} + +void +fs_visitor::visit(ir_texture *ir) +{ + int base_mrf = 2; + fs_inst *inst = NULL; + unsigned int mlen = 0; + + ir->coordinate->accept(this); + fs_reg coordinate = this->result; + + if (ir->projector) { + fs_reg inv_proj = fs_reg(this, glsl_type::float_type); + + ir->projector->accept(this); + emit(fs_inst(FS_OPCODE_RCP, inv_proj, this->result)); + + fs_reg proj_coordinate = fs_reg(this, ir->coordinate->type); + for (unsigned int i = 0; i < ir->coordinate->type->vector_elements; i++) { + emit(fs_inst(BRW_OPCODE_MUL, proj_coordinate, coordinate, inv_proj)); + coordinate.reg_offset++; + proj_coordinate.reg_offset++; + } + proj_coordinate.reg_offset = 0; + + coordinate = proj_coordinate; + } + + for (mlen = 0; mlen < ir->coordinate->type->vector_elements; mlen++) { + emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), coordinate)); + coordinate.reg_offset++; + } + + /* Pre-Ironlake, the 8-wide sampler always took u,v,r. */ + if (intel->gen < 5) + mlen = 3; + + if (ir->shadow_comparitor) { + /* For shadow comparisons, we have to supply u,v,r. */ + mlen = 3; + + ir->shadow_comparitor->accept(this); + emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result)); + mlen++; + } + + /* Do we ever want to handle writemasking on texture samples? Is it + * performance relevant? + */ + fs_reg dst = fs_reg(this, glsl_type::vec4_type); + + switch (ir->op) { + case ir_tex: + inst = emit(fs_inst(FS_OPCODE_TEX, dst, fs_reg(MRF, base_mrf))); + break; + case ir_txb: + ir->lod_info.bias->accept(this); + emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result)); + mlen++; + + inst = emit(fs_inst(FS_OPCODE_TXB, dst, fs_reg(MRF, base_mrf))); + break; + case ir_txl: + ir->lod_info.lod->accept(this); + emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result)); + mlen++; + + inst = emit(fs_inst(FS_OPCODE_TXL, dst, fs_reg(MRF, base_mrf))); + break; + case ir_txd: + case ir_txf: + assert(!"GLSL 1.30 features unsupported"); + break; + } + + this->result = dst; + + if (ir->shadow_comparitor) + inst->shadow_compare = true; + inst->mlen = mlen; +} + +void +fs_visitor::visit(ir_swizzle *ir) +{ + ir->val->accept(this); + fs_reg val = this->result; + + fs_reg result = fs_reg(this, ir->type); + this->result = result; + + for (unsigned int i = 0; i < ir->type->vector_elements; i++) { + fs_reg channel = val; + int swiz = 0; + + switch (i) { + case 0: + swiz = ir->mask.x; + break; + case 1: + swiz = ir->mask.y; + break; + case 2: + swiz = ir->mask.z; + break; + case 3: + swiz = ir->mask.w; + break; + } + + channel.reg_offset += swiz; + emit(fs_inst(BRW_OPCODE_MOV, result, channel)); + result.reg_offset++; + } +} + +void +fs_visitor::visit(ir_discard *ir) +{ + assert(ir->condition == NULL); /* FINISHME */ + + emit(fs_inst(FS_OPCODE_DISCARD)); +} + +void +fs_visitor::visit(ir_constant *ir) +{ + fs_reg reg(this, ir->type); + this->result = reg; + + for (unsigned int i = 0; i < ir->type->vector_elements; i++) { + switch (ir->type->base_type) { + case GLSL_TYPE_FLOAT: + emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg(ir->value.f[i]))); + break; + case GLSL_TYPE_UINT: + emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg(ir->value.u[i]))); + break; + case GLSL_TYPE_INT: + emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg(ir->value.i[i]))); + break; + case GLSL_TYPE_BOOL: + emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg((int)ir->value.b[i]))); + break; + default: + assert(!"Non-float/uint/int/bool constant"); + } + reg.reg_offset++; + } +} + +void +fs_visitor::visit(ir_if *ir) +{ + fs_inst *inst; + + /* Don't point the annotation at the if statement, because then it plus + * the then and else blocks get printed. + */ + this->base_ir = ir->condition; + + /* Generate the condition into the condition code. */ + ir->condition->accept(this); + inst = emit(fs_inst(BRW_OPCODE_MOV, fs_reg(brw_null_reg()), this->result)); + inst->conditional_mod = BRW_CONDITIONAL_NZ; + + inst = emit(fs_inst(BRW_OPCODE_IF)); + inst->predicated = true; + + foreach_iter(exec_list_iterator, iter, ir->then_instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + this->base_ir = ir; + + ir->accept(this); + } + + if (!ir->else_instructions.is_empty()) { + emit(fs_inst(BRW_OPCODE_ELSE)); + + foreach_iter(exec_list_iterator, iter, ir->else_instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + this->base_ir = ir; + + ir->accept(this); + } + } + + emit(fs_inst(BRW_OPCODE_ENDIF)); +} + +void +fs_visitor::visit(ir_loop *ir) +{ + assert(!ir->from); + assert(!ir->to); + assert(!ir->increment); + assert(!ir->counter); + + emit(fs_inst(BRW_OPCODE_DO)); + + /* Start a safety counter. If the user messed up their loop + * counting, we don't want to hang the GPU. + */ + fs_reg max_iter = fs_reg(this, glsl_type::int_type); + emit(fs_inst(BRW_OPCODE_MOV, max_iter, fs_reg(10000))); + + foreach_iter(exec_list_iterator, iter, ir->body_instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + fs_inst *inst; + + this->base_ir = ir; + ir->accept(this); + + /* Check the maximum loop iters counter. */ + inst = emit(fs_inst(BRW_OPCODE_ADD, max_iter, max_iter, fs_reg(-1))); + inst->conditional_mod = BRW_CONDITIONAL_Z; + + inst = emit(fs_inst(BRW_OPCODE_BREAK)); + inst->predicated = true; + } + + emit(fs_inst(BRW_OPCODE_WHILE)); +} + +void +fs_visitor::visit(ir_loop_jump *ir) +{ + switch (ir->mode) { + case ir_loop_jump::jump_break: + emit(fs_inst(BRW_OPCODE_BREAK)); + break; + case ir_loop_jump::jump_continue: + emit(fs_inst(BRW_OPCODE_CONTINUE)); + break; + } +} + +void +fs_visitor::visit(ir_call *ir) +{ + assert(!"FINISHME"); +} + +void +fs_visitor::visit(ir_return *ir) +{ + assert(!"FINISHME"); +} + +void +fs_visitor::visit(ir_function *ir) +{ + /* Ignore function bodies other than main() -- we shouldn't see calls to + * them since they should all be inlined before we get to ir_to_mesa. + */ + if (strcmp(ir->name, "main") == 0) { + const ir_function_signature *sig; + exec_list empty; + + sig = ir->matching_signature(&empty); + + assert(sig); + + foreach_iter(exec_list_iterator, iter, sig->body) { + ir_instruction *ir = (ir_instruction *)iter.get(); + this->base_ir = ir; + + ir->accept(this); + } + } +} + +void +fs_visitor::visit(ir_function_signature *ir) +{ + assert(!"not reached"); + (void)ir; +} + +fs_inst * +fs_visitor::emit(fs_inst inst) +{ + fs_inst *list_inst = new(mem_ctx) fs_inst; + *list_inst = inst; + + list_inst->annotation = this->current_annotation; + list_inst->ir = this->base_ir; + + this->instructions.push_tail(list_inst); + + return list_inst; +} + +/** Emits a dummy fragment shader consisting of magenta for bringup purposes. */ +void +fs_visitor::emit_dummy_fs() +{ + /* Everyone's favorite color. */ + emit(fs_inst(BRW_OPCODE_MOV, + fs_reg(MRF, 2), + fs_reg(1.0f))); + emit(fs_inst(BRW_OPCODE_MOV, + fs_reg(MRF, 3), + fs_reg(0.0f))); + emit(fs_inst(BRW_OPCODE_MOV, + fs_reg(MRF, 4), + fs_reg(1.0f))); + emit(fs_inst(BRW_OPCODE_MOV, + fs_reg(MRF, 5), + fs_reg(0.0f))); + + fs_inst *write; + write = emit(fs_inst(FS_OPCODE_FB_WRITE, + fs_reg(0), + fs_reg(0))); +} + +/* The register location here is relative to the start of the URB + * data. It will get adjusted to be a real location before + * generate_code() time. + */ +struct brw_reg +fs_visitor::interp_reg(int location, int channel) +{ + int regnr = location * 2 + channel / 2; + int stride = (channel & 1) * 4; + + return brw_vec1_grf(regnr, stride); +} + +/** Emits the interpolation for the varying inputs. */ +void +fs_visitor::emit_interpolation() +{ + struct brw_reg g1_uw = retype(brw_vec1_grf(1, 0), BRW_REGISTER_TYPE_UW); + /* For now, the source regs for the setup URB data will be unset, + * since we don't know until codegen how many push constants we'll + * use, and therefore what the setup URB offset is. + */ + fs_reg src_reg = reg_undef; + + this->current_annotation = "compute pixel centers"; + this->pixel_x = fs_reg(this, glsl_type::uint_type); + this->pixel_y = fs_reg(this, glsl_type::uint_type); + emit(fs_inst(BRW_OPCODE_ADD, + this->pixel_x, + fs_reg(stride(suboffset(g1_uw, 4), 2, 4, 0)), + fs_reg(brw_imm_v(0x10101010)))); + emit(fs_inst(BRW_OPCODE_ADD, + this->pixel_y, + fs_reg(stride(suboffset(g1_uw, 5), 2, 4, 0)), + fs_reg(brw_imm_v(0x11001100)))); + + this->current_annotation = "compute pixel deltas from v0"; + this->delta_x = fs_reg(this, glsl_type::float_type); + this->delta_y = fs_reg(this, glsl_type::float_type); + emit(fs_inst(BRW_OPCODE_ADD, + this->delta_x, + this->pixel_x, + fs_reg(negate(brw_vec1_grf(1, 0))))); + emit(fs_inst(BRW_OPCODE_ADD, + this->delta_y, + this->pixel_y, + fs_reg(brw_vec1_grf(1, 1)))); + + this->current_annotation = "compute pos.w and 1/pos.w"; + /* Compute wpos. Unlike many other varying inputs, we usually need it + * to produce 1/w, and the varying variable wouldn't show up. + */ + fs_reg wpos = fs_reg(this, glsl_type::vec4_type); + this->interp_attrs[FRAG_ATTRIB_WPOS] = wpos; + emit(fs_inst(BRW_OPCODE_MOV, wpos, this->pixel_x)); /* FINISHME: ARB_fcc */ + wpos.reg_offset++; + emit(fs_inst(BRW_OPCODE_MOV, wpos, this->pixel_y)); /* FINISHME: ARB_fcc */ + wpos.reg_offset++; + emit(fs_inst(FS_OPCODE_LINTERP, wpos, this->delta_x, this->delta_y, + interp_reg(FRAG_ATTRIB_WPOS, 2))); + wpos.reg_offset++; + emit(fs_inst(FS_OPCODE_LINTERP, wpos, this->delta_x, this->delta_y, + interp_reg(FRAG_ATTRIB_WPOS, 3))); + /* Compute the pixel W value from wpos.w. */ + this->pixel_w = fs_reg(this, glsl_type::float_type); + emit(fs_inst(FS_OPCODE_RCP, this->pixel_w, wpos)); + + /* FINISHME: gl_FrontFacing */ + + foreach_iter(exec_list_iterator, iter, *this->shader->ir) { + ir_instruction *ir = (ir_instruction *)iter.get(); + ir_variable *var = ir->as_variable(); + + if (!var) + continue; + + if (var->mode != ir_var_in) + continue; + + /* If it's already set up (WPOS), skip. */ + if (var->location == 0) + continue; + + this->current_annotation = talloc_asprintf(this->mem_ctx, + "interpolate %s " + "(FRAG_ATTRIB[%d])", + var->name, + var->location); + emit_pinterp(var->location); + } + this->current_annotation = NULL; +} + +void +fs_visitor::emit_pinterp(int location) +{ + fs_reg interp_attr = fs_reg(this, glsl_type::vec4_type); + this->interp_attrs[location] = interp_attr; + + for (unsigned int i = 0; i < 4; i++) { + struct brw_reg interp = interp_reg(location, i); + emit(fs_inst(FS_OPCODE_LINTERP, + interp_attr, + this->delta_x, + this->delta_y, + fs_reg(interp))); + interp_attr.reg_offset++; + } + interp_attr.reg_offset -= 4; + + for (unsigned int i = 0; i < 4; i++) { + emit(fs_inst(BRW_OPCODE_MUL, + interp_attr, + interp_attr, + this->pixel_w)); + interp_attr.reg_offset++; + } +} + +void +fs_visitor::emit_fb_writes() +{ + this->current_annotation = "FB write"; + + assert(this->frag_color || !"FINISHME: MRT"); + fs_reg color = *(variable_storage(this->frag_color)); + + for (int i = 0; i < 4; i++) { + emit(fs_inst(BRW_OPCODE_MOV, + fs_reg(MRF, 2 + i), + color)); + color.reg_offset++; + } + + emit(fs_inst(FS_OPCODE_FB_WRITE, + fs_reg(0), + fs_reg(0))); + + this->current_annotation = NULL; +} + +void +fs_visitor::generate_fb_write(fs_inst *inst) +{ + GLboolean eot = 1; /* FINISHME: MRT */ + /* FINISHME: AADS */ + + /* Header is 2 regs, g0 and g1 are the contents. g0 will be implied + * move, here's g1. + */ + brw_push_insn_state(p); + brw_set_mask_control(p, BRW_MASK_DISABLE); + brw_set_compression_control(p, BRW_COMPRESSION_NONE); + brw_MOV(p, + brw_message_reg(1), + brw_vec8_grf(1, 0)); + brw_pop_insn_state(p); + + int nr = 2 + 4; + + brw_fb_WRITE(p, + 8, /* dispatch_width */ + retype(vec8(brw_null_reg()), BRW_REGISTER_TYPE_UW), + 0, /* base MRF */ + retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW), + 0, /* FINISHME: MRT target */ + nr, + 0, + eot); +} + +void +fs_visitor::generate_linterp(fs_inst *inst, + struct brw_reg dst, struct brw_reg *src) +{ + struct brw_reg delta_x = src[0]; + struct brw_reg delta_y = src[1]; + struct brw_reg interp = src[2]; + + if (brw->has_pln && + delta_y.nr == delta_x.nr + 1 && + (intel->gen >= 6 || (delta_x.nr & 1) == 0)) { + brw_PLN(p, dst, interp, delta_x); + } else { + brw_LINE(p, brw_null_reg(), interp, delta_x); + brw_MAC(p, dst, suboffset(interp, 1), delta_y); + } +} + +void +fs_visitor::generate_math(fs_inst *inst, + struct brw_reg dst, struct brw_reg *src) +{ + int op; + + switch (inst->opcode) { + case FS_OPCODE_RCP: + op = BRW_MATH_FUNCTION_INV; + break; + case FS_OPCODE_RSQ: + op = BRW_MATH_FUNCTION_RSQ; + break; + case FS_OPCODE_SQRT: + op = BRW_MATH_FUNCTION_SQRT; + break; + case FS_OPCODE_EXP2: + op = BRW_MATH_FUNCTION_EXP; + break; + case FS_OPCODE_LOG2: + op = BRW_MATH_FUNCTION_LOG; + break; + case FS_OPCODE_POW: + op = BRW_MATH_FUNCTION_POW; + break; + case FS_OPCODE_SIN: + op = BRW_MATH_FUNCTION_SIN; + break; + case FS_OPCODE_COS: + op = BRW_MATH_FUNCTION_COS; + break; + default: + assert(!"not reached: unknown math function"); + op = 0; + break; + } + + if (inst->opcode == FS_OPCODE_POW) { + brw_MOV(p, brw_message_reg(3), src[1]); + } + + brw_math(p, dst, + op, + inst->saturate ? BRW_MATH_SATURATE_SATURATE : + BRW_MATH_SATURATE_NONE, + 2, src[0], + BRW_MATH_DATA_VECTOR, + BRW_MATH_PRECISION_FULL); +} + +void +fs_visitor::generate_tex(fs_inst *inst, struct brw_reg dst, struct brw_reg src) +{ + int msg_type = -1; + int rlen = 4; + + if (intel->gen == 5) { + switch (inst->opcode) { + case FS_OPCODE_TEX: + if (inst->shadow_compare) { + msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_COMPARE_GEN5; + } else { + msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_GEN5; + } + break; + case FS_OPCODE_TXB: + if (inst->shadow_compare) { + msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_BIAS_COMPARE_GEN5; + } else { + msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_BIAS_GEN5; + } + break; + } + } else { + switch (inst->opcode) { + case FS_OPCODE_TEX: + /* Note that G45 and older determines shadow compare and dispatch width + * from message length for most messages. + */ + if (inst->shadow_compare) { + msg_type = BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_COMPARE; + } else { + msg_type = BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE; + } + case FS_OPCODE_TXB: + if (inst->shadow_compare) { + assert(!"FINISHME: shadow compare with bias."); + msg_type = BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS; + } else { + msg_type = BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS; + rlen = 8; + } + break; + } + } + assert(msg_type != -1); + + /* g0 header. */ + src.nr--; + + brw_SAMPLE(p, + retype(dst, BRW_REGISTER_TYPE_UW), + src.nr, + retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW), + SURF_INDEX_TEXTURE(inst->sampler), + inst->sampler, + WRITEMASK_XYZW, + msg_type, + rlen, + inst->mlen + 1, + 0, + 1, + BRW_SAMPLER_SIMD_MODE_SIMD8); +} + +void +fs_visitor::generate_discard(fs_inst *inst) +{ + struct brw_reg g0 = retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_UW); + brw_push_insn_state(p); + brw_set_mask_control(p, BRW_MASK_DISABLE); + brw_NOT(p, c->emit_mask_reg, brw_mask_reg(1)); /* IMASK */ + brw_AND(p, g0, c->emit_mask_reg, g0); + brw_pop_insn_state(p); +} + +static void +trivial_assign_reg(int header_size, fs_reg *reg) +{ + if (reg->file == GRF && reg->reg != 0) { + reg->hw_reg = header_size + reg->reg - 1 + reg->reg_offset; + reg->reg = 0; + } +} + +void +fs_visitor::assign_curb_setup() +{ + c->prog_data.first_curbe_grf = c->key.nr_payload_regs; + c->prog_data.curb_read_length = ALIGN(c->prog_data.nr_params, 8) / 8; + + /* Map the offsets in the UNIFORM file to fixed HW regs. */ + foreach_iter(exec_list_iterator, iter, this->instructions) { + fs_inst *inst = (fs_inst *)iter.get(); + + for (unsigned int i = 0; i < 3; i++) { + if (inst->src[i].file == UNIFORM) { + int constant_nr = inst->src[i].hw_reg + inst->src[i].reg_offset; + struct brw_reg brw_reg = brw_vec1_grf(c->prog_data.first_curbe_grf + + constant_nr / 8, + constant_nr % 8); + + inst->src[i].file = FIXED_HW_REG; + inst->src[i].fixed_hw_reg = brw_reg; + } + } + } +} + +void +fs_visitor::assign_urb_setup() +{ + int urb_start = c->prog_data.first_curbe_grf + c->prog_data.curb_read_length; + int interp_reg_nr[FRAG_ATTRIB_MAX]; + + c->prog_data.urb_read_length = 0; + + /* Figure out where each of the incoming setup attributes lands. */ + for (unsigned int i = 0; i < FRAG_ATTRIB_MAX; i++) { + interp_reg_nr[i] = -1; + + if (i != FRAG_ATTRIB_WPOS && + !(brw->fragment_program->Base.InputsRead & BITFIELD64_BIT(i))) + continue; + + /* Each attribute is 4 setup channels, each of which is half a reg. */ + interp_reg_nr[i] = urb_start + c->prog_data.urb_read_length; + c->prog_data.urb_read_length += 2; + } + + /* Map the register numbers for FS_OPCODE_LINTERP so that it uses + * the correct setup input. + */ + foreach_iter(exec_list_iterator, iter, this->instructions) { + fs_inst *inst = (fs_inst *)iter.get(); + + if (inst->opcode != FS_OPCODE_LINTERP) + continue; + + assert(inst->src[2].file == FIXED_HW_REG); + + int location = inst->src[2].fixed_hw_reg.nr / 2; + assert(interp_reg_nr[location] != -1); + inst->src[2].fixed_hw_reg.nr = (interp_reg_nr[location] + + (inst->src[2].fixed_hw_reg.nr & 1)); + } + + this->first_non_payload_grf = urb_start + c->prog_data.urb_read_length; +} + +void +fs_visitor::assign_regs() +{ + int header_size = this->first_non_payload_grf; + int last_grf = 0; + + /* FINISHME: trivial assignment of register numbers */ + foreach_iter(exec_list_iterator, iter, this->instructions) { + fs_inst *inst = (fs_inst *)iter.get(); + + trivial_assign_reg(header_size, &inst->dst); + trivial_assign_reg(header_size, &inst->src[0]); + trivial_assign_reg(header_size, &inst->src[1]); + + last_grf = MAX2(last_grf, inst->dst.hw_reg); + last_grf = MAX2(last_grf, inst->src[0].hw_reg); + last_grf = MAX2(last_grf, inst->src[1].hw_reg); + } + + this->grf_used = last_grf + 1; +} + +static struct brw_reg brw_reg_from_fs_reg(fs_reg *reg) +{ + struct brw_reg brw_reg; + + switch (reg->file) { + case GRF: + case ARF: + case MRF: + brw_reg = brw_vec8_reg(reg->file, + reg->hw_reg, 0); + brw_reg = retype(brw_reg, reg->type); + break; + case IMM: + switch (reg->type) { + case BRW_REGISTER_TYPE_F: + brw_reg = brw_imm_f(reg->imm.f); + break; + case BRW_REGISTER_TYPE_D: + brw_reg = brw_imm_d(reg->imm.i); + break; + case BRW_REGISTER_TYPE_UD: + brw_reg = brw_imm_ud(reg->imm.u); + break; + default: + assert(!"not reached"); + break; + } + break; + case FIXED_HW_REG: + brw_reg = reg->fixed_hw_reg; + break; + case BAD_FILE: + /* Probably unused. */ + brw_reg = brw_null_reg(); + break; + case UNIFORM: + assert(!"not reached"); + brw_reg = brw_null_reg(); + break; + } + if (reg->abs) + brw_reg = brw_abs(brw_reg); + if (reg->negate) + brw_reg = negate(brw_reg); + + return brw_reg; +} + +void +fs_visitor::generate_code() +{ + unsigned int annotation_len = 0; + int last_native_inst = 0; + struct brw_instruction *if_stack[16], *loop_stack[16]; + int if_stack_depth = 0, loop_stack_depth = 0; + int if_depth_in_loop[16]; + + if_depth_in_loop[loop_stack_depth] = 0; + + memset(&if_stack, 0, sizeof(if_stack)); + foreach_iter(exec_list_iterator, iter, this->instructions) { + fs_inst *inst = (fs_inst *)iter.get(); + struct brw_reg src[3], dst; + + for (unsigned int i = 0; i < 3; i++) { + src[i] = brw_reg_from_fs_reg(&inst->src[i]); + } + dst = brw_reg_from_fs_reg(&inst->dst); + + brw_set_conditionalmod(p, inst->conditional_mod); + brw_set_predicate_control(p, inst->predicated); + + switch (inst->opcode) { + case BRW_OPCODE_MOV: + brw_MOV(p, dst, src[0]); + break; + case BRW_OPCODE_ADD: + brw_ADD(p, dst, src[0], src[1]); + break; + case BRW_OPCODE_MUL: + brw_MUL(p, dst, src[0], src[1]); + break; + + case BRW_OPCODE_FRC: + brw_FRC(p, dst, src[0]); + break; + case BRW_OPCODE_RNDD: + brw_RNDD(p, dst, src[0]); + break; + case BRW_OPCODE_RNDZ: + brw_RNDZ(p, dst, src[0]); + break; + + case BRW_OPCODE_AND: + brw_AND(p, dst, src[0], src[1]); + break; + case BRW_OPCODE_OR: + brw_OR(p, dst, src[0], src[1]); + break; + case BRW_OPCODE_XOR: + brw_XOR(p, dst, src[0], src[1]); + break; + + case BRW_OPCODE_CMP: + brw_CMP(p, dst, inst->conditional_mod, src[0], src[1]); + break; + case BRW_OPCODE_SEL: + brw_SEL(p, dst, src[0], src[1]); + break; + + case BRW_OPCODE_IF: + assert(if_stack_depth < 16); + if_stack[if_stack_depth] = brw_IF(p, BRW_EXECUTE_8); + if_stack_depth++; + break; + case BRW_OPCODE_ELSE: + if_stack[if_stack_depth - 1] = + brw_ELSE(p, if_stack[if_stack_depth - 1]); + break; + case BRW_OPCODE_ENDIF: + if_stack_depth--; + brw_ENDIF(p , if_stack[if_stack_depth]); + break; + + case BRW_OPCODE_DO: + loop_stack[loop_stack_depth++] = brw_DO(p, BRW_EXECUTE_8); + if_depth_in_loop[loop_stack_depth] = 0; + break; + + case BRW_OPCODE_BREAK: + brw_BREAK(p, if_depth_in_loop[loop_stack_depth]); + brw_set_predicate_control(p, BRW_PREDICATE_NONE); + break; + case BRW_OPCODE_CONTINUE: + brw_CONT(p, if_depth_in_loop[loop_stack_depth]); + brw_set_predicate_control(p, BRW_PREDICATE_NONE); + break; + + case BRW_OPCODE_WHILE: { + struct brw_instruction *inst0, *inst1; + GLuint br = 1; + + if (intel->gen == 5) + br = 2; + + assert(loop_stack_depth > 0); + loop_stack_depth--; + inst0 = inst1 = brw_WHILE(p, loop_stack[loop_stack_depth]); + /* patch all the BREAK/CONT instructions from last BGNLOOP */ + while (inst0 > loop_stack[loop_stack_depth]) { + inst0--; + if (inst0->header.opcode == BRW_OPCODE_BREAK && + inst0->bits3.if_else.jump_count == 0) { + inst0->bits3.if_else.jump_count = br * (inst1 - inst0 + 1); + } + else if (inst0->header.opcode == BRW_OPCODE_CONTINUE && + inst0->bits3.if_else.jump_count == 0) { + inst0->bits3.if_else.jump_count = br * (inst1 - inst0); + } + } + } + break; + + case FS_OPCODE_RCP: + case FS_OPCODE_RSQ: + case FS_OPCODE_SQRT: + case FS_OPCODE_EXP2: + case FS_OPCODE_LOG2: + case FS_OPCODE_POW: + case FS_OPCODE_SIN: + case FS_OPCODE_COS: + generate_math(inst, dst, src); + break; + case FS_OPCODE_LINTERP: + generate_linterp(inst, dst, src); + break; + case FS_OPCODE_TEX: + case FS_OPCODE_TXB: + case FS_OPCODE_TXL: + generate_tex(inst, dst, src[0]); + break; + case FS_OPCODE_DISCARD: + generate_discard(inst); + break; + case FS_OPCODE_FB_WRITE: + generate_fb_write(inst); + break; + default: + if (inst->opcode < (int)ARRAY_SIZE(brw_opcodes)) { + _mesa_problem(ctx, "Unsupported opcode `%s' in FS", + brw_opcodes[inst->opcode].name); + } else { + _mesa_problem(ctx, "Unsupported opcode %d in FS", inst->opcode); + } + this->fail = true; + } + + if (annotation_len < p->nr_insn) { + annotation_len *= 2; + if (annotation_len < 16) + annotation_len = 16; + + this->annotation_string = talloc_realloc(this->mem_ctx, + annotation_string, + const char *, + annotation_len); + this->annotation_ir = talloc_realloc(this->mem_ctx, + annotation_ir, + ir_instruction *, + annotation_len); + } + + for (unsigned int i = last_native_inst; i < p->nr_insn; i++) { + this->annotation_string[i] = inst->annotation; + this->annotation_ir[i] = inst->ir; + } + last_native_inst = p->nr_insn; + } +} + +GLboolean +brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c) +{ + struct brw_compile *p = &c->func; + struct intel_context *intel = &brw->intel; + GLcontext *ctx = &intel->ctx; + struct brw_shader *shader = NULL; + struct gl_shader_program *prog = ctx->Shader.CurrentProgram; + + if (!prog) + return GL_FALSE; + + if (!using_new_fs) + return GL_FALSE; + + for (unsigned int i = 0; i < prog->_NumLinkedShaders; i++) { + if (prog->_LinkedShaders[i]->Type == GL_FRAGMENT_SHADER) { + shader = (struct brw_shader *)prog->_LinkedShaders[i]; + break; + } + } + if (!shader) + return GL_FALSE; + + /* We always use 8-wide mode, at least for now. For one, flow + * control only works in 8-wide. Also, when we're fragment shader + * bound, we're almost always under register pressure as well, so + * 8-wide would save us from the performance cliff of spilling + * regs. + */ + c->dispatch_width = 8; + + if (INTEL_DEBUG & DEBUG_WM) { + printf("GLSL IR for native fragment shader %d:\n", prog->Name); + _mesa_print_ir(shader->ir, NULL); + printf("\n"); + } + + /* Now the main event: Visit the shader IR and generate our FS IR for it. + */ + fs_visitor v(c, shader); + + if (0) { + v.emit_dummy_fs(); + } else { + v.emit_interpolation(); + + /* Generate FS IR for main(). (the visitor only descends into + * functions called "main"). + */ + foreach_iter(exec_list_iterator, iter, *shader->ir) { + ir_instruction *ir = (ir_instruction *)iter.get(); + v.base_ir = ir; + ir->accept(&v); + } + + if (v.fail) + return GL_FALSE; + + v.emit_fb_writes(); + v.assign_curb_setup(); + v.assign_urb_setup(); + v.assign_regs(); + } + + v.generate_code(); + + if (INTEL_DEBUG & DEBUG_WM) { + const char *last_annotation_string = NULL; + ir_instruction *last_annotation_ir = NULL; + + printf("Native code for fragment shader %d:\n", prog->Name); + for (unsigned int i = 0; i < p->nr_insn; i++) { + if (last_annotation_ir != v.annotation_ir[i]) { + last_annotation_ir = v.annotation_ir[i]; + if (last_annotation_ir) { + printf(" "); + last_annotation_ir->print(); + printf("\n"); + } + } + if (last_annotation_string != v.annotation_string[i]) { + last_annotation_string = v.annotation_string[i]; + if (last_annotation_string) + printf(" %s\n", last_annotation_string); + } + brw_disasm(stdout, &p->store[i], intel->gen); + } + printf("\n"); + } + + c->prog_data.total_grf = v.grf_used; + c->prog_data.total_scratch = 0; + + return GL_TRUE; +} diff --git a/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp b/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp new file mode 100644 index 0000000000..d8d58a9467 --- /dev/null +++ b/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp @@ -0,0 +1,365 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file brw_wm_channel_expressions.cpp + * + * Breaks vector operations down into operations on each component. + * + * The 965 fragment shader receives 8 or 16 pixels at a time, so each + * channel of a vector is laid out as 1 or 2 8-float registers. Each + * ALU operation operates on one of those channel registers. As a + * result, there is no value to the 965 fragment shader in tracking + * "vector" expressions in the sense of GLSL fragment shaders, when + * doing a channel at a time may help in constant folding, algebraic + * simplification, and reducing the liveness of channel registers. + * + * The exception to the desire to break everything down to floats is + * texturing. The texture sampler returns a writemasked masked + * 4/8-register sequence containing the texture values. We don't want + * to dispatch to the sampler separately for each channel we need, so + * we do retain the vector types in that case. + */ + +extern "C" { +#include "main/core.h" +#include "brw_wm.h" +} +#include "../glsl/ir.h" +#include "../glsl/ir_expression_flattening.h" +#include "../glsl/glsl_types.h" + +class ir_channel_expressions_visitor : public ir_hierarchical_visitor { +public: + ir_channel_expressions_visitor() + { + this->progress = false; + this->mem_ctx = NULL; + } + + ir_visitor_status visit_leave(ir_assignment *); + + ir_rvalue *get_element(ir_variable *var, unsigned int element); + void assign(ir_assignment *ir, int elem, ir_rvalue *val); + + bool progress; + void *mem_ctx; +}; + +static bool +channel_expressions_predicate(ir_instruction *ir) +{ + ir_expression *expr = ir->as_expression(); + unsigned int i; + + if (!expr) + return false; + + for (i = 0; i < expr->get_num_operands(); i++) { + if (expr->operands[i]->type->is_vector()) + return true; + } + + return false; +} + +extern "C" { +GLboolean +brw_do_channel_expressions(exec_list *instructions) +{ + ir_channel_expressions_visitor v; + + /* Pull out any matrix expression to a separate assignment to a + * temp. This will make our handling of the breakdown to + * operations on the matrix's vector components much easier. + */ + do_expression_flattening(instructions, channel_expressions_predicate); + + visit_list_elements(&v, instructions); + + return v.progress; +} +} + +ir_rvalue * +ir_channel_expressions_visitor::get_element(ir_variable *var, unsigned int elem) +{ + ir_dereference *deref; + + if (var->type->is_scalar()) + return new(mem_ctx) ir_dereference_variable(var); + + assert(elem < var->type->components()); + deref = new(mem_ctx) ir_dereference_variable(var); + return new(mem_ctx) ir_swizzle(deref, elem, 0, 0, 0, 1); +} + +void +ir_channel_expressions_visitor::assign(ir_assignment *ir, int elem, ir_rvalue *val) +{ + ir_dereference *lhs = ir->lhs->clone(mem_ctx, NULL); + ir_assignment *assign; + ir_swizzle *val_swiz; + + /* This assign-of-expression should have been generated by the + * expression flattening visitor (since we never short circit to + * not flatten, even for plain assignments of variables), so the + * writemask is always full. + */ + assert(ir->write_mask == (1 << ir->lhs->type->components()) - 1); + + /* Smear the float across all the channels for the masked write. */ + val_swiz = new(mem_ctx) ir_swizzle(val, 0, 0, 0, 0, + ir->lhs->type->components()); + assign = new(mem_ctx) ir_assignment(lhs, val_swiz, NULL, (1 << elem)); + ir->insert_before(assign); +} + +ir_visitor_status +ir_channel_expressions_visitor::visit_leave(ir_assignment *ir) +{ + ir_expression *expr = ir->rhs->as_expression(); + bool found_vector = false; + unsigned int i, vector_elements = 1; + ir_variable *op_var[2]; + + if (!expr) + return visit_continue; + + if (!this->mem_ctx) + this->mem_ctx = talloc_parent(ir); + + for (i = 0; i < expr->get_num_operands(); i++) { + if (expr->operands[i]->type->is_vector()) { + found_vector = true; + vector_elements = expr->operands[i]->type->vector_elements; + break; + } + } + if (!found_vector) + return visit_continue; + + /* Store the expression operands in temps so we can use them + * multiple times. + */ + for (i = 0; i < expr->get_num_operands(); i++) { + ir_assignment *assign; + ir_dereference *deref; + + assert(!expr->operands[i]->type->is_matrix()); + + op_var[i] = new(mem_ctx) ir_variable(expr->operands[i]->type, + "channel_expressions", + ir_var_temporary); + ir->insert_before(op_var[i]); + + deref = new(mem_ctx) ir_dereference_variable(op_var[i]); + assign = new(mem_ctx) ir_assignment(deref, + expr->operands[i], + NULL); + ir->insert_before(assign); + } + + const glsl_type *element_type = glsl_type::get_instance(ir->lhs->type->base_type, + 1, 1); + + /* OK, time to break down this vector operation. */ + switch (expr->operation) { + case ir_unop_bit_not: + case ir_unop_logic_not: + case ir_unop_neg: + case ir_unop_abs: + case ir_unop_sign: + case ir_unop_rcp: + case ir_unop_rsq: + case ir_unop_sqrt: + case ir_unop_exp: + case ir_unop_log: + case ir_unop_exp2: + case ir_unop_log2: + case ir_unop_f2i: + case ir_unop_i2f: + case ir_unop_f2b: + case ir_unop_b2f: + case ir_unop_i2b: + case ir_unop_b2i: + case ir_unop_u2f: + case ir_unop_trunc: + case ir_unop_ceil: + case ir_unop_floor: + case ir_unop_fract: + case ir_unop_sin: + case ir_unop_cos: + case ir_unop_dFdx: + case ir_unop_dFdy: + for (i = 0; i < vector_elements; i++) { + ir_rvalue *op0 = get_element(op_var[0], i); + + assign(ir, i, new(mem_ctx) ir_expression(expr->operation, + element_type, + op0, + NULL)); + } + break; + + case ir_binop_add: + case ir_binop_sub: + case ir_binop_mul: + case ir_binop_div: + case ir_binop_mod: + case ir_binop_min: + case ir_binop_max: + case ir_binop_pow: + case ir_binop_lshift: + case ir_binop_rshift: + case ir_binop_bit_and: + case ir_binop_bit_xor: + case ir_binop_bit_or: + for (i = 0; i < vector_elements; i++) { + ir_rvalue *op0 = get_element(op_var[0], i); + ir_rvalue *op1 = get_element(op_var[1], i); + + assign(ir, i, new(mem_ctx) ir_expression(expr->operation, + element_type, + op0, + op1)); + } + break; + + case ir_unop_any: { + ir_expression *temp; + temp = new(mem_ctx) ir_expression(ir_binop_logic_or, + element_type, + get_element(op_var[0], 0), + get_element(op_var[0], 1)); + + for (i = 2; i < vector_elements; i++) { + temp = new(mem_ctx) ir_expression(ir_binop_logic_or, + element_type, + get_element(op_var[0], i), + temp); + } + assign(ir, 0, temp); + break; + } + + case ir_binop_dot: { + ir_expression *last = NULL; + for (i = 0; i < vector_elements; i++) { + ir_rvalue *op0 = get_element(op_var[0], i); + ir_rvalue *op1 = get_element(op_var[1], i); + ir_expression *temp; + + temp = new(mem_ctx) ir_expression(ir_binop_mul, + element_type, + op0, + op1); + if (last) { + last = new(mem_ctx) ir_expression(ir_binop_add, + element_type, + temp, + last); + } else { + last = temp; + } + } + assign(ir, 0, last); + break; + } + + case ir_binop_cross: { + for (i = 0; i < vector_elements; i++) { + int swiz0 = (i + 1) % 3; + int swiz1 = (i + 2) % 3; + ir_expression *temp1, *temp2; + + temp1 = new(mem_ctx) ir_expression(ir_binop_mul, + element_type, + get_element(op_var[0], swiz0), + get_element(op_var[1], swiz1)); + + temp2 = new(mem_ctx) ir_expression(ir_binop_mul, + element_type, + get_element(op_var[1], swiz0), + get_element(op_var[0], swiz1)); + + temp2 = new(mem_ctx) ir_expression(ir_unop_neg, + element_type, + temp2, + NULL); + + assign(ir, i, new(mem_ctx) ir_expression(ir_binop_add, + element_type, + temp1, temp2)); + } + break; + } + + case ir_binop_less: + case ir_binop_greater: + case ir_binop_lequal: + case ir_binop_gequal: + case ir_binop_logic_and: + case ir_binop_logic_xor: + case ir_binop_logic_or: + ir->print(); + printf("\n"); + assert(!"not reached: expression operates on scalars only"); + break; + case ir_binop_equal: + case ir_binop_nequal: { + ir_expression *last = NULL; + for (i = 0; i < vector_elements; i++) { + ir_rvalue *op0 = get_element(op_var[0], i); + ir_rvalue *op1 = get_element(op_var[1], i); + ir_expression *temp; + ir_expression_operation join; + + if (expr->operation == ir_binop_equal) + join = ir_binop_logic_and; + else + join = ir_binop_logic_or; + + temp = new(mem_ctx) ir_expression(expr->operation, + element_type, + op0, + op1); + if (last) { + last = new(mem_ctx) ir_expression(join, + element_type, + temp, + last); + } else { + last = temp; + } + } + assign(ir, 0, last); + break; + } + } + + ir->remove(); + this->progress = true; + + return visit_continue; +} diff --git a/src/mesa/drivers/dri/i965/brw_fs_vector_splitting.cpp b/src/mesa/drivers/dri/i965/brw_fs_vector_splitting.cpp new file mode 100644 index 0000000000..00d5c20248 --- /dev/null +++ b/src/mesa/drivers/dri/i965/brw_fs_vector_splitting.cpp @@ -0,0 +1,391 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file brw_wm_vector_splitting.cpp + * + * If a vector is only ever referenced by its components, then + * split those components out to individual variables so they can be + * handled normally by other optimization passes. + * + * This skips vectors in uniforms and varyings, which need to be + * accessible as vectors for their access by the GL. Also, vector + * results of non-variable-derefs in assignments aren't handled + * because to do so we would have to store the vector result to a + * temporary in order to unload each channel, and to do so would just + * loop us back to where we started. For the 965, this is exactly the + * behavior we want for the results of texture lookups, but probably not for + */ + +extern "C" { +#include "main/core.h" +#include "intel_context.h" +} +#include "../glsl/ir.h" +#include "../glsl/ir_visitor.h" +#include "../glsl/ir_print_visitor.h" +#include "../glsl/ir_rvalue_visitor.h" +#include "../glsl/glsl_types.h" + +static bool debug = false; + +class variable_entry : public exec_node +{ +public: + variable_entry(ir_variable *var) + { + this->var = var; + this->whole_vector_access = 0; + this->declaration = false; + this->mem_ctx = NULL; + } + + ir_variable *var; /* The key: the variable's pointer. */ + + /** Number of times the variable is referenced, including assignments. */ + unsigned whole_vector_access; + + bool declaration; /* If the variable had a decl in the instruction stream */ + + ir_variable *components[4]; + + /** talloc_parent(this->var) -- the shader's talloc context. */ + void *mem_ctx; +}; + +class ir_vector_reference_visitor : public ir_hierarchical_visitor { +public: + ir_vector_reference_visitor(void) + { + this->mem_ctx = talloc_new(NULL); + this->variable_list.make_empty(); + } + + ~ir_vector_reference_visitor(void) + { + talloc_free(mem_ctx); + } + + virtual ir_visitor_status visit(ir_variable *); + virtual ir_visitor_status visit(ir_dereference_variable *); + virtual ir_visitor_status visit_enter(ir_swizzle *); + virtual ir_visitor_status visit_enter(ir_assignment *); + virtual ir_visitor_status visit_enter(ir_function_signature *); + + variable_entry *get_variable_entry(ir_variable *var); + + /* List of variable_entry */ + exec_list variable_list; + + void *mem_ctx; +}; + +variable_entry * +ir_vector_reference_visitor::get_variable_entry(ir_variable *var) +{ + assert(var); + + if (!var->type->is_vector()) + return NULL; + + switch (var->mode) { + case ir_var_uniform: + case ir_var_in: + case ir_var_out: + case ir_var_inout: + /* Can't split varyings or uniforms. Function in/outs won't get split + * either, so don't care about the ambiguity. + */ + return NULL; + case ir_var_auto: + case ir_var_temporary: + break; + } + + foreach_iter(exec_list_iterator, iter, this->variable_list) { + variable_entry *entry = (variable_entry *)iter.get(); + if (entry->var == var) + return entry; + } + + variable_entry *entry = new(mem_ctx) variable_entry(var); + this->variable_list.push_tail(entry); + return entry; +} + + +ir_visitor_status +ir_vector_reference_visitor::visit(ir_variable *ir) +{ + variable_entry *entry = this->get_variable_entry(ir); + + if (entry) + entry->declaration = true; + + return visit_continue; +} + +ir_visitor_status +ir_vector_reference_visitor::visit(ir_dereference_variable *ir) +{ + ir_variable *const var = ir->var; + variable_entry *entry = this->get_variable_entry(var); + + if (entry) + entry->whole_vector_access++; + + return visit_continue; +} + +ir_visitor_status +ir_vector_reference_visitor::visit_enter(ir_swizzle *ir) +{ + /* Don't descend into a vector ir_dereference_variable below. */ + if (ir->val->as_dereference_variable() && ir->type->is_scalar()) + return visit_continue_with_parent; + + return visit_continue; +} + +ir_visitor_status +ir_vector_reference_visitor::visit_enter(ir_assignment *ir) +{ + if (ir->lhs->as_dereference_variable() && + ir->rhs->as_dereference_variable() && + !ir->condition) { + /* We'll split copies of a vector to copies of channels, so don't + * descend to the ir_dereference_variables. + */ + return visit_continue_with_parent; + } + if (ir->lhs->as_dereference_variable() && + is_power_of_two(ir->write_mask) && + !ir->condition) { + /* If we're writing just a channel, then channel-splitting the LHS is OK. + */ + ir->rhs->accept(this); + return visit_continue_with_parent; + } + return visit_continue; +} + +ir_visitor_status +ir_vector_reference_visitor::visit_enter(ir_function_signature *ir) +{ + /* We don't want to descend into the function parameters and + * split them, so just accept the body here. + */ + visit_list_elements(this, &ir->body); + return visit_continue_with_parent; +} + +class ir_vector_splitting_visitor : public ir_rvalue_visitor { +public: + ir_vector_splitting_visitor(exec_list *vars) + { + this->variable_list = vars; + } + + virtual ir_visitor_status visit_leave(ir_assignment *); + + void handle_rvalue(ir_rvalue **rvalue); + struct variable_entry *get_splitting_entry(ir_variable *var); + + exec_list *variable_list; + void *mem_ctx; +}; + +struct variable_entry * +ir_vector_splitting_visitor::get_splitting_entry(ir_variable *var) +{ + assert(var); + + if (!var->type->is_vector()) + return NULL; + + foreach_iter(exec_list_iterator, iter, *this->variable_list) { + variable_entry *entry = (variable_entry *)iter.get(); + if (entry->var == var) { + return entry; + } + } + + return NULL; +} + +void +ir_vector_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + ir_swizzle *swiz = (*rvalue)->as_swizzle(); + if (!swiz || !swiz->type->is_scalar()) + return; + + ir_dereference_variable *deref_var = swiz->val->as_dereference_variable(); + if (!deref_var) + return; + + variable_entry *entry = get_splitting_entry(deref_var->var); + if (!entry) + return; + + ir_variable *var = entry->components[swiz->mask.x]; + *rvalue = new(entry->mem_ctx) ir_dereference_variable(var); +} + +ir_visitor_status +ir_vector_splitting_visitor::visit_leave(ir_assignment *ir) +{ + ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable(); + ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable(); + variable_entry *lhs = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL; + variable_entry *rhs = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL; + + if (lhs_deref && rhs_deref && (lhs || rhs) && !ir->condition) { + /* Straight assignment of vector variables. */ + for (unsigned int i = 0; i < ir->rhs->type->vector_elements; i++) { + ir_dereference *new_lhs; + ir_rvalue *new_rhs; + void *mem_ctx = lhs ? lhs->mem_ctx : rhs->mem_ctx; + unsigned int writemask; + + if (lhs) { + new_lhs = new(mem_ctx) ir_dereference_variable(lhs->components[i]); + writemask = (ir->write_mask >> i) & 1; + } else { + new_lhs = ir->lhs->clone(mem_ctx, NULL); + writemask = ir->write_mask & (1 << i); + } + + if (rhs) { + new_rhs = new(mem_ctx) ir_dereference_variable(rhs->components[i]); + /* If we're writing into a writemask, smear it out to that channel. */ + if (!lhs) + new_rhs = new(mem_ctx) ir_swizzle(new_rhs, i, i, i, i, i + 1); + } else { + new_rhs = new(mem_ctx) ir_swizzle(ir->rhs->clone(mem_ctx, NULL), + i, i, i, i, 1); + } + + ir->insert_before(new(mem_ctx) ir_assignment(new_lhs, + new_rhs, + NULL, writemask)); + } + ir->remove(); + } else if (lhs) { + int elem = -1; + + switch (ir->write_mask) { + case (1 << 0): + elem = 0; + break; + case (1 << 1): + elem = 1; + break; + case (1 << 2): + elem = 2; + break; + case (1 << 3): + elem = 3; + break; + default: + ir->print(); + assert(!"not reached: non-channelwise dereference of LHS."); + } + + ir->lhs = new(mem_ctx) ir_dereference_variable(lhs->components[elem]); + ir->write_mask = (1 << 0); + + handle_rvalue(&ir->rhs); + ir->rhs = new(mem_ctx) ir_swizzle(ir->rhs, + elem, elem, elem, elem, 1); + } else { + handle_rvalue(&ir->rhs); + } + + handle_rvalue(&ir->condition); + + return visit_continue; +} + +extern "C" { +bool +brw_do_vector_splitting(exec_list *instructions) +{ + ir_vector_reference_visitor refs; + + visit_list_elements(&refs, instructions); + + /* Trim out variables we can't split. */ + foreach_iter(exec_list_iterator, iter, refs.variable_list) { + variable_entry *entry = (variable_entry *)iter.get(); + + if (debug) { + printf("vector %s@%p: decl %d, whole_access %d\n", + entry->var->name, (void *) entry->var, entry->declaration, + entry->whole_vector_access); + } + + if (!entry->declaration || entry->whole_vector_access) { + entry->remove(); + } + } + + if (refs.variable_list.is_empty()) + return false; + + void *mem_ctx = talloc_new(NULL); + + /* Replace the decls of the vectors to be split with their split + * components. + */ + foreach_iter(exec_list_iterator, iter, refs.variable_list) { + variable_entry *entry = (variable_entry *)iter.get(); + const struct glsl_type *type; + type = glsl_type::get_instance(entry->var->type->base_type, 1, 1); + + entry->mem_ctx = talloc_parent(entry->var); + + for (unsigned int i = 0; i < entry->var->type->vector_elements; i++) { + const char *name = talloc_asprintf(mem_ctx, "%s_%c", + entry->var->name, + "xyzw"[i]); + + entry->components[i] = new(entry->mem_ctx) ir_variable(type, name, + ir_var_temporary); + entry->var->insert_before(entry->components[i]); + } + + entry->var->remove(); + } + + ir_vector_splitting_visitor split(&refs.variable_list); + visit_list_elements(&split, instructions); + + talloc_free(mem_ctx); + + return true; +} +} diff --git a/src/mesa/drivers/dri/i965/brw_misc_state.c b/src/mesa/drivers/dri/i965/brw_misc_state.c index 572175f463..6eeaba7772 100644 --- a/src/mesa/drivers/dri/i965/brw_misc_state.c +++ b/src/mesa/drivers/dri/i965/brw_misc_state.c @@ -281,7 +281,7 @@ static void emit_depthbuffer(struct brw_context *brw) } assert(region->tiling != I915_TILING_X); - if (IS_GEN6(intel->intelScreen->deviceID)) + if (intel->gen >= 6) assert(region->tiling != I915_TILING_NONE); BEGIN_BATCH(len); @@ -295,7 +295,7 @@ static void emit_depthbuffer(struct brw_context *brw) I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH((BRW_SURFACE_MIPMAPLAYOUT_BELOW << 1) | - ((region->pitch - 1) << 6) | + ((region->width - 1) << 6) | ((region->height - 1) << 19)); OUT_BATCH(0); diff --git a/src/mesa/drivers/dri/i965/brw_optimize.c b/src/mesa/drivers/dri/i965/brw_optimize.c index 8aa6fb6cc6..cbed2bd5cb 100644 --- a/src/mesa/drivers/dri/i965/brw_optimize.c +++ b/src/mesa/drivers/dri/i965/brw_optimize.c @@ -32,12 +32,7 @@ #include "brw_defines.h" #include "brw_eu.h" -static const struct { - char *name; - int nsrc; - int ndst; - GLboolean is_arith; -} inst_opcode[128] = { +const struct brw_instruction_info brw_opcodes[128] = { [BRW_OPCODE_MOV] = { .name = "mov", .nsrc = 1, .ndst = 1, .is_arith = 1 }, [BRW_OPCODE_FRC] = { .name = "frc", .nsrc = 1, .ndst = 1, .is_arith = 1 }, [BRW_OPCODE_RNDU] = { .name = "rndu", .nsrc = 1, .ndst = 1, .is_arith = 1 }, @@ -94,7 +89,7 @@ static const struct { static INLINE GLboolean brw_is_arithmetic_inst(const struct brw_instruction *inst) { - return inst_opcode[inst->header.opcode].is_arith; + return brw_opcodes[inst->header.opcode].is_arith; } static const GLuint inst_stride[7] = { @@ -122,7 +117,7 @@ brw_is_grf_written(const struct brw_instruction *inst, int reg_index, int size, int gen) { - if (inst_opcode[inst->header.opcode].ndst == 0) + if (brw_opcodes[inst->header.opcode].ndst == 0) return GL_FALSE; if (inst->bits1.da1.dest_address_mode != BRW_ADDRESS_DIRECT) @@ -161,20 +156,19 @@ brw_is_grf_written(const struct brw_instruction *inst, return left < right; } -/* Specific path for message register since we need to handle the compr4 case */ -static INLINE GLboolean -brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size) +static GLboolean +brw_is_mrf_written_alu(const struct brw_instruction *inst, + int reg_index, int size) { - if (inst_opcode[inst->header.opcode].ndst == 0) + if (brw_opcodes[inst->header.opcode].ndst == 0) return GL_FALSE; - if (inst->bits1.da1.dest_address_mode != BRW_ADDRESS_DIRECT) - if (inst->bits1.ia1.dest_reg_file == BRW_MESSAGE_REGISTER_FILE) - return GL_TRUE; - if (inst->bits1.da1.dest_reg_file != BRW_MESSAGE_REGISTER_FILE) return GL_FALSE; + if (inst->bits1.da1.dest_address_mode != BRW_ADDRESS_DIRECT) + return GL_TRUE; + const int reg_start = reg_index * REG_SIZE; const int reg_end = reg_start + size; @@ -188,8 +182,6 @@ brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size) if (is_compr4 && inst->header.execution_size != BRW_EXECUTE_16) return GL_TRUE; - GLboolean is_written = GL_FALSE; - /* Here we write mrf_{i} and mrf_{i+4}. So we read two times 8 elements */ if (is_compr4) { const int length = 8 * type_size * inst->bits1.da1.dest_horiz_stride; @@ -210,7 +202,8 @@ brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size) const int left1 = MAX2(write_start1, reg_start); const int right1 = MIN2(write_end1, reg_end); - is_written = left0 < right0 || left1 < right1; + if (left0 < right0 || left1 < right1) + return GL_TRUE; } else { int length; @@ -223,25 +216,41 @@ brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size) + inst->bits1.da1.dest_subreg_nr; const int write_end = write_start + length; const int left = MAX2(write_start, reg_start); - const int right = MIN2(write_end, reg_end);; + const int right = MIN2(write_end, reg_end); - is_written = left < right; + if (left < right) + return GL_TRUE; } - /* SEND may perform an implicit mov to a mrf register */ - if (is_written == GL_FALSE && - inst->header.opcode == BRW_OPCODE_SEND && - inst->bits1.da1.src0_reg_file != 0) { + return GL_FALSE; +} - const int mrf_start = inst->header.destreg__conditionalmod; - const int write_start = mrf_start * REG_SIZE; - const int write_end = write_start + REG_SIZE; - const int left = MAX2(write_start, reg_start); - const int right = MIN2(write_end, reg_end);; - is_written = left < right; - } +/* SEND may perform an implicit mov to a mrf register */ +static GLboolean brw_is_mrf_written_send(const struct brw_instruction *inst, + int reg_index, int size) +{ + + const int reg_start = reg_index * REG_SIZE; + const int reg_end = reg_start + size; + const int mrf_start = inst->header.destreg__conditionalmod; + const int write_start = mrf_start * REG_SIZE; + const int write_end = write_start + REG_SIZE; + const int left = MAX2(write_start, reg_start); + const int right = MIN2(write_end, reg_end); + + if (inst->header.opcode != BRW_OPCODE_SEND || + inst->bits1.da1.src0_reg_file == 0) + return GL_FALSE; - return is_written; + return left < right; +} + +/* Specific path for message register since we need to handle the compr4 case */ +static INLINE GLboolean +brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size) +{ + return (brw_is_mrf_written_alu(inst, reg_index, size) || + brw_is_mrf_written_send(inst, reg_index, size)); } static INLINE GLboolean @@ -284,7 +293,7 @@ static INLINE GLboolean brw_is_grf_read(const struct brw_instruction *inst, int reg_index, int size) { int i, j; - if (inst_opcode[inst->header.opcode].nsrc == 0) + if (brw_opcodes[inst->header.opcode].nsrc == 0) return GL_FALSE; /* Look at first source. We must take into account register regions to @@ -292,7 +301,7 @@ brw_is_grf_read(const struct brw_instruction *inst, int reg_index, int size) * since we do not take into account the fact that some complete registers * may be skipped */ - if (inst_opcode[inst->header.opcode].nsrc >= 1) { + if (brw_opcodes[inst->header.opcode].nsrc >= 1) { if (inst->bits2.da1.src0_address_mode != BRW_ADDRESS_DIRECT) if (inst->bits1.ia1.src0_reg_file == BRW_GENERAL_REGISTER_FILE) @@ -327,7 +336,7 @@ brw_is_grf_read(const struct brw_instruction *inst, int reg_index, int size) } /* Second src register */ - if (inst_opcode[inst->header.opcode].nsrc >= 2) { + if (brw_opcodes[inst->header.opcode].nsrc >= 2) { if (inst->bits3.da1.src1_address_mode != BRW_ADDRESS_DIRECT) if (inst->bits1.ia1.src1_reg_file == BRW_GENERAL_REGISTER_FILE) diff --git a/src/mesa/drivers/dri/i965/brw_program.c b/src/mesa/drivers/dri/i965/brw_program.c index 4b08d2599b..bc152204a4 100644 --- a/src/mesa/drivers/dri/i965/brw_program.c +++ b/src/mesa/drivers/dri/i965/brw_program.c @@ -36,6 +36,7 @@ #include "program/program.h" #include "program/programopt.h" #include "tnl/tnl.h" +#include "talloc.h" #include "brw_context.h" #include "brw_wm.h" @@ -114,10 +115,7 @@ shader_error(GLcontext *ctx, struct gl_program *prog, const char *msg) shader = _mesa_lookup_shader_program(ctx, prog->Id); if (shader) { - if (shader->InfoLog) { - free(shader->InfoLog); - } - shader->InfoLog = _mesa_strdup(msg); + shader->InfoLog = talloc_strdup_append(shader->InfoLog, msg); shader->LinkStatus = GL_FALSE; } } @@ -170,6 +168,9 @@ static GLboolean brwProgramStringNotify( GLcontext *ctx, * See piglit glsl-{vs,fs}-functions-[23] tests. */ for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + int r; + if (prog->Instructions[i].Opcode == OPCODE_CAL) { shader_error(ctx, prog, "i965 driver doesn't yet support uninlined function " @@ -177,16 +178,28 @@ static GLboolean brwProgramStringNotify( GLcontext *ctx, "the end of the function to work around it.\n"); return GL_FALSE; } - if (prog->Instructions[i].DstReg.RelAddr && - prog->Instructions[i].DstReg.File == PROGRAM_INPUT) { + + if (prog->Instructions[i].Opcode == OPCODE_RET) { shader_error(ctx, prog, - "Variable indexing of shader inputs unsupported\n"); + "i965 driver doesn't yet support \"return\" " + "from main().\n"); return GL_FALSE; } - if (prog->Instructions[i].DstReg.RelAddr && + + for (r = 0; r < _mesa_num_inst_src_regs(inst->Opcode); r++) { + if (prog->Instructions[i].SrcReg[r].RelAddr && + prog->Instructions[i].SrcReg[r].File == PROGRAM_INPUT) { + shader_error(ctx, prog, + "Variable indexing of shader inputs unsupported\n"); + return GL_FALSE; + } + } + + if (target == GL_FRAGMENT_PROGRAM_ARB && + prog->Instructions[i].DstReg.RelAddr && prog->Instructions[i].DstReg.File == PROGRAM_OUTPUT) { shader_error(ctx, prog, - "Variable indexing of shader outputs unsupported\n"); + "Variable indexing of FS outputs unsupported\n"); return GL_FALSE; } if (target == GL_FRAGMENT_PROGRAM_ARB) { @@ -218,5 +231,10 @@ void brwInitFragProgFuncs( struct dd_function_table *functions ) functions->DeleteProgram = brwDeleteProgram; functions->IsProgramNative = brwIsProgramNative; functions->ProgramStringNotify = brwProgramStringNotify; + + functions->NewShader = brw_new_shader; + functions->NewShaderProgram = brw_new_shader_program; + functions->CompileShader = brw_compile_shader; + functions->LinkShader = brw_link_shader; } diff --git a/src/mesa/drivers/dri/i965/brw_state.h b/src/mesa/drivers/dri/i965/brw_state.h index af08446f2d..c5d296b129 100644 --- a/src/mesa/drivers/dri/i965/brw_state.h +++ b/src/mesa/drivers/dri/i965/brw_state.h @@ -107,6 +107,7 @@ extern const struct brw_tracked_state gen6_sf_vp; extern const struct brw_tracked_state gen6_urb; extern const struct brw_tracked_state gen6_viewport_state; extern const struct brw_tracked_state gen6_vs_state; +extern const struct brw_tracked_state gen6_wm_constants; extern const struct brw_tracked_state gen6_wm_state; /*********************************************************************** diff --git a/src/mesa/drivers/dri/i965/brw_state_upload.c b/src/mesa/drivers/dri/i965/brw_state_upload.c index f92a19c2aa..a0c130557e 100644 --- a/src/mesa/drivers/dri/i965/brw_state_upload.c +++ b/src/mesa/drivers/dri/i965/brw_state_upload.c @@ -35,7 +35,6 @@ #include "brw_state.h" #include "intel_batchbuffer.h" #include "intel_buffers.h" -#include "intel_chipset.h" /* This is used to initialize brw->state.atoms[]. We could use this * list directly except for a single atom, brw_constant_buffer, which @@ -129,7 +128,7 @@ const struct brw_tracked_state *gen6_atoms[] = &gen6_cc_state_pointers, &brw_vs_constants, /* Before vs_surfaces and constant_buffer */ - &brw_wm_constants, /* Before wm_surfaces and constant_buffer */ + &gen6_wm_constants, /* Before wm_surfaces and constant_buffer */ &brw_vs_surfaces, /* must do before unit */ &brw_wm_constant_surface, /* must do before wm surfaces/bind bo */ @@ -351,7 +350,7 @@ void brw_validate_state( struct brw_context *brw ) brw_add_validated_bo(brw, intel->batch->buf); - if (IS_GEN6(intel->intelScreen->deviceID)) { + if (intel->gen >= 6) { atoms = gen6_atoms; num_atoms = ARRAY_SIZE(gen6_atoms); } else { @@ -425,7 +424,7 @@ void brw_upload_state(struct brw_context *brw) const struct brw_tracked_state **atoms; int num_atoms; - if (IS_GEN6(intel->intelScreen->deviceID)) { + if (intel->gen >= 6) { atoms = gen6_atoms; num_atoms = ARRAY_SIZE(gen6_atoms); } else { diff --git a/src/mesa/drivers/dri/i965/brw_structs.h b/src/mesa/drivers/dri/i965/brw_structs.h index 2fde42a706..2a118e01c5 100644 --- a/src/mesa/drivers/dri/i965/brw_structs.h +++ b/src/mesa/drivers/dri/i965/brw_structs.h @@ -750,7 +750,7 @@ struct gen6_depth_stencil_state } ds1; struct { - GLuint pad0:25; + GLuint pad0:26; GLuint depth_write_enable:1; GLuint depth_test_func:3; GLuint pad1:1; @@ -1305,13 +1305,14 @@ struct brw_instruction GLuint access_mode:1; GLuint mask_control:1; GLuint dependency_control:2; - GLuint compression_control:2; + GLuint compression_control:2; /* gen6: quater control */ GLuint thread_control:2; GLuint predicate_control:4; GLuint predicate_inverse:1; GLuint execution_size:3; GLuint destreg__conditionalmod:4; /* destreg - send, conditionalmod - others */ - GLuint pad0:2; + GLuint acc_wr_control:1; + GLuint cmpt_control:1; GLuint debug_control:1; GLuint saturate:1; } header; @@ -1359,7 +1360,7 @@ struct brw_instruction GLuint dest_writemask:4; GLuint dest_subreg_nr:1; GLuint dest_reg_nr:8; - GLuint pad1:2; + GLuint dest_horiz_stride:2; GLuint dest_address_mode:1; } da16; @@ -1373,7 +1374,7 @@ struct brw_instruction GLuint dest_writemask:4; GLint dest_indirect_offset:6; GLuint dest_subreg_nr:3; - GLuint pad1:2; + GLuint dest_horiz_stride:2; GLuint dest_address_mode:1; } ia16; } bits1; diff --git a/src/mesa/drivers/dri/i965/brw_vs.c b/src/mesa/drivers/dri/i965/brw_vs.c index 9a832af9a9..9f90e1e5e5 100644 --- a/src/mesa/drivers/dri/i965/brw_vs.c +++ b/src/mesa/drivers/dri/i965/brw_vs.c @@ -75,10 +75,10 @@ static void do_vs_prog( struct brw_context *brw, c.prog_data.outputs_written |= BITFIELD64_BIT(VERT_RESULT_TEX0 + i); } - if (0) - _mesa_print_program(&c.vp->program.Base); - - + if (0) { + _mesa_fprint_program_opt(stdout, &c.vp->program.Base, PROG_PRINT_DEBUG, + GL_TRUE); + } /* Emit GEN4 code. */ diff --git a/src/mesa/drivers/dri/i965/brw_vs_emit.c b/src/mesa/drivers/dri/i965/brw_vs_emit.c index b6b558e9a6..1d88c6b5a4 100644 --- a/src/mesa/drivers/dri/i965/brw_vs_emit.c +++ b/src/mesa/drivers/dri/i965/brw_vs_emit.c @@ -47,6 +47,7 @@ brw_vs_arg_can_be_immediate(enum prog_opcode opcode, int arg) [OPCODE_MOV] = 1, [OPCODE_ADD] = 2, [OPCODE_CMP] = 3, + [OPCODE_DP2] = 2, [OPCODE_DP3] = 2, [OPCODE_DP4] = 2, [OPCODE_DPH] = 2, @@ -97,6 +98,39 @@ static void release_tmps( struct brw_vs_compile *c ) c->last_tmp = c->first_tmp; } +static int +get_first_reladdr_output(struct gl_vertex_program *vp) +{ + int i; + int first_reladdr_output = VERT_RESULT_MAX; + + for (i = 0; i < vp->Base.NumInstructions; i++) { + struct prog_instruction *inst = vp->Base.Instructions + i; + + if (inst->DstReg.File == PROGRAM_OUTPUT && + inst->DstReg.RelAddr && + inst->DstReg.Index < first_reladdr_output) + first_reladdr_output = inst->DstReg.Index; + } + + return first_reladdr_output; +} + +/* Clears the record of which vp_const_buffer elements have been + * loaded into our constant buffer registers, for the starts of new + * blocks after control flow. + */ +static void +clear_current_const(struct brw_vs_compile *c) +{ + unsigned int i; + + if (c->vp->use_const_buffer) { + for (i = 0; i < 3; i++) { + c->current_const[i].index = -1; + } + } +} /** * Preallocate GRF register before code emit. @@ -108,6 +142,7 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c ) struct intel_context *intel = &c->func.brw->intel; GLuint i, reg = 0, mrf; int attributes_in_vue; + int first_reladdr_output; /* Determine whether to use a real constant buffer or use a block * of GRF registers for constants. The later is faster but only @@ -225,6 +260,7 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c ) else mrf = 4; + first_reladdr_output = get_first_reladdr_output(&c->vp->program); for (i = 0; i < VERT_RESULT_MAX; i++) { if (c->prog_data.outputs_written & BITFIELD64_BIT(i)) { c->nr_outputs++; @@ -253,15 +289,16 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c ) * For attributes beyond the compute-to-MRF, we compute to * GRFs and they will be written in the second URB_WRITE. */ - if (mrf < 15) { + if (first_reladdr_output > i && mrf < 15) { c->regs[PROGRAM_OUTPUT][i] = brw_message_reg(mrf); mrf++; } else { - if (!c->first_overflow_output) + if (mrf >= 15 && !c->first_overflow_output) c->first_overflow_output = i; c->regs[PROGRAM_OUTPUT][i] = brw_vec8_grf(reg, 0); reg++; + mrf++; } } } @@ -292,10 +329,10 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c ) if (c->vp->use_const_buffer) { for (i = 0; i < 3; i++) { - c->current_const[i].index = -1; c->current_const[i].reg = brw_vec8_grf(reg, 0); reg++; } + clear_current_const(c); } for (i = 0; i < 128; i++) { @@ -502,6 +539,23 @@ static void emit_cmp( struct brw_compile *p, brw_set_predicate_control(p, BRW_PREDICATE_NONE); } +static void emit_sign(struct brw_vs_compile *c, + struct brw_reg dst, + struct brw_reg arg0) +{ + struct brw_compile *p = &c->func; + + brw_MOV(p, dst, brw_imm_f(0)); + + brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_L, arg0, brw_imm_f(0)); + brw_MOV(p, dst, brw_imm_f(-1.0)); + brw_set_predicate_control(p, BRW_PREDICATE_NONE); + + brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_G, arg0, brw_imm_f(0)); + brw_MOV(p, dst, brw_imm_f(1.0)); + brw_set_predicate_control(p, BRW_PREDICATE_NONE); +} + static void emit_max( struct brw_compile *p, struct brw_reg dst, struct brw_reg arg0, @@ -1010,13 +1064,11 @@ move_to_reladdr_dst(struct brw_vs_compile *c, int reg_size = 32; struct brw_reg addr_reg = c->regs[PROGRAM_ADDRESS][0]; struct brw_reg vp_address = retype(vec1(addr_reg), BRW_REGISTER_TYPE_D); - struct brw_reg temp_base = c->regs[inst->DstReg.File][0]; - GLuint byte_offset = temp_base.nr * 32 + temp_base.subnr; + struct brw_reg base = c->regs[inst->DstReg.File][inst->DstReg.Index]; + GLuint byte_offset = base.nr * 32 + base.subnr; struct brw_reg indirect = brw_vec4_indirect(0,0); struct brw_reg acc = retype(vec1(get_tmp(c)), BRW_REGISTER_TYPE_UW); - byte_offset += inst->DstReg.Index * reg_size; - brw_push_insn_state(p); brw_set_access_mode(p, BRW_ALIGN_1); @@ -1162,10 +1214,12 @@ static struct brw_reg get_arg( struct brw_vs_compile *c, /* Convert 3-bit swizzle to 2-bit. */ - reg.dw1.bits.swizzle = BRW_SWIZZLE4(GET_SWZ(src->Swizzle, 0), - GET_SWZ(src->Swizzle, 1), - GET_SWZ(src->Swizzle, 2), - GET_SWZ(src->Swizzle, 3)); + if (reg.file != BRW_IMMEDIATE_VALUE) { + reg.dw1.bits.swizzle = BRW_SWIZZLE4(GET_SWZ(src->Swizzle, 0), + GET_SWZ(src->Swizzle, 1), + GET_SWZ(src->Swizzle, 2), + GET_SWZ(src->Swizzle, 3)); + } /* Note this is ok for non-swizzle instructions: */ @@ -1211,6 +1265,7 @@ static struct brw_reg get_dst( struct brw_vs_compile *c, reg = brw_null_reg(); } + assert(reg.type != BRW_IMMEDIATE_VALUE); reg.dw1.bits.writemask = dst.WriteMask; return reg; @@ -1299,6 +1354,7 @@ static void emit_vertex_write( struct brw_vs_compile *c) struct brw_reg ndc; int eot; GLuint len_vertex_header = 2; + int next_mrf, i; if (c->key.copy_edgeflag) { brw_MOV(p, @@ -1376,6 +1432,7 @@ static void emit_vertex_write( struct brw_vs_compile *c) * of zeros followed by two sets of NDC coordinates: */ brw_set_access_mode(p, BRW_ALIGN_1); + brw_set_acc_write_control(p, 0); /* The VUE layout is documented in Volume 2a. */ if (intel->gen >= 6) { @@ -1416,6 +1473,23 @@ static void emit_vertex_write( struct brw_vs_compile *c) len_vertex_header = 2; } + /* Move variable-addressed, non-overflow outputs to their MRFs. */ + next_mrf = 2 + len_vertex_header; + for (i = 0; i < VERT_RESULT_MAX; i++) { + if (c->first_overflow_output > 0 && i >= c->first_overflow_output) + break; + if (!(c->prog_data.outputs_written & BITFIELD64_BIT(i))) + continue; + + if (i >= VERT_RESULT_TEX0 && + c->regs[PROGRAM_OUTPUT][i].file == BRW_GENERAL_REGISTER_FILE) { + brw_MOV(p, brw_message_reg(next_mrf), c->regs[PROGRAM_OUTPUT][i]); + next_mrf++; + } else if (c->regs[PROGRAM_OUTPUT][i].file == BRW_MESSAGE_REGISTER_FILE) { + next_mrf = c->regs[PROGRAM_OUTPUT][i].nr + 1; + } + } + eot = (c->first_overflow_output == 0); brw_urb_WRITE(p, @@ -1541,18 +1615,23 @@ void brw_vs_emit(struct brw_vs_compile *c ) const GLuint nr_insns = c->vp->program.Base.NumInstructions; GLuint insn, if_depth = 0, loop_depth = 0; struct brw_instruction *if_inst[MAX_IF_DEPTH], *loop_inst[MAX_LOOP_DEPTH] = { 0 }; + int if_depth_in_loop[MAX_LOOP_DEPTH]; const struct brw_indirect stack_index = brw_indirect(0, 0); GLuint index; GLuint file; if (INTEL_DEBUG & DEBUG_VS) { printf("vs-mesa:\n"); - _mesa_print_program(&c->vp->program.Base); + _mesa_fprint_program_opt(stdout, &c->vp->program.Base, PROG_PRINT_DEBUG, + GL_TRUE); printf("\n"); } brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_access_mode(p, BRW_ALIGN_16); + if_depth_in_loop[loop_depth] = 0; + + brw_set_acc_write_control(p, 1); for (insn = 0; insn < nr_insns; insn++) { GLuint i; @@ -1591,7 +1670,7 @@ void brw_vs_emit(struct brw_vs_compile *c ) const struct prog_instruction *inst = &c->vp->program.Base.Instructions[insn]; struct brw_reg args[3], dst; GLuint i; - + #if 0 printf("%d: ", insn); _mesa_print_instruction(inst); @@ -1636,6 +1715,9 @@ void brw_vs_emit(struct brw_vs_compile *c ) case OPCODE_COS: emit_math1(c, BRW_MATH_FUNCTION_COS, dst, args[0], BRW_MATH_PRECISION_FULL); break; + case OPCODE_DP2: + brw_DP2(p, dst, args[0], args[1]); + break; case OPCODE_DP3: brw_DP3(p, dst, args[0], args[1]); break; @@ -1732,6 +1814,9 @@ void brw_vs_emit(struct brw_vs_compile *c ) case OPCODE_SLE: unalias2(c, dst, args[0], args[1], emit_sle); break; + case OPCODE_SSG: + unalias1(c, dst, args[0], emit_sign); + break; case OPCODE_SUB: brw_ADD(p, dst, args[0], negate(args[1])); break; @@ -1753,31 +1838,38 @@ void brw_vs_emit(struct brw_vs_compile *c ) if_inst[if_depth] = brw_IF(p, BRW_EXECUTE_8); /* Note that brw_IF smashes the predicate_control field. */ if_inst[if_depth]->header.predicate_control = get_predicate(inst); + if_depth_in_loop[loop_depth]++; if_depth++; break; case OPCODE_ELSE: + clear_current_const(c); assert(if_depth > 0); if_inst[if_depth-1] = brw_ELSE(p, if_inst[if_depth-1]); break; case OPCODE_ENDIF: + clear_current_const(c); assert(if_depth > 0); brw_ENDIF(p, if_inst[--if_depth]); + if_depth_in_loop[loop_depth]--; break; case OPCODE_BGNLOOP: + clear_current_const(c); loop_inst[loop_depth++] = brw_DO(p, BRW_EXECUTE_8); + if_depth_in_loop[loop_depth] = 0; break; case OPCODE_BRK: brw_set_predicate_control(p, get_predicate(inst)); - brw_BREAK(p); + brw_BREAK(p, if_depth_in_loop[loop_depth]); brw_set_predicate_control(p, BRW_PREDICATE_NONE); break; case OPCODE_CONT: brw_set_predicate_control(p, get_predicate(inst)); - brw_CONT(p); + brw_CONT(p, if_depth_in_loop[loop_depth]); brw_set_predicate_control(p, BRW_PREDICATE_NONE); break; case OPCODE_ENDLOOP: { + clear_current_const(c); struct brw_instruction *inst0, *inst1; GLuint br = 1; @@ -1793,12 +1885,10 @@ void brw_vs_emit(struct brw_vs_compile *c ) if (inst0->header.opcode == BRW_OPCODE_BREAK && inst0->bits3.if_else.jump_count == 0) { inst0->bits3.if_else.jump_count = br * (inst1 - inst0 + 1); - inst0->bits3.if_else.pop_count = 0; } else if (inst0->header.opcode == BRW_OPCODE_CONTINUE && inst0->bits3.if_else.jump_count == 0) { inst0->bits3.if_else.jump_count = br * (inst1 - inst0); - inst0->bits3.if_else.pop_count = 0; } } } @@ -1883,11 +1973,9 @@ void brw_vs_emit(struct brw_vs_compile *c ) } } - if (inst->DstReg.RelAddr && inst->DstReg.File == PROGRAM_TEMPORARY) { - /* We don't do RelAddr of PROGRAM_OUTPUT yet, because of the - * compute-to-mrf and the fact that we are allocating - * registers for only the used PROGRAM_OUTPUTs. - */ + if (inst->DstReg.RelAddr) { + assert(inst->DstReg.File == PROGRAM_TEMPORARY|| + inst->DstReg.File == PROGRAM_OUTPUT); move_to_reladdr_dst(c, inst, dst); } @@ -1903,7 +1991,7 @@ void brw_vs_emit(struct brw_vs_compile *c ) printf("vs-native:\n"); for (i = 0; i < p->nr_insn; i++) - brw_disasm(stderr, &p->store[i], intel->gen); + brw_disasm(stdout, &p->store[i], intel->gen); printf("\n"); } } diff --git a/src/mesa/drivers/dri/i965/brw_vtbl.c b/src/mesa/drivers/dri/i965/brw_vtbl.c index 14227a5133..8f1601d10f 100644 --- a/src/mesa/drivers/dri/i965/brw_vtbl.c +++ b/src/mesa/drivers/dri/i965/brw_vtbl.c @@ -101,6 +101,7 @@ static void brw_destroy_context( struct intel_context *intel ) dri_bo_release(&brw->wm.prog_bo); dri_bo_release(&brw->wm.state_bo); dri_bo_release(&brw->wm.const_bo); + dri_bo_release(&brw->wm.push_const_bo); dri_bo_release(&brw->cc.prog_bo); dri_bo_release(&brw->cc.state_bo); dri_bo_release(&brw->cc.vp_bo); diff --git a/src/mesa/drivers/dri/i965/brw_wm.c b/src/mesa/drivers/dri/i965/brw_wm.c index e182fc3202..d70be7bda2 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.c +++ b/src/mesa/drivers/dri/i965/brw_wm.c @@ -32,7 +32,7 @@ #include "brw_context.h" #include "brw_wm.h" #include "brw_state.h" - +#include "main/formats.h" /** Return number of src args for given instruction */ GLuint brw_wm_nr_args( GLuint opcode ) @@ -68,6 +68,7 @@ GLuint brw_wm_is_scalar_result( GLuint opcode ) case OPCODE_RCP: case OPCODE_RSQ: case OPCODE_SIN: + case OPCODE_DP2: case OPCODE_DP3: case OPCODE_DP4: case OPCODE_DPH: @@ -177,17 +178,19 @@ static void do_wm_prog( struct brw_context *brw, /* temporary sanity check assertion */ ASSERT(fp->isGLSL == brw_wm_is_glsl(&c->fp->program)); - /* - * Shader which use GLSL features such as flow control are handled - * differently from "simple" shaders. - */ - if (fp->isGLSL) { - c->dispatch_width = 8; - brw_wm_glsl_emit(brw, c); - } - else { - c->dispatch_width = 16; - brw_wm_non_glsl_emit(brw, c); + if (!brw_wm_fs_emit(brw, c)) { + /* + * Shader which use GLSL features such as flow control are handled + * differently from "simple" shaders. + */ + if (fp->isGLSL) { + c->dispatch_width = 8; + brw_wm_glsl_emit(brw, c); + } + else { + c->dispatch_width = 16; + brw_wm_non_glsl_emit(brw, c); + } } if (INTEL_DEBUG & DEBUG_WM) diff --git a/src/mesa/drivers/dri/i965/brw_wm.h b/src/mesa/drivers/dri/i965/brw_wm.h index f40977fab8..2639d4f26b 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.h +++ b/src/mesa/drivers/dri/i965/brw_wm.h @@ -61,7 +61,7 @@ struct brw_wm_prog_key { GLuint source_depth_reg:3; GLuint aa_dest_stencil_reg:3; GLuint dest_depth_reg:3; - GLuint nr_depth_regs:3; + GLuint nr_payload_regs:4; GLuint computes_depth:1; /* could be derived from program string */ GLuint source_depth_to_render_target:1; GLuint flat_shade:1; @@ -306,6 +306,7 @@ void brw_wm_lookup_iz( GLuint line_aa, GLboolean brw_wm_is_glsl(const struct gl_fragment_program *fp); void brw_wm_glsl_emit(struct brw_context *brw, struct brw_wm_compile *c); +GLboolean brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c); /* brw_wm_emit.c */ void emit_alu1(struct brw_compile *p, @@ -343,6 +344,11 @@ void emit_delta_xy(struct brw_compile *p, const struct brw_reg *dst, GLuint mask, const struct brw_reg *arg0); +void emit_dp2(struct brw_compile *p, + const struct brw_reg *dst, + GLuint mask, + const struct brw_reg *arg0, + const struct brw_reg *arg1); void emit_dp3(struct brw_compile *p, const struct brw_reg *dst, GLuint mask, @@ -425,6 +431,10 @@ void emit_sop(struct brw_compile *p, GLuint cond, const struct brw_reg *arg0, const struct brw_reg *arg1); +void emit_sign(struct brw_compile *p, + const struct brw_reg *dst, + GLuint mask, + const struct brw_reg *arg0); void emit_tex(struct brw_wm_compile *c, struct brw_reg *dst, GLuint dst_flags, @@ -450,4 +460,13 @@ void emit_xpd(struct brw_compile *p, const struct brw_reg *arg0, const struct brw_reg *arg1); +GLboolean brw_compile_shader(GLcontext *ctx, + struct gl_shader *shader); +GLboolean brw_link_shader(GLcontext *ctx, struct gl_shader_program *prog); +struct gl_shader *brw_new_shader(GLcontext *ctx, GLuint name, GLuint type); +struct gl_shader_program *brw_new_shader_program(GLcontext *ctx, GLuint name); + +GLboolean brw_do_channel_expressions(struct exec_list *instructions); +GLboolean brw_do_vector_splitting(struct exec_list *instructions); + #endif diff --git a/src/mesa/drivers/dri/i965/brw_wm_debug.c b/src/mesa/drivers/dri/i965/brw_wm_debug.c index a78cc8b54e..6a91251a80 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_debug.c +++ b/src/mesa/drivers/dri/i965/brw_wm_debug.c @@ -44,16 +44,16 @@ void brw_wm_print_value( struct brw_wm_compile *c, printf("undef"); else if( value - c->vreg >= 0 && value - c->vreg < BRW_WM_MAX_VREG) - printf("r%d", value - c->vreg); + printf("r%ld", (long) (value - c->vreg)); else if (value - c->creg >= 0 && value - c->creg < BRW_WM_MAX_PARAM) - printf("c%d", value - c->creg); + printf("c%ld", (long) (value - c->creg)); else if (value - c->payload.input_interp >= 0 && value - c->payload.input_interp < FRAG_ATTRIB_MAX) - printf("i%d", value - c->payload.input_interp); + printf("i%ld", (long) (value - c->payload.input_interp)); else if (value - c->payload.depth >= 0 && value - c->payload.depth < FRAG_ATTRIB_MAX) - printf("d%d", value - c->payload.depth); + printf("d%ld", (long) (value - c->payload.depth)); else printf("?"); } diff --git a/src/mesa/drivers/dri/i965/brw_wm_emit.c b/src/mesa/drivers/dri/i965/brw_wm_emit.c index d9fa2e6335..f3ad01b3fe 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_emit.c +++ b/src/mesa/drivers/dri/i965/brw_wm_emit.c @@ -668,6 +668,28 @@ void emit_cmp(struct brw_compile *p, } } +void emit_sign(struct brw_compile *p, + const struct brw_reg *dst, + GLuint mask, + const struct brw_reg *arg0) +{ + GLuint i; + + for (i = 0; i < 4; i++) { + if (mask & (1<<i)) { + brw_MOV(p, dst[i], brw_imm_f(0.0)); + + brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_L, arg0[i], brw_imm_f(0)); + brw_MOV(p, dst[i], brw_imm_f(-1.0)); + brw_set_predicate_control(p, BRW_PREDICATE_NONE); + + brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_G, arg0[i], brw_imm_f(0)); + brw_MOV(p, dst[i], brw_imm_f(1.0)); + brw_set_predicate_control(p, BRW_PREDICATE_NONE); + } + } +} + void emit_max(struct brw_compile *p, const struct brw_reg *dst, GLuint mask, @@ -709,6 +731,27 @@ void emit_min(struct brw_compile *p, } +void emit_dp2(struct brw_compile *p, + const struct brw_reg *dst, + GLuint mask, + const struct brw_reg *arg0, + const struct brw_reg *arg1) +{ + int dst_chan = _mesa_ffs(mask & WRITEMASK_XYZW) - 1; + + if (!(mask & WRITEMASK_XYZW)) + return; /* Do not emit dead code */ + + assert(is_power_of_two(mask & WRITEMASK_XYZW)); + + brw_MUL(p, brw_null_reg(), arg0[0], arg1[0]); + + brw_set_saturate(p, (mask & SATURATE) ? 1 : 0); + brw_MAC(p, dst[dst_chan], arg0[1], arg1[1]); + brw_set_saturate(p, 0); +} + + void emit_dp3(struct brw_compile *p, const struct brw_reg *dst, GLuint mask, @@ -809,21 +852,28 @@ void emit_math1(struct brw_wm_compile *c, const struct brw_reg *arg0) { struct brw_compile *p = &c->func; + struct intel_context *intel = &p->brw->intel; int dst_chan = _mesa_ffs(mask & WRITEMASK_XYZW) - 1; GLuint saturate = ((mask & SATURATE) ? BRW_MATH_SATURATE_SATURATE : BRW_MATH_SATURATE_NONE); + struct brw_reg src; + + if (intel->gen >= 6 && arg0[0].hstride == BRW_HORIZONTAL_STRIDE_0) { + /* Gen6 math requires that source and dst horizontal stride be 1. + * + */ + src = *dst; + brw_MOV(p, src, arg0[0]); + } else { + src = arg0[0]; + } if (!(mask & WRITEMASK_XYZW)) return; /* Do not emit dead code */ assert(is_power_of_two(mask & WRITEMASK_XYZW)); - /* If compressed, this will write message reg 2,3 from arg0.x's 16 - * channels. - */ - brw_MOV(p, brw_message_reg(2), arg0[0]); - /* Send two messages to perform all 16 operations: */ brw_push_insn_state(p); @@ -833,7 +883,7 @@ void emit_math1(struct brw_wm_compile *c, function, saturate, 2, - brw_null_reg(), + src, BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); @@ -844,7 +894,7 @@ void emit_math1(struct brw_wm_compile *c, function, saturate, 3, - brw_null_reg(), + sechalf(src), BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); } @@ -873,13 +923,6 @@ void emit_math2(struct brw_wm_compile *c, brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); - brw_MOV(p, brw_message_reg(2), arg0[0]); - if (c->dispatch_width == 16) { - brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); - brw_MOV(p, brw_message_reg(4), sechalf(arg0[0])); - } - - brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(3), arg1[0]); if (c->dispatch_width == 16) { brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); @@ -892,7 +935,7 @@ void emit_math2(struct brw_wm_compile *c, function, saturate, 2, - brw_null_reg(), + arg0[0], BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); @@ -905,7 +948,7 @@ void emit_math2(struct brw_wm_compile *c, function, saturate, 4, - brw_null_reg(), + sechalf(arg0[0]), BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); } @@ -1199,6 +1242,7 @@ static void fire_fb_write( struct brw_wm_compile *c, GLuint eot ) { struct brw_compile *p = &c->func; + struct intel_context *intel = &p->brw->intel; struct brw_reg dst; if (c->dispatch_width == 16) @@ -1209,6 +1253,7 @@ static void fire_fb_write( struct brw_wm_compile *c, /* Pass through control information: */ /* mov (8) m1.0<1>:ud r1.0<8;8,1>:ud { Align1 NoMask } */ + if (intel->gen < 6) /* gen6, use headerless for fb write */ { brw_push_insn_state(p); brw_set_mask_control(p, BRW_MASK_DISABLE); /* ? */ @@ -1222,6 +1267,7 @@ static void fire_fb_write( struct brw_wm_compile *c, /* Send framebuffer write message: */ /* send (16) null.0<1>:uw m0 r0.0<8;8,1>:uw 0x85a04000:ud { Align1 EOT } */ brw_fb_WRITE(p, + c->dispatch_width, dst, base_reg, retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW), @@ -1263,8 +1309,10 @@ void emit_fb_write(struct brw_wm_compile *c, { struct brw_compile *p = &c->func; struct brw_context *brw = p->brw; + struct intel_context *intel = &brw->intel; GLuint nr = 2; GLuint channel; + int base_reg; /* For gen6 fb write with no header, starting from color payload directly!. */ /* Reserve a space for AA - may not be needed: */ @@ -1276,9 +1324,40 @@ void emit_fb_write(struct brw_wm_compile *c, */ brw_push_insn_state(p); + if (intel->gen >= 6) + base_reg = nr; + else + base_reg = 0; + for (channel = 0; channel < 4; channel++) { - if (c->dispatch_width == 16 && brw->has_compr4) { - /* By setting the high bit of the MRF register number, we indicate + if (intel->gen >= 6) { + /* gen6 SIMD16 single source DP write looks like: + * m + 0: r0 + * m + 1: r1 + * m + 2: g0 + * m + 3: g1 + * m + 4: b0 + * m + 5: b1 + * m + 6: a0 + * m + 7: a1 + */ + if (c->dispatch_width == 16) { + brw_MOV(p, brw_message_reg(nr + channel * 2), arg0[channel]); + } else { + brw_MOV(p, brw_message_reg(nr + channel), arg0[channel]); + } + } else if (c->dispatch_width == 16 && brw->has_compr4) { + /* pre-gen6 SIMD16 single source DP write looks like: + * m + 0: r0 + * m + 1: g0 + * m + 2: b0 + * m + 3: a0 + * m + 4: r1 + * m + 5: g1 + * m + 6: b1 + * m + 7: a1 + * + * By setting the high bit of the MRF register number, we indicate * that we want COMPR4 mode - instead of doing the usual destination * + 1 for the second half we get destination + 4. */ @@ -1303,7 +1382,11 @@ void emit_fb_write(struct brw_wm_compile *c, } /* skip over the regs populated above: */ - nr += 8; + if (c->dispatch_width == 16) + nr += 8; + else + nr += 4; + brw_pop_insn_state(p); if (c->key.source_depth_to_render_target) @@ -1336,11 +1419,16 @@ void emit_fb_write(struct brw_wm_compile *c, nr += 2; } + if (intel->gen >= 6) { + /* Subtract off the message header, since we send headerless. */ + nr -= 2; + } + if (!c->key.runtime_check_aads_emit) { if (c->key.aa_dest_stencil_reg) emit_aa(c, arg1, 2); - fire_fb_write(c, 0, nr, target, eot); + fire_fb_write(c, base_reg, nr, target, eot); } else { struct brw_reg v1_null_ud = vec1(retype(brw_null_reg(), BRW_REGISTER_TYPE_UD)); @@ -1562,6 +1650,10 @@ void brw_wm_emit( struct brw_wm_compile *c ) emit_ddxy(p, dst, dst_flags, GL_FALSE, args[0]); break; + case OPCODE_DP2: + emit_dp2(p, dst, dst_flags, args[0], args[1]); + break; + case OPCODE_DP3: emit_dp3(p, dst, dst_flags, args[0], args[1]); break; @@ -1673,6 +1765,10 @@ void brw_wm_emit( struct brw_wm_compile *c ) emit_sne(p, dst, dst_flags, args[0], args[1]); break; + case OPCODE_SSG: + emit_sign(p, dst, dst_flags, args[0]); + break; + case OPCODE_LIT: emit_lit(c, dst, dst_flags, args[0]); break; @@ -1724,7 +1820,7 @@ void brw_wm_emit( struct brw_wm_compile *c ) printf("wm-native:\n"); for (i = 0; i < p->nr_insn; i++) - brw_disasm(stderr, &p->store[i], p->brw->intel.gen); + brw_disasm(stdout, &p->store[i], p->brw->intel.gen); printf("\n"); } } diff --git a/src/mesa/drivers/dri/i965/brw_wm_fp.c b/src/mesa/drivers/dri/i965/brw_wm_fp.c index 0bef874b88..3870bf10fc 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_fp.c +++ b/src/mesa/drivers/dri/i965/brw_wm_fp.c @@ -88,6 +88,7 @@ static struct prog_src_register src_reg(GLuint file, GLuint idx) reg.RelAddr = 0; reg.Negate = NEGATE_NONE; reg.Abs = 0; + reg.HasIndex2 = 0; return reg; } @@ -1036,13 +1037,12 @@ static void print_insns( const struct prog_instruction *insn, for (i = 0; i < nr; i++, insn++) { printf("%3d: ", i); if (insn->Opcode < MAX_OPCODE) - _mesa_print_instruction(insn); + _mesa_fprint_instruction_opt(stdout, insn, 0, PROG_PRINT_DEBUG, NULL); else if (insn->Opcode < MAX_WM_OPCODE) { GLuint idx = insn->Opcode - MAX_OPCODE; - _mesa_print_alu_instruction(insn, - wm_opcode_strings[idx], - 3); + _mesa_fprint_alu_instruction(stdout, insn, wm_opcode_strings[idx], + 3, PROG_PRINT_DEBUG, NULL); } else printf("965 Opcode %d\n", insn->Opcode); @@ -1061,7 +1061,8 @@ void brw_wm_pass_fp( struct brw_wm_compile *c ) if (INTEL_DEBUG & DEBUG_WM) { printf("pre-fp:\n"); - _mesa_print_program(&fp->program.Base); + _mesa_fprint_program_opt(stdout, &fp->program.Base, PROG_PRINT_DEBUG, + GL_TRUE); printf("\n"); } diff --git a/src/mesa/drivers/dri/i965/brw_wm_glsl.c b/src/mesa/drivers/dri/i965/brw_wm_glsl.c index 575f89b17f..c1083c5942 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_glsl.c +++ b/src/mesa/drivers/dri/i965/brw_wm_glsl.c @@ -303,13 +303,13 @@ static void prealloc_reg(struct brw_wm_compile *c) c->first_free_grf = 0; for (i = 0; i < 4; i++) { - if (i < c->key.nr_depth_regs) + if (i < (c->key.nr_payload_regs + 1) / 2) reg = brw_vec8_grf(i * 2, 0); else reg = brw_vec8_grf(0, 0); set_reg(c, PROGRAM_PAYLOAD, PAYLOAD_DEPTH, i, reg); } - reg_index += 2 * c->key.nr_depth_regs; + reg_index += c->key.nr_payload_regs; /* constants */ { @@ -380,7 +380,7 @@ static void prealloc_reg(struct brw_wm_compile *c) } } - c->prog_data.first_curbe_grf = c->key.nr_depth_regs * 2; + c->prog_data.first_curbe_grf = c->key.nr_payload_regs; c->prog_data.urb_read_length = urb_read_length; c->prog_data.curb_read_length = c->nr_creg; c->emit_mask_reg = brw_uw1_reg(BRW_GENERAL_REGISTER_FILE, reg_index, 0); @@ -1803,12 +1803,15 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) #define MAX_IF_DEPTH 32 #define MAX_LOOP_DEPTH 32 struct brw_instruction *if_inst[MAX_IF_DEPTH], *loop_inst[MAX_LOOP_DEPTH]; + int if_depth_in_loop[MAX_LOOP_DEPTH]; GLuint i, if_depth = 0, loop_depth = 0; struct brw_compile *p = &c->func; struct brw_indirect stack_index = brw_indirect(0, 0); c->out_of_regs = GL_FALSE; + if_depth_in_loop[loop_depth] = 0; + prealloc_reg(c); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, get_addr_reg(stack_index), brw_address(c->stack)); @@ -1903,6 +1906,9 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) case OPCODE_SWZ: emit_alu1(p, brw_MOV, dst, dst_flags, args[0]); break; + case OPCODE_DP2: + emit_dp2(p, dst, dst_flags, args[0], args[1]); + break; case OPCODE_DP3: emit_dp3(p, dst, dst_flags, args[0], args[1]); break; @@ -1971,6 +1977,9 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) emit_sop(p, dst, dst_flags, BRW_CONDITIONAL_NEQ, args[0], args[1]); break; + case OPCODE_SSG: + emit_sign(p, dst, dst_flags, args[0]); + break; case OPCODE_MUL: emit_alu2(p, brw_MUL, dst, dst_flags, args[0], args[1]); break; @@ -2014,6 +2023,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) case OPCODE_IF: assert(if_depth < MAX_IF_DEPTH); if_inst[if_depth++] = brw_IF(p, BRW_EXECUTE_8); + if_depth_in_loop[loop_depth]++; break; case OPCODE_ELSE: assert(if_depth > 0); @@ -2022,6 +2032,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) case OPCODE_ENDIF: assert(if_depth > 0); brw_ENDIF(p, if_inst[--if_depth]); + if_depth_in_loop[loop_depth]--; break; case OPCODE_BGNSUB: brw_save_label(p, inst->Comment, p->nr_insn); @@ -2056,13 +2067,14 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) case OPCODE_BGNLOOP: /* XXX may need to invalidate the current_constant regs */ loop_inst[loop_depth++] = brw_DO(p, BRW_EXECUTE_8); + if_depth_in_loop[loop_depth] = 0; break; case OPCODE_BRK: - brw_BREAK(p); + brw_BREAK(p, if_depth_in_loop[loop_depth]); brw_set_predicate_control(p, BRW_PREDICATE_NONE); break; case OPCODE_CONT: - brw_CONT(p); + brw_CONT(p, if_depth_in_loop[loop_depth]); brw_set_predicate_control(p, BRW_PREDICATE_NONE); break; case OPCODE_ENDLOOP: @@ -2082,12 +2094,10 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) if (inst0->header.opcode == BRW_OPCODE_BREAK && inst0->bits3.if_else.jump_count == 0) { inst0->bits3.if_else.jump_count = br * (inst1 - inst0 + 1); - inst0->bits3.if_else.pop_count = 0; } else if (inst0->header.opcode == BRW_OPCODE_CONTINUE && inst0->bits3.if_else.jump_count == 0) { inst0->bits3.if_else.jump_count = br * (inst1 - inst0); - inst0->bits3.if_else.pop_count = 0; } } } @@ -2111,7 +2121,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) if (INTEL_DEBUG & DEBUG_WM) { printf("wm-native:\n"); for (i = 0; i < p->nr_insn; i++) - brw_disasm(stderr, &p->store[i], intel->gen); + brw_disasm(stdout, &p->store[i], intel->gen); printf("\n"); } } diff --git a/src/mesa/drivers/dri/i965/brw_wm_iz.c b/src/mesa/drivers/dri/i965/brw_wm_iz.c index 5e399ac62a..8505ef1951 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_iz.c +++ b/src/mesa/drivers/dri/i965/brw_wm_iz.c @@ -152,6 +152,6 @@ void brw_wm_lookup_iz( GLuint line_aa, reg+=2; } - key->nr_depth_regs = (reg+1)/2; + key->nr_payload_regs = reg; } diff --git a/src/mesa/drivers/dri/i965/brw_wm_pass0.c b/src/mesa/drivers/dri/i965/brw_wm_pass0.c index 05de85a957..8fc960b445 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_pass0.c +++ b/src/mesa/drivers/dri/i965/brw_wm_pass0.c @@ -379,7 +379,7 @@ static void pass0_init_payload( struct brw_wm_compile *c ) GLuint i; for (i = 0; i < 4; i++) { - GLuint j = i >= c->key.nr_depth_regs ? 0 : i; + GLuint j = i >= (c->key.nr_payload_regs + 1) / 2 ? 0 : i; pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, PAYLOAD_DEPTH, i, &c->payload.depth[j] ); } diff --git a/src/mesa/drivers/dri/i965/brw_wm_pass1.c b/src/mesa/drivers/dri/i965/brw_wm_pass1.c index b449394029..962515a99e 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_pass1.c +++ b/src/mesa/drivers/dri/i965/brw_wm_pass1.c @@ -158,6 +158,7 @@ void brw_wm_pass1( struct brw_wm_compile *c ) case OPCODE_FLR: case OPCODE_FRC: case OPCODE_MOV: + case OPCODE_SSG: case OPCODE_SWZ: case OPCODE_TRUNC: read0 = writemask; @@ -254,6 +255,11 @@ void brw_wm_pass1( struct brw_wm_compile *c ) read2 = WRITEMASK_W; /* pixel w */ break; + case OPCODE_DP2: + read0 = WRITEMASK_XY; + read1 = WRITEMASK_XY; + break; + case OPCODE_DP3: read0 = WRITEMASK_XYZ; read1 = WRITEMASK_XYZ; diff --git a/src/mesa/drivers/dri/i965/brw_wm_pass2.c b/src/mesa/drivers/dri/i965/brw_wm_pass2.c index 31303febf0..54acb3038b 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_pass2.c +++ b/src/mesa/drivers/dri/i965/brw_wm_pass2.c @@ -76,7 +76,7 @@ static void init_registers( struct brw_wm_compile *c ) for (j = 0; j < c->grf_limit; j++) c->pass2_grf[j].nextuse = BRW_WM_MAX_INSN; - for (j = 0; j < c->key.nr_depth_regs; j++) + for (j = 0; j < (c->key.nr_payload_regs + 1) / 2; j++) prealloc_reg(c, &c->payload.depth[j], i++); for (j = 0; j < c->nr_creg; j++) @@ -101,7 +101,7 @@ static void init_registers( struct brw_wm_compile *c ) assert(nr_interp_regs >= 1); - c->prog_data.first_curbe_grf = c->key.nr_depth_regs * 2; + c->prog_data.first_curbe_grf = ALIGN(c->key.nr_payload_regs, 2); c->prog_data.urb_read_length = nr_interp_regs * 2; c->prog_data.curb_read_length = c->nr_creg * 2; diff --git a/src/mesa/drivers/dri/i965/brw_wm_state.c b/src/mesa/drivers/dri/i965/brw_wm_state.c index c1cf4db1ca..6699d0a73e 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_state.c +++ b/src/mesa/drivers/dri/i965/brw_wm_state.c @@ -104,8 +104,22 @@ wm_unit_populate_key(struct brw_context *brw, struct brw_wm_unit_key *key) key->uses_kill = fp->UsesKill || ctx->Color.AlphaEnabled; key->is_glsl = bfp->isGLSL; - /* temporary sanity check assertion */ - ASSERT(bfp->isGLSL == brw_wm_is_glsl(fp)); + /* If using the fragment shader backend, the program is always + * 8-wide. + */ + if (ctx->Shader.CurrentProgram) { + int i; + + for (i = 0; i < ctx->Shader.CurrentProgram->_NumLinkedShaders; i++) { + struct brw_shader *shader = + (struct brw_shader *)ctx->Shader.CurrentProgram->_LinkedShaders[i];; + + if (shader->base.Type == GL_FRAGMENT_SHADER && + shader->ir != NULL) { + key->is_glsl = GL_TRUE; + } + } + } /* _NEW_DEPTH */ key->stats_wm = intel->stats_wm; diff --git a/src/mesa/drivers/dri/i965/gen6_cc.c b/src/mesa/drivers/dri/i965/gen6_cc.c index f7acad6912..26f1070a16 100644 --- a/src/mesa/drivers/dri/i965/gen6_cc.c +++ b/src/mesa/drivers/dri/i965/gen6_cc.c @@ -267,9 +267,9 @@ static void upload_cc_state_pointers(struct brw_context *brw) BEGIN_BATCH(4); OUT_BATCH(CMD_3D_CC_STATE_POINTERS << 16 | (4 - 2)); - OUT_RELOC(brw->cc.state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1); OUT_RELOC(brw->cc.blend_state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1); OUT_RELOC(brw->cc.depth_stencil_state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1); + OUT_RELOC(brw->cc.state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1); ADVANCE_BATCH(); intel_batchbuffer_emit_mi_flush(intel->batch); diff --git a/src/mesa/drivers/dri/i965/gen6_wm_state.c b/src/mesa/drivers/dri/i965/gen6_wm_state.c index 863c85449d..2cd640de17 100644 --- a/src/mesa/drivers/dri/i965/gen6_wm_state.c +++ b/src/mesa/drivers/dri/i965/gen6_wm_state.c @@ -34,18 +34,59 @@ #include "intel_batchbuffer.h" static void +prepare_wm_constants(struct brw_context *brw) +{ + struct intel_context *intel = &brw->intel; + GLcontext *ctx = &intel->ctx; + const struct brw_fragment_program *fp = + brw_fragment_program_const(brw->fragment_program); + + drm_intel_bo_unreference(brw->wm.push_const_bo); + brw->wm.push_const_bo = NULL; + + /* Updates the ParamaterValues[i] pointers for all parameters of the + * basic type of PROGRAM_STATE_VAR. + */ + /* XXX: Should this happen somewhere before to get our state flag set? */ + _mesa_load_state_parameters(ctx, fp->program.Base.Parameters); + + if (brw->wm.prog_data->nr_params != 0) { + float *constants; + unsigned int i; + + brw->wm.push_const_bo = drm_intel_bo_alloc(intel->bufmgr, + "WM constant_bo", + brw->wm.prog_data->nr_params * + sizeof(float), + 4096); + drm_intel_gem_bo_map_gtt(brw->wm.push_const_bo); + constants = brw->wm.push_const_bo->virtual; + for (i = 0; i < brw->wm.prog_data->nr_params; i++) { + constants[i] = *brw->wm.prog_data->param[i]; + } + drm_intel_gem_bo_unmap_gtt(brw->wm.push_const_bo); + } +} + +const struct brw_tracked_state gen6_wm_constants = { + .dirty = { + .mesa = _NEW_PROGRAM_CONSTANTS, + .brw = 0, + .cache = 0, + }, + .prepare = prepare_wm_constants, +}; + +static void upload_wm_state(struct brw_context *brw) { struct intel_context *intel = &brw->intel; GLcontext *ctx = &intel->ctx; const struct brw_fragment_program *fp = brw_fragment_program_const(brw->fragment_program); - unsigned int nr_params = fp->program.Base.Parameters->NumParameters; - drm_intel_bo *constant_bo; - int i; uint32_t dw2, dw4, dw5, dw6; - if (fp->use_const_buffer || nr_params == 0) { + if (fp->use_const_buffer || brw->wm.prog_data->nr_params == 0) { /* Disable the push constant buffers. */ BEGIN_BATCH(5); OUT_BATCH(CMD_3D_CONSTANT_PS_STATE << 16 | (5 - 2)); @@ -55,35 +96,17 @@ upload_wm_state(struct brw_context *brw) OUT_BATCH(0); ADVANCE_BATCH(); } else { - /* Updates the ParamaterValues[i] pointers for all parameters of the - * basic type of PROGRAM_STATE_VAR. - */ - _mesa_load_state_parameters(ctx, fp->program.Base.Parameters); - - constant_bo = drm_intel_bo_alloc(intel->bufmgr, "WM constant_bo", - nr_params * 4 * sizeof(float), - 4096); - drm_intel_gem_bo_map_gtt(constant_bo); - for (i = 0; i < nr_params; i++) { - memcpy((char *)constant_bo->virtual + i * 4 * sizeof(float), - fp->program.Base.Parameters->ParameterValues[i], - 4 * sizeof(float)); - } - drm_intel_gem_bo_unmap_gtt(constant_bo); - BEGIN_BATCH(5); OUT_BATCH(CMD_3D_CONSTANT_PS_STATE << 16 | GEN6_CONSTANT_BUFFER_0_ENABLE | (5 - 2)); - OUT_RELOC(constant_bo, + OUT_RELOC(brw->wm.push_const_bo, I915_GEM_DOMAIN_RENDER, 0, /* XXX: bad domain */ - ALIGN(nr_params, 2) / 2 - 1); + ALIGN(brw->wm.prog_data->nr_params, 8) / 8 - 1); OUT_BATCH(0); OUT_BATCH(0); OUT_BATCH(0); ADVANCE_BATCH(); - - drm_intel_bo_unreference(constant_bo); } intel_batchbuffer_emit_mi_flush(intel->batch); diff --git a/src/mesa/drivers/dri/intel/intel_buffer_objects.c b/src/mesa/drivers/dri/intel/intel_buffer_objects.c index 8ab41f8d27..117d4daf3b 100644 --- a/src/mesa/drivers/dri/intel/intel_buffer_objects.c +++ b/src/mesa/drivers/dri/intel/intel_buffer_objects.c @@ -202,6 +202,9 @@ intel_bufferobj_subdata(GLcontext * ctx, struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); + if (size == 0) + return; + assert(intel_obj); if (intel_obj->region) @@ -426,6 +429,9 @@ intel_bufferobj_flush_mapped_range(GLcontext *ctx, GLenum target, if (intel_obj->range_map_buffer == NULL) return; + if (length == 0) + return; + temp_bo = drm_intel_bo_alloc(intel->bufmgr, "range map flush", length, 64); drm_intel_bo_subdata(temp_bo, 0, length, intel_obj->range_map_buffer); diff --git a/src/mesa/drivers/dri/intel/intel_chipset.h b/src/mesa/drivers/dri/intel/intel_chipset.h index 72a74322ee..b5f180bbc8 100644 --- a/src/mesa/drivers/dri/intel/intel_chipset.h +++ b/src/mesa/drivers/dri/intel/intel_chipset.h @@ -73,6 +73,7 @@ #define PCI_CHIP_SANDYBRIDGE 0x0102 #define PCI_CHIP_SANDYBRIDGE_M 0x0106 +#define PCI_CHIP_SANDYBRIDGE_M_D0 0x0126 #define IS_MOBILE(devid) (devid == PCI_CHIP_I855_GM || \ devid == PCI_CHIP_I915_GM || \ @@ -119,7 +120,8 @@ #define IS_IRONLAKE(devid) IS_GEN5(devid) #define IS_GEN6(devid) (devid == PCI_CHIP_SANDYBRIDGE || \ - devid == PCI_CHIP_SANDYBRIDGE_M) + devid == PCI_CHIP_SANDYBRIDGE_M || \ + devid == PCI_CHIP_SANDYBRIDGE_M_D0) #define IS_965(devid) (IS_GEN4(devid) || \ IS_G4X(devid) || \ diff --git a/src/mesa/drivers/dri/intel/intel_context.c b/src/mesa/drivers/dri/intel/intel_context.c index e19f44035f..a9ba93d24b 100644 --- a/src/mesa/drivers/dri/intel/intel_context.c +++ b/src/mesa/drivers/dri/intel/intel_context.c @@ -377,7 +377,8 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) intel_region_reference(®ion, depth_region); } else - region = intel_region_alloc_for_handle(intel, buffers[i].cpp, + region = intel_region_alloc_for_handle(intel->intelScreen, + buffers[i].cpp, drawable->w, drawable->h, buffers[i].pitch / buffers[i].cpp, @@ -720,6 +721,8 @@ intelInitContext(struct intel_context *intel, ctx->Const.MaxPointSizeAA = 3.0; ctx->Const.PointSizeGranularity = 1.0; + ctx->Const.MaxSamples = 1.0; + /* reinitialize the context point state. * It depend on constants in __GLcontextRec::Const */ diff --git a/src/mesa/drivers/dri/intel/intel_context.h b/src/mesa/drivers/dri/intel/intel_context.h index c7ac2de01e..28d53284fd 100644 --- a/src/mesa/drivers/dri/intel/intel_context.h +++ b/src/mesa/drivers/dri/intel/intel_context.h @@ -32,14 +32,26 @@ #include "main/mtypes.h" #include "main/mm.h" -#include "texmem.h" #include "dri_metaops.h" + +#ifdef __cplusplus +extern "C" { + /* Evil hack for using libdrm in a c++ compiler. */ + #define virtual virt +#endif + #include "drm.h" #include "intel_bufmgr.h" #include "intel_screen.h" #include "intel_tex_obj.h" #include "i915_drm.h" + +#ifdef __cplusplus + #undef virtual +} +#endif + #include "tnl/t_vertex.h" #define TAG(x) intel##x diff --git a/src/mesa/drivers/dri/intel/intel_extensions.c b/src/mesa/drivers/dri/intel/intel_extensions.c index edba1fc2f2..bf22a423fc 100644 --- a/src/mesa/drivers/dri/intel/intel_extensions.c +++ b/src/mesa/drivers/dri/intel/intel_extensions.c @@ -50,8 +50,9 @@ #define need_GL_EXT_cull_vertex #define need_GL_EXT_draw_buffers2 #define need_GL_EXT_fog_coord -#define need_GL_EXT_framebuffer_object #define need_GL_EXT_framebuffer_blit +#define need_GL_EXT_framebuffer_multisample +#define need_GL_EXT_framebuffer_object #define need_GL_EXT_gpu_program_parameters #define need_GL_EXT_point_parameters #define need_GL_EXT_provoking_vertex @@ -111,6 +112,7 @@ static const struct dri_extension card_extensions[] = { { "GL_EXT_cull_vertex", GL_EXT_cull_vertex_functions }, { "GL_EXT_framebuffer_blit", GL_EXT_framebuffer_blit_functions }, { "GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions }, + { "GL_EXT_framebuffer_multisample", GL_EXT_framebuffer_multisample_functions }, { "GL_EXT_fog_coord", GL_EXT_fog_coord_functions }, { "GL_EXT_gpu_program_parameters", GL_EXT_gpu_program_parameters_functions }, { "GL_EXT_packed_depth_stencil", NULL }, diff --git a/src/mesa/drivers/dri/intel/intel_fbo.c b/src/mesa/drivers/dri/intel/intel_fbo.c index 4a83886fc1..2693b5fa72 100644 --- a/src/mesa/drivers/dri/intel/intel_fbo.c +++ b/src/mesa/drivers/dri/intel/intel_fbo.c @@ -137,27 +137,21 @@ intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb, rb->Format = MESA_FORMAT_A8; rb->DataType = GL_UNSIGNED_BYTE; break; + case GL_DEPTH_COMPONENT16: + rb->Format = MESA_FORMAT_Z16; + rb->DataType = GL_UNSIGNED_SHORT; + break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: - /* alloc a depth+stencil buffer */ - rb->Format = MESA_FORMAT_S8_Z24; - rb->DataType = GL_UNSIGNED_INT_24_8_EXT; - break; - case GL_DEPTH_COMPONENT16: - rb->Format = MESA_FORMAT_Z16; - rb->DataType = GL_UNSIGNED_SHORT; - break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: - rb->Format = MESA_FORMAT_S8_Z24; - rb->DataType = GL_UNSIGNED_INT_24_8_EXT; - break; case GL_DEPTH_STENCIL_EXT: case GL_DEPTH24_STENCIL8_EXT: + /* alloc a depth+stencil buffer */ rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; @@ -182,7 +176,7 @@ intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb, /* alloc hardware renderbuffer */ DBG("Allocating %d x %d Intel RBO\n", width, height); - irb->region = intel_region_alloc(intel, I915_TILING_NONE, cpp, + irb->region = intel_region_alloc(intel->intelScreen, I915_TILING_NONE, cpp, width, height, GL_TRUE); if (!irb->region) return GL_FALSE; /* out of memory? */ diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c index 39ac0205fa..d316d34d69 100644 --- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c +++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c @@ -30,6 +30,7 @@ #include "intel_regions.h" #include "intel_tex_layout.h" #include "main/enums.h" +#include "main/formats.h" #define FILE_DEBUG_FLAG DEBUG_MIPTREE @@ -136,7 +137,7 @@ intel_miptree_create(struct intel_context *intel, return NULL; } - mt->region = intel_region_alloc(intel, + mt->region = intel_region_alloc(intel->intelScreen, tiling, mt->cpp, mt->total_width, diff --git a/src/mesa/drivers/dri/intel/intel_regions.c b/src/mesa/drivers/dri/intel/intel_regions.c index 680d18ba29..e87e29462c 100644 --- a/src/mesa/drivers/dri/intel/intel_regions.c +++ b/src/mesa/drivers/dri/intel/intel_regions.c @@ -142,10 +142,10 @@ intel_region_unmap(struct intel_context *intel, struct intel_region *region) } static struct intel_region * -intel_region_alloc_internal(struct intel_context *intel, +intel_region_alloc_internal(struct intel_screen *screen, GLuint cpp, GLuint width, GLuint height, GLuint pitch, - drm_intel_bo *buffer) + uint32_t tiling, drm_intel_bo *buffer) { struct intel_region *region; @@ -164,44 +164,52 @@ intel_region_alloc_internal(struct intel_context *intel, region->pitch = pitch; region->refcount = 1; region->buffer = buffer; - - /* Default to no tiling */ - region->tiling = I915_TILING_NONE; + region->tiling = tiling; + region->screen = screen; _DBG("%s <-- %p\n", __FUNCTION__, region); return region; } struct intel_region * -intel_region_alloc(struct intel_context *intel, +intel_region_alloc(struct intel_screen *screen, uint32_t tiling, GLuint cpp, GLuint width, GLuint height, GLboolean expect_accelerated_upload) { drm_intel_bo *buffer; - struct intel_region *region; unsigned long flags = 0; unsigned long aligned_pitch; if (expect_accelerated_upload) flags |= BO_ALLOC_FOR_RENDER; - buffer = drm_intel_bo_alloc_tiled(intel->bufmgr, "region", + buffer = drm_intel_bo_alloc_tiled(screen->bufmgr, "region", width, height, cpp, &tiling, &aligned_pitch, flags); - region = intel_region_alloc_internal(intel, cpp, width, height, - aligned_pitch / cpp, buffer); - if (region == NULL) - return region; + return intel_region_alloc_internal(screen, cpp, width, height, + aligned_pitch / cpp, tiling, buffer); +} - region->tiling = tiling; +GLboolean +intel_region_flink(struct intel_region *region, uint32_t *name) +{ + if (region->name == 0) { + if (drm_intel_bo_flink(region->buffer, ®ion->name)) + return GL_FALSE; + + _mesa_HashInsert(region->screen->named_regions, + region->name, region); + } - return region; + *name = region->name; + + return GL_TRUE; } struct intel_region * -intel_region_alloc_for_handle(struct intel_context *intel, +intel_region_alloc_for_handle(struct intel_screen *screen, GLuint cpp, GLuint width, GLuint height, GLuint pitch, GLuint handle, const char *name) @@ -209,9 +217,9 @@ intel_region_alloc_for_handle(struct intel_context *intel, struct intel_region *region, *dummy; drm_intel_bo *buffer; int ret; - uint32_t bit_6_swizzle; + uint32_t bit_6_swizzle, tiling; - region = _mesa_HashLookup(intel->intelScreen->named_regions, handle); + region = _mesa_HashLookup(screen->named_regions, handle); if (region != NULL) { dummy = NULL; if (region->width != width || region->height != height || @@ -225,25 +233,26 @@ intel_region_alloc_for_handle(struct intel_context *intel, return dummy; } - buffer = intel_bo_gem_create_from_name(intel->bufmgr, name, handle); - - region = intel_region_alloc_internal(intel, cpp, - width, height, pitch, buffer); - if (region == NULL) - return region; - - ret = drm_intel_bo_get_tiling(region->buffer, ®ion->tiling, - &bit_6_swizzle); + buffer = intel_bo_gem_create_from_name(screen->bufmgr, name, handle); + if (buffer == NULL) + return NULL; + ret = drm_intel_bo_get_tiling(buffer, &tiling, &bit_6_swizzle); if (ret != 0) { fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n", handle, name, strerror(-ret)); - intel_region_release(®ion); + drm_intel_bo_unreference(buffer); + return NULL; + } + + region = intel_region_alloc_internal(screen, cpp, + width, height, pitch, tiling, buffer); + if (region == NULL) { + drm_intel_bo_unreference(buffer); return NULL; } region->name = handle; - region->screen = intel->intelScreen; - _mesa_HashInsert(intel->intelScreen->named_regions, handle, region); + _mesa_HashInsert(screen->named_regions, handle, region); return region; } diff --git a/src/mesa/drivers/dri/intel/intel_regions.h b/src/mesa/drivers/dri/intel/intel_regions.h index 6bbed32f2a..8464a5e937 100644 --- a/src/mesa/drivers/dri/intel/intel_regions.h +++ b/src/mesa/drivers/dri/intel/intel_regions.h @@ -76,18 +76,21 @@ struct intel_region /* Allocate a refcounted region. Pointers to regions should only be * copied by calling intel_reference_region(). */ -struct intel_region *intel_region_alloc(struct intel_context *intel, +struct intel_region *intel_region_alloc(struct intel_screen *screen, uint32_t tiling, GLuint cpp, GLuint width, GLuint height, GLboolean expect_accelerated_upload); struct intel_region * -intel_region_alloc_for_handle(struct intel_context *intel, +intel_region_alloc_for_handle(struct intel_screen *screen, GLuint cpp, GLuint width, GLuint height, GLuint pitch, unsigned int handle, const char *name); +GLboolean +intel_region_flink(struct intel_region *region, uint32_t *name); + void intel_region_reference(struct intel_region **dst, struct intel_region *src); diff --git a/src/mesa/drivers/dri/intel/intel_screen.c b/src/mesa/drivers/dri/intel/intel_screen.c index 15a465c640..0a542a7303 100644 --- a/src/mesa/drivers/dri/intel/intel_screen.c +++ b/src/mesa/drivers/dri/intel/intel_screen.c @@ -70,7 +70,7 @@ PUBLIC const char __driConfigOptions[] = DRI_CONF_DESC(en, "Enable early Z in classic mode (unstable, 945-only).") DRI_CONF_OPT_END - DRI_CONF_OPT_BEGIN(fragment_shader, bool, false) + DRI_CONF_OPT_BEGIN(fragment_shader, bool, true) DRI_CONF_DESC(en, "Enable limited ARB_fragment_shader support on 915/945.") DRI_CONF_OPT_END @@ -159,7 +159,8 @@ intel_create_image_from_name(__DRIcontext *context, image->data = loaderPrivate; cpp = _mesa_get_format_bytes(image->format); - image->region = intel_region_alloc_for_handle(intel, cpp, width, height, + image->region = intel_region_alloc_for_handle(intel->intelScreen, + cpp, width, height, pitch, name, "image"); if (image->region == NULL) { FREE(image); @@ -206,11 +207,79 @@ intel_destroy_image(__DRIimage *image) FREE(image); } +static __DRIimage * +intel_create_image(__DRIscreen *screen, + int width, int height, int format, + unsigned int use, + void *loaderPrivate) +{ + __DRIimage *image; + struct intel_screen *intelScreen = screen->private; + int cpp; + + image = CALLOC(sizeof *image); + if (image == NULL) + return NULL; + + switch (format) { + case __DRI_IMAGE_FORMAT_RGB565: + image->format = MESA_FORMAT_RGB565; + image->internal_format = GL_RGB; + image->data_type = GL_UNSIGNED_BYTE; + break; + case __DRI_IMAGE_FORMAT_XRGB8888: + image->format = MESA_FORMAT_XRGB8888; + image->internal_format = GL_RGB; + image->data_type = GL_UNSIGNED_BYTE; + break; + case __DRI_IMAGE_FORMAT_ARGB8888: + image->format = MESA_FORMAT_ARGB8888; + image->internal_format = GL_RGBA; + image->data_type = GL_UNSIGNED_BYTE; + break; + default: + free(image); + return NULL; + } + + image->data = loaderPrivate; + cpp = _mesa_get_format_bytes(image->format); + + image->region = + intel_region_alloc(intelScreen, I915_TILING_NONE, + cpp, width, height, GL_TRUE); + if (image->region == NULL) { + FREE(image); + return NULL; + } + + return image; +} + +static GLboolean +intel_query_image(__DRIimage *image, int attrib, int *value) +{ + switch (attrib) { + case __DRI_IMAGE_ATTRIB_STRIDE: + *value = image->region->pitch * image->region->cpp; + return GL_TRUE; + case __DRI_IMAGE_ATTRIB_HANDLE: + *value = image->region->buffer->handle; + return GL_TRUE; + case __DRI_IMAGE_ATTRIB_NAME: + return intel_region_flink(image->region, (uint32_t *) value); + default: + return GL_FALSE; + } +} + static struct __DRIimageExtensionRec intelImageExtension = { { __DRI_IMAGE, __DRI_IMAGE_VERSION }, intel_create_image_from_name, intel_create_image_from_renderbuffer, intel_destroy_image, + intel_create_image, + intel_query_image }; static const __DRIextension *intelScreenExtensions[] = { diff --git a/src/mesa/drivers/dri/intel/intel_tex.h b/src/mesa/drivers/dri/intel/intel_tex.h index 4bb012dc65..cd77dd5b8e 100644 --- a/src/mesa/drivers/dri/intel/intel_tex.h +++ b/src/mesa/drivers/dri/intel/intel_tex.h @@ -31,8 +31,6 @@ #include "main/mtypes.h" #include "main/formats.h" #include "intel_context.h" -#include "texmem.h" - void intelInitTextureFuncs(struct dd_function_table *functions); diff --git a/src/mesa/drivers/dri/nouveau/nouveau_driver.c b/src/mesa/drivers/dri/nouveau/nouveau_driver.c index 4ec864c181..6452fe218e 100644 --- a/src/mesa/drivers/dri/nouveau/nouveau_driver.c +++ b/src/mesa/drivers/dri/nouveau/nouveau_driver.c @@ -138,5 +138,7 @@ nouveau_driver_functions_init(struct dd_function_table *functions) functions->DrawPixels = _mesa_meta_DrawPixels; functions->CopyPixels = _mesa_meta_CopyPixels; functions->Bitmap = _mesa_meta_Bitmap; +#if FEATURE_EXT_framebuffer_blit functions->BlitFramebuffer = _mesa_meta_BlitFramebuffer; +#endif } diff --git a/src/mesa/drivers/dri/nouveau/nouveau_fbo.c b/src/mesa/drivers/dri/nouveau/nouveau_fbo.c index bd1273beea..32d8f2d0f9 100644 --- a/src/mesa/drivers/dri/nouveau/nouveau_fbo.c +++ b/src/mesa/drivers/dri/nouveau/nouveau_fbo.c @@ -262,10 +262,12 @@ nouveau_finish_render_texture(GLcontext *ctx, void nouveau_fbo_functions_init(struct dd_function_table *functions) { +#if FEATURE_EXT_framebuffer_object functions->NewFramebuffer = nouveau_framebuffer_new; functions->NewRenderbuffer = nouveau_renderbuffer_new; functions->BindFramebuffer = nouveau_bind_framebuffer; functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer; functions->RenderTexture = nouveau_render_texture; functions->FinishRenderTexture = nouveau_finish_render_texture; +#endif } diff --git a/src/mesa/drivers/dri/r300/compiler/Makefile b/src/mesa/drivers/dri/r300/compiler/Makefile index 3167d49bca..d0eb170784 100644 --- a/src/mesa/drivers/dri/r300/compiler/Makefile +++ b/src/mesa/drivers/dri/r300/compiler/Makefile @@ -23,6 +23,7 @@ C_SOURCES = \ radeon_dataflow_deadcode.c \ radeon_dataflow_swizzles.c \ radeon_optimize.c \ + radeon_remove_constants.c \ radeon_rename_regs.c \ r3xx_fragprog.c \ r300_fragprog.c \ diff --git a/src/mesa/drivers/dri/r300/compiler/SConscript b/src/mesa/drivers/dri/r300/compiler/SConscript index c6f47a6f8a..847857b142 100755 --- a/src/mesa/drivers/dri/r300/compiler/SConscript +++ b/src/mesa/drivers/dri/r300/compiler/SConscript @@ -22,6 +22,7 @@ r300compiler = env.ConvenienceLibrary( 'radeon_pair_schedule.c', 'radeon_pair_regalloc.c', 'radeon_optimize.c', + 'radeon_remove_constants.c', 'radeon_rename_regs.c', 'radeon_emulate_branches.c', 'radeon_emulate_loops.c', diff --git a/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c b/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c index d2fa816894..8613ec5109 100644 --- a/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c +++ b/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c @@ -30,6 +30,7 @@ #include "radeon_program_alu.h" #include "radeon_program_tex.h" #include "radeon_rename_regs.h" +#include "radeon_remove_constants.h" #include "r300_fragprog.h" #include "r300_fragprog_swizzle.h" #include "r500_fragprog.h" @@ -180,6 +181,13 @@ void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c) debug_program_log(c, "after dataflow passes"); + if (c->Base.remove_unused_constants) { + rc_remove_unused_constants(&c->Base, + &c->code->constants_remap_table); + + debug_program_log(c, "after constants cleanup"); + } + if(!c->Base.is_r500) { /* This pass makes it easier for the scheduler to group TEX * instructions and reduces the chances of creating too @@ -224,4 +232,14 @@ void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c) r300FragmentProgramDump(c->code); } } + + /* Check the number of constants. */ + if (!c->Base.Error) { + unsigned max = c->Base.is_r500 ? R500_PFS_NUM_CONST_REGS : R300_PFS_NUM_CONST_REGS; + + if (c->Base.Program.Constants.Count > max) { + rc_error(&c->Base, "Too many constants. Max: %i, Got: %i\n", + max, c->Base.Program.Constants.Count); + } + } } diff --git a/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c b/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c index 666c9c2a7a..b05b3aabf3 100644 --- a/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c +++ b/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c @@ -31,6 +31,7 @@ #include "radeon_swizzle.h" #include "radeon_emulate_branches.h" #include "radeon_emulate_loops.h" +#include "radeon_remove_constants.h" struct loop { int BgnLoop; @@ -465,7 +466,7 @@ static void translate_vertex_program(struct r300_vertex_program_compiler * compi { struct rc_instruction *rci; - struct loop * loops; + struct loop * loops = NULL; int current_loop_depth = 0; int loops_reserved = 0; @@ -484,6 +485,21 @@ static void translate_vertex_program(struct r300_vertex_program_compiler * compi if (!valid_dst(compiler->code, &vpi->DstReg)) continue; + if (rc_get_opcode_info(vpi->Opcode)->HasDstReg) { + /* Relative addressing of destination operands is not supported yet. */ + if (vpi->DstReg.RelAddr) { + rc_error(&compiler->Base, "Vertex program does not support relative " + "addressing of destination operands (yet).\n"); + return; + } + + /* Neither is Saturate. */ + if (vpi->SaturateMode != RC_SATURATE_NONE) { + rc_error(&compiler->Base, "Vertex program does not support the Saturate " + "modifier (yet).\n"); + } + } + if (compiler->code->length >= R500_VS_MAX_ALU_DWORDS || (compiler->code->length >= R300_VS_MAX_ALU_DWORDS && !compiler->Base.is_r500)) { rc_error(&compiler->Base, "Vertex program has too many instructions\n"); @@ -543,10 +559,16 @@ static void translate_vertex_program(struct r300_vertex_program_compiler * compi } case RC_OPCODE_ENDLOOP: { - struct loop * l = &loops[current_loop_depth - 1]; - unsigned int act_addr = l->BgnLoop - 1; - unsigned int last_addr = (compiler->code->length / 4) - 1; - unsigned int ret_addr = l->BgnLoop; + struct loop * l; + unsigned int act_addr; + unsigned int last_addr; + unsigned int ret_addr; + + assert(loops); + l = &loops[current_loop_depth - 1]; + act_addr = l->BgnLoop - 1; + last_addr = (compiler->code->length / 4) - 1; + ret_addr = l->BgnLoop; if (loops_reserved >= R300_VS_MAX_FC_OPS) { rc_error(&compiler->Base, @@ -624,10 +646,9 @@ static void allocate_temporary_registers(struct r300_vertex_program_compiler * c struct temporary_allocation * ta; unsigned int i, j; - compiler->code->num_temporaries = 0; memset(hwtemps, 0, sizeof(hwtemps)); - /* Pass 1: Count original temporaries and allocate structures */ + /* Pass 1: Count original temporaries. */ for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); @@ -645,12 +666,30 @@ static void allocate_temporary_registers(struct r300_vertex_program_compiler * c } } } + compiler->code->num_temporaries = num_orig_temps; + + /* Pass 2: If there is relative addressing of temporaries, we cannot change register indices. Give up. */ + for (inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info *opcode = rc_get_opcode_info(inst->U.I.Opcode); + + if (opcode->HasDstReg) + if (inst->U.I.DstReg.RelAddr) + return; + for (i = 0; i < opcode->NumSrcRegs; ++i) { + if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY && + inst->U.I.SrcReg[i].RelAddr) { + return; + } + } + } + + compiler->code->num_temporaries = 0; ta = (struct temporary_allocation*)memory_pool_malloc(&compiler->Base.Pool, sizeof(struct temporary_allocation) * num_orig_temps); memset(ta, 0, sizeof(struct temporary_allocation) * num_orig_temps); - /* Pass 2: Determine original temporary lifetimes */ + /* Pass 3: Determine original temporary lifetimes */ for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); /* Instructions inside of loops need to use the ENDLOOP @@ -685,7 +724,7 @@ static void allocate_temporary_registers(struct r300_vertex_program_compiler * c } } - /* Pass 3: Register allocation */ + /* Pass 4: Register allocation */ for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); @@ -853,6 +892,76 @@ static int swizzle_is_native(rc_opcode opcode, struct rc_src_register reg) return 1; } +static void transform_negative_addressing(struct r300_vertex_program_compiler *c, + struct rc_instruction *arl, + struct rc_instruction *end, + int min_offset) +{ + struct rc_instruction *inst, *add; + unsigned const_swizzle; + + /* Transform ARL */ + add = rc_insert_new_instruction(&c->Base, arl->Prev); + add->U.I.Opcode = RC_OPCODE_ADD; + add->U.I.DstReg.File = RC_FILE_TEMPORARY; + add->U.I.DstReg.Index = rc_find_free_temporary(&c->Base); + add->U.I.DstReg.WriteMask = RC_MASK_X; + add->U.I.SrcReg[0] = arl->U.I.SrcReg[0]; + add->U.I.SrcReg[1].File = RC_FILE_CONSTANT; + add->U.I.SrcReg[1].Index = rc_constants_add_immediate_scalar(&c->Base.Program.Constants, + min_offset, &const_swizzle); + add->U.I.SrcReg[1].Swizzle = const_swizzle; + + arl->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + arl->U.I.SrcReg[0].Index = add->U.I.DstReg.Index; + arl->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XXXX; + + /* Rewrite offsets up to and excluding inst. */ + for (inst = arl->Next; inst != end; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + for (unsigned i = 0; i < opcode->NumSrcRegs; i++) + if (inst->U.I.SrcReg[i].RelAddr) + inst->U.I.SrcReg[i].Index -= min_offset; + } +} + +static void rc_emulate_negative_addressing(struct r300_vertex_program_compiler *c) +{ + struct rc_instruction *inst, *lastARL = NULL; + int min_offset = 0; + + for (inst = c->Base.Program.Instructions.Next; inst != &c->Base.Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + if (inst->U.I.Opcode == RC_OPCODE_ARL) { + if (lastARL != NULL && min_offset < 0) + transform_negative_addressing(c, lastARL, inst, min_offset); + + lastARL = inst; + min_offset = 0; + continue; + } + + for (unsigned i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->U.I.SrcReg[i].RelAddr && + inst->U.I.SrcReg[i].Index < 0) { + /* ARL must precede any indirect addressing. */ + if (lastARL == NULL) { + rc_error(&c->Base, "Vertex shader: Found relative addressing without ARL."); + return; + } + + if (inst->U.I.SrcReg[i].Index < min_offset) + min_offset = inst->U.I.SrcReg[i].Index; + } + } + } + + if (lastARL != NULL && min_offset < 0) + transform_negative_addressing(c, lastARL, inst, min_offset); +} + static void debug_program_log(struct r300_vertex_program_compiler* c, const char * where) { if (c->Base.Debug) { @@ -868,44 +977,56 @@ static struct rc_swizzle_caps r300_vertprog_swizzle_caps = { }; -void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* compiler) +void r3xx_compile_vertex_program(struct r300_vertex_program_compiler *c) { struct emulate_loop_state loop_state; - compiler->Base.SwizzleCaps = &r300_vertprog_swizzle_caps; + c->Base.SwizzleCaps = &r300_vertprog_swizzle_caps; - addArtificialOutputs(compiler); + addArtificialOutputs(c); - debug_program_log(compiler, "before compilation"); + debug_program_log(c, "before compilation"); - if (compiler->Base.is_r500) - rc_transform_loops(&compiler->Base, &loop_state, R500_VS_MAX_ALU); + if (c->Base.is_r500) + rc_transform_loops(&c->Base, &loop_state, R500_VS_MAX_ALU); else - rc_transform_loops(&compiler->Base, &loop_state, R300_VS_MAX_ALU); + rc_transform_loops(&c->Base, &loop_state, R300_VS_MAX_ALU); + if (c->Base.Error) + return; - debug_program_log(compiler, "after emulate loops"); + debug_program_log(c, "after emulate loops"); - if (!compiler->Base.is_r500) { - rc_emulate_branches(&compiler->Base); - debug_program_log(compiler, "after emulate branches"); + if (!c->Base.is_r500) { + rc_emulate_branches(&c->Base); + if (c->Base.Error) + return; + debug_program_log(c, "after emulate branches"); } - if (compiler->Base.is_r500) { + rc_emulate_negative_addressing(c); + + debug_program_log(c, "after negative addressing emulation"); + + if (c->Base.is_r500) { struct radeon_program_transformation transformations[] = { { &r300_transform_vertex_alu, 0 }, { &r300_transform_trig_scale_vertex, 0 } }; - radeonLocalTransform(&compiler->Base, 2, transformations); + radeonLocalTransform(&c->Base, 2, transformations); + if (c->Base.Error) + return; - debug_program_log(compiler, "after native rewrite"); + debug_program_log(c, "after native rewrite"); } else { struct radeon_program_transformation transformations[] = { { &r300_transform_vertex_alu, 0 }, { &radeonTransformTrigSimple, 0 } }; - radeonLocalTransform(&compiler->Base, 2, transformations); + radeonLocalTransform(&c->Base, 2, transformations); + if (c->Base.Error) + return; - debug_program_log(compiler, "after native rewrite"); + debug_program_log(c, "after native rewrite"); /* Note: This pass has to be done seperately from ALU rewrite, * because it needs to check every instruction. @@ -913,9 +1034,11 @@ void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* compiler) struct radeon_program_transformation transformations2[] = { { &transform_nonnative_modifiers, 0 }, }; - radeonLocalTransform(&compiler->Base, 1, transformations2); + radeonLocalTransform(&c->Base, 1, transformations2); + if (c->Base.Error) + return; - debug_program_log(compiler, "after emulate modifiers"); + debug_program_log(c, "after emulate modifiers"); } { @@ -926,30 +1049,58 @@ void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* compiler) struct radeon_program_transformation transformations[] = { { &transform_source_conflicts, 0 }, }; - radeonLocalTransform(&compiler->Base, 1, transformations); + radeonLocalTransform(&c->Base, 1, transformations); + if (c->Base.Error) + return; } - debug_program_log(compiler, "after source conflict resolve"); + debug_program_log(c, "after source conflict resolve"); - rc_dataflow_deadcode(&compiler->Base, &dataflow_outputs_mark_used, compiler); + rc_dataflow_deadcode(&c->Base, &dataflow_outputs_mark_used, c); + if (c->Base.Error) + return; - debug_program_log(compiler, "after deadcode"); + debug_program_log(c, "after deadcode"); - rc_dataflow_swizzles(&compiler->Base); + rc_dataflow_swizzles(&c->Base); + if (c->Base.Error) + return; - allocate_temporary_registers(compiler); + debug_program_log(c, "after dataflow"); - debug_program_log(compiler, "after dataflow"); + allocate_temporary_registers(c); + if (c->Base.Error) + return; - translate_vertex_program(compiler); + debug_program_log(c, "after register allocation"); - rc_constants_copy(&compiler->code->constants, &compiler->Base.Program.Constants); + if (c->Base.remove_unused_constants) { + rc_remove_unused_constants(&c->Base, + &c->code->constants_remap_table); + if (c->Base.Error) + return; - compiler->code->InputsRead = compiler->Base.Program.InputsRead; - compiler->code->OutputsWritten = compiler->Base.Program.OutputsWritten; + debug_program_log(c, "after constants cleanup"); + } - if (compiler->Base.Debug) { + translate_vertex_program(c); + if (c->Base.Error) + return; + + rc_constants_copy(&c->code->constants, &c->Base.Program.Constants); + + c->code->InputsRead = c->Base.Program.InputsRead; + c->code->OutputsWritten = c->Base.Program.OutputsWritten; + + if (c->Base.Debug) { fprintf(stderr, "Final vertex program code:\n"); - r300_vertex_program_dump(compiler); + r300_vertex_program_dump(c); + } + + /* Check the number of constants. */ + if (!c->Base.Error && + c->Base.Program.Constants.Count > 256) { + rc_error(&c->Base, "Too many constants. Max: 256, Got: %i\n", + c->Base.Program.Constants.Count); } } diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_code.h b/src/mesa/drivers/dri/r300/compiler/radeon_code.h index 896246d203..f76676fae8 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_code.h +++ b/src/mesa/drivers/dri/r300/compiler/radeon_code.h @@ -235,6 +235,7 @@ struct rX00_fragment_program_code { unsigned writes_depth:1; struct rc_constant_list constants; + unsigned *constants_remap_table; }; @@ -266,6 +267,7 @@ struct r300_vertex_program_code { int outputs[VSF_MAX_OUTPUTS]; struct rc_constant_list constants; + unsigned *constants_remap_table; uint32_t InputsRead; uint32_t OutputsWritten; diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_compiler.h b/src/mesa/drivers/dri/r300/compiler/radeon_compiler.h index 7c42eb3ae5..5155b912e1 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_compiler.h +++ b/src/mesa/drivers/dri/r300/compiler/radeon_compiler.h @@ -39,9 +39,12 @@ struct radeon_compiler { char * ErrorMsg; /* Hardware specification. */ - unsigned is_r500; + unsigned is_r500:1; unsigned max_temp_regs; + /* Whether to remove unused constants and empty holes in constant space. */ + unsigned remove_unused_constants:1; + /** * Variables used internally, not be touched by callers * of the compiler diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_deadcode.c b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_deadcode.c index faf531b412..acdb371de9 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_deadcode.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_deadcode.c @@ -157,8 +157,12 @@ static void update_instruction(struct deadcode_state * s, struct rc_instruction unsigned char * pused = get_used_ptr(s, inst->U.I.DstReg.File, inst->U.I.DstReg.Index); if (pused) { usedmask = *pused & inst->U.I.DstReg.WriteMask; - *pused &= ~usedmask; + if (!inst->U.I.DstReg.RelAddr) + *pused &= ~usedmask; } + + if (inst->U.I.DstReg.RelAddr) + mark_used(s, RC_FILE_ADDRESS, 0, RC_MASK_X); } insts->WriteMask |= usedmask; @@ -213,6 +217,7 @@ void rc_dataflow_deadcode(struct radeon_compiler * c, rc_dataflow_mark_outputs_f { struct deadcode_state s; unsigned int nr_instructions; + unsigned has_temp_reladdr_src = 0; memset(&s, 0, sizeof(s)); s.C = c; @@ -300,6 +305,30 @@ void rc_dataflow_deadcode(struct radeon_compiler * c, rc_dataflow_mark_outputs_f rc_error(c, "%s: Unhandled control flow instruction %s\n", __FUNCTION__, opcode->Name); } } + + if (!has_temp_reladdr_src) { + for (unsigned i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY && + inst->U.I.SrcReg[i].RelAddr) { + /* If there is a register read from a temporary file with relative addressing, + * mark all preceding written registers as used. */ + for (struct rc_instruction *ptr = inst->Prev; + ptr != &c->Program.Instructions; + ptr = ptr->Prev) { + if (opcode->HasDstReg && + ptr->U.I.DstReg.File == RC_FILE_TEMPORARY && + ptr->U.I.DstReg.WriteMask) { + mark_used(&s, + ptr->U.I.DstReg.File, + ptr->U.I.DstReg.Index, + ptr->U.I.DstReg.WriteMask); + } + } + + has_temp_reladdr_src = 1; + } + } + } } update_instruction(&s, inst); diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.c b/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.c index 2ea830be7f..da495a3afa 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.c @@ -95,6 +95,12 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { .IsComponentwise = 1 }, { + .Opcode = RC_OPCODE_DP2, + .Name = "DP2", + .NumSrcRegs = 2, + .HasDstReg = 1 + }, + { .Opcode = RC_OPCODE_DP3, .Name = "DP3", .NumSrcRegs = 2, @@ -295,6 +301,13 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { .IsComponentwise = 1 }, { + .Opcode = RC_OPCODE_SSG, + .Name = "SSG", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { .Opcode = RC_OPCODE_SUB, .Name = "SUB", .NumSrcRegs = 2, @@ -435,6 +448,10 @@ void rc_compute_sources_for_writemask( case RC_OPCODE_ARL: srcmasks[0] |= RC_MASK_X; break; + case RC_OPCODE_DP2: + srcmasks[0] |= RC_MASK_XY; + srcmasks[1] |= RC_MASK_XY; + break; case RC_OPCODE_DP3: srcmasks[0] |= RC_MASK_XYZ; srcmasks[1] |= RC_MASK_XYZ; diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.h b/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.h index 6e18d6eb3f..d3f639c870 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.h +++ b/src/mesa/drivers/dri/r300/compiler/radeon_opcodes.h @@ -64,6 +64,9 @@ typedef enum { * dst.c = d src0.c / dy */ RC_OPCODE_DDY, + /** scalar instruction: dst = src0.x*src1.x + src0.y*src1.y */ + RC_OPCODE_DP2, + /** scalar instruction: dst = src0.x*src1.x + src0.y*src1.y + src0.z*src1.z */ RC_OPCODE_DP3, @@ -154,6 +157,9 @@ typedef enum { /** vec4 instruction: dst.c = (src0.c != src1.c) ? 1.0 : 0.0 */ RC_OPCODE_SNE, + /** vec4 instruction: dst.c = (src0.c < 0 ?) -1 : ((src0.c > 0) : 1 : 0) */ + RC_OPCODE_SSG, + /** vec4 instruction: dst.c = src0.c - src1.c */ RC_OPCODE_SUB, diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_pair_translate.c b/src/mesa/drivers/dri/r300/compiler/radeon_pair_translate.c index 407a0a55ee..8327e9aced 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_pair_translate.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_pair_translate.c @@ -230,6 +230,34 @@ static void set_pair_instruction(struct r300_fragment_program_compiler *c, } +static void check_opcode_support(struct r300_fragment_program_compiler *c, + struct rc_sub_instruction *inst) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode); + + if (opcode->HasDstReg) { + if (inst->DstReg.RelAddr) { + rc_error(&c->Base, "Fragment program does not support relative addressing " + "of destination operands.\n"); + return; + } + + if (inst->SaturateMode == RC_SATURATE_MINUS_PLUS_ONE) { + rc_error(&c->Base, "Fragment program does not support signed Saturate.\n"); + return; + } + } + + for (unsigned i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->SrcReg[i].RelAddr) { + rc_error(&c->Base, "Fragment program does not support relative addressing " + " of source operands.\n"); + return; + } + } +} + + /** * Translate all ALU instructions into corresponding pair instructions, * performing no other changes. @@ -249,6 +277,8 @@ void rc_pair_translate(struct r300_fragment_program_compiler *c) struct rc_sub_instruction copy = inst->U.I; + check_opcode_support(c, ©); + final_rewrite(©); inst->Type = RC_INSTRUCTION_PAIR; set_pair_instruction(c, &inst->U.P, ©); diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program_alu.c b/src/mesa/drivers/dri/r300/compiler/radeon_program_alu.c index 857aae5514..704a7bb2d2 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_program_alu.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_alu.c @@ -216,18 +216,18 @@ static void transform_CEIL(struct radeon_compiler* c, rc_remove_instruction(inst); } -static void transform_DP3(struct radeon_compiler* c, +static void transform_DP2(struct radeon_compiler* c, struct rc_instruction* inst) { struct rc_src_register src0 = inst->U.I.SrcReg[0]; struct rc_src_register src1 = inst->U.I.SrcReg[1]; - src0.Negate &= ~RC_MASK_W; - src0.Swizzle &= ~(7 << (3 * 3)); - src0.Swizzle |= RC_SWIZZLE_ZERO << (3 * 3); - src1.Negate &= ~RC_MASK_W; - src1.Swizzle &= ~(7 << (3 * 3)); - src1.Swizzle |= RC_SWIZZLE_ZERO << (3 * 3); - emit2(c, inst->Prev, RC_OPCODE_DP4, inst->U.I.SaturateMode, inst->U.I.DstReg, src0, src1); + src0.Negate &= ~(RC_MASK_Z | RC_MASK_W); + src0.Swizzle &= ~(63 << (3 * 2)); + src0.Swizzle |= (RC_SWIZZLE_ZERO << (3 * 2)) | (RC_SWIZZLE_ZERO << (3 * 3)); + src1.Negate &= ~(RC_MASK_Z | RC_MASK_W); + src1.Swizzle &= ~(63 << (3 * 2)); + src1.Swizzle |= (RC_SWIZZLE_ZERO << (3 * 2)) | (RC_SWIZZLE_ZERO << (3 * 3)); + emit2(c, inst->Prev, RC_OPCODE_DP3, inst->U.I.SaturateMode, inst->U.I.DstReg, src0, src1); rc_remove_instruction(inst); } @@ -464,6 +464,43 @@ static void transform_SNE(struct radeon_compiler* c, rc_remove_instruction(inst); } +static void transform_SSG(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + /* result = sign(x) + * + * CMP tmp0, -x, 1, 0 + * CMP tmp1, x, 1, 0 + * ADD result, tmp0, -tmp1; + */ + unsigned tmp0, tmp1; + + /* 0 < x */ + tmp0 = rc_find_free_temporary(c); + emit3(c, inst->Prev, RC_OPCODE_CMP, 0, + dstregtmpmask(tmp0, inst->U.I.DstReg.WriteMask), + negate(inst->U.I.SrcReg[0]), + builtin_one, + builtin_zero); + + /* x < 0 */ + tmp1 = rc_find_free_temporary(c); + emit3(c, inst->Prev, RC_OPCODE_CMP, 0, + dstregtmpmask(tmp1, inst->U.I.DstReg.WriteMask), + inst->U.I.SrcReg[0], + builtin_one, + builtin_zero); + + /* Either both are zero, or one of them is one and the other is zero. */ + /* result = tmp0 - tmp1 */ + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, + inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, tmp0), + negate(srcreg(RC_FILE_TEMPORARY, tmp1))); + + rc_remove_instruction(inst); +} + static void transform_SUB(struct radeon_compiler* c, struct rc_instruction* inst) { @@ -516,6 +553,7 @@ int radeonTransformALU( switch(inst->U.I.Opcode) { case RC_OPCODE_ABS: transform_ABS(c, inst); return 1; case RC_OPCODE_CEIL: transform_CEIL(c, inst); return 1; + case RC_OPCODE_DP2: transform_DP2(c, inst); return 1; case RC_OPCODE_DPH: transform_DPH(c, inst); return 1; case RC_OPCODE_DST: transform_DST(c, inst); return 1; case RC_OPCODE_FLR: transform_FLR(c, inst); return 1; @@ -530,6 +568,7 @@ int radeonTransformALU( case RC_OPCODE_SLE: transform_SLE(c, inst); return 1; case RC_OPCODE_SLT: transform_SLT(c, inst); return 1; case RC_OPCODE_SNE: transform_SNE(c, inst); return 1; + case RC_OPCODE_SSG: transform_SSG(c, inst); return 1; case RC_OPCODE_SUB: transform_SUB(c, inst); return 1; case RC_OPCODE_SWZ: transform_SWZ(c, inst); return 1; case RC_OPCODE_XPD: transform_XPD(c, inst); return 1; @@ -577,6 +616,29 @@ static void transform_r300_vertex_CMP(struct radeon_compiler* c, rc_remove_instruction(inst); } +static void transform_r300_vertex_DP2(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_instruction *next_inst = inst->Next; + transform_DP2(c, inst); + next_inst->Prev->U.I.Opcode = RC_OPCODE_DP4; +} + +static void transform_r300_vertex_DP3(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_src_register src0 = inst->U.I.SrcReg[0]; + struct rc_src_register src1 = inst->U.I.SrcReg[1]; + src0.Negate &= ~RC_MASK_W; + src0.Swizzle &= ~(7 << (3 * 3)); + src0.Swizzle |= RC_SWIZZLE_ZERO << (3 * 3); + src1.Negate &= ~RC_MASK_W; + src1.Swizzle &= ~(7 << (3 * 3)); + src1.Swizzle |= RC_SWIZZLE_ZERO << (3 * 3); + emit2(c, inst->Prev, RC_OPCODE_DP4, inst->U.I.SaturateMode, inst->U.I.DstReg, src0, src1); + rc_remove_instruction(inst); +} + static void transform_r300_vertex_fix_LIT(struct radeon_compiler* c, struct rc_instruction* inst) { @@ -672,6 +734,41 @@ static void transform_r300_vertex_SLE(struct radeon_compiler* c, inst->U.I.SrcReg[1].Negate ^= RC_MASK_XYZW; } +static void transform_r300_vertex_SSG(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + /* result = sign(x) + * + * SLT tmp0, 0, x; + * SLT tmp1, x, 0; + * ADD result, tmp0, -tmp1; + */ + unsigned tmp0, tmp1; + + /* 0 < x */ + tmp0 = rc_find_free_temporary(c); + emit2(c, inst->Prev, RC_OPCODE_SLT, 0, + dstregtmpmask(tmp0, inst->U.I.DstReg.WriteMask), + builtin_zero, + inst->U.I.SrcReg[0]); + + /* x < 0 */ + tmp1 = rc_find_free_temporary(c); + emit2(c, inst->Prev, RC_OPCODE_SLT, 0, + dstregtmpmask(tmp1, inst->U.I.DstReg.WriteMask), + inst->U.I.SrcReg[0], + builtin_zero); + + /* Either both are zero, or one of them is one and the other is zero. */ + /* result = tmp0 - tmp1 */ + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, + inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, tmp0), + negate(srcreg(RC_FILE_TEMPORARY, tmp1))); + + rc_remove_instruction(inst); +} + /** * For use with radeonLocalTransform, this transforms non-native ALU * instructions of the r300 up to r500 vertex engine. @@ -685,7 +782,8 @@ int r300_transform_vertex_alu( case RC_OPCODE_ABS: transform_r300_vertex_ABS(c, inst); return 1; case RC_OPCODE_CEIL: transform_CEIL(c, inst); return 1; case RC_OPCODE_CMP: transform_r300_vertex_CMP(c, inst); return 1; - case RC_OPCODE_DP3: transform_DP3(c, inst); return 1; + case RC_OPCODE_DP2: transform_r300_vertex_DP2(c, inst); return 1; + case RC_OPCODE_DP3: transform_r300_vertex_DP3(c, inst); return 1; case RC_OPCODE_DPH: transform_DPH(c, inst); return 1; case RC_OPCODE_FLR: transform_FLR(c, inst); return 1; case RC_OPCODE_LIT: transform_r300_vertex_fix_LIT(c, inst); return 1; @@ -705,6 +803,7 @@ int r300_transform_vertex_alu( return 1; } return 0; + case RC_OPCODE_SSG: transform_r300_vertex_SSG(c, inst); return 1; case RC_OPCODE_SUB: transform_SUB(c, inst); return 1; case RC_OPCODE_SWZ: transform_SWZ(c, inst); return 1; case RC_OPCODE_XPD: transform_XPD(c, inst); return 1; diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c b/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c index 9c4b65f4c0..ddce590ee6 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_tex.c @@ -117,8 +117,8 @@ int radeonTransformTEX( struct rc_instruction * inst_rcp = NULL; struct rc_instruction * inst_mad; struct rc_instruction * inst_cmp; - unsigned tmp_texsample = rc_find_free_temporary(c); - unsigned tmp_sum = rc_find_free_temporary(c); + unsigned tmp_texsample; + unsigned tmp_sum; unsigned tmp_recip_w = 0; int pass, fail, tex; @@ -126,6 +126,7 @@ int radeonTransformTEX( struct rc_dst_register output_reg = inst->U.I.DstReg; /* Redirect TEX to a new temp. */ + tmp_texsample = rc_find_free_temporary(c); inst->U.I.DstReg.File = RC_FILE_TEMPORARY; inst->U.I.DstReg.Index = tmp_texsample; inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; @@ -144,6 +145,7 @@ int radeonTransformTEX( } /* Perspective-divide r by W (if it's TXP) and add the texture sample (see below). */ + tmp_sum = rc_find_free_temporary(c); inst_mad = rc_insert_new_instruction(c, inst_rcp ? inst_rcp : inst); inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY; inst_mad->U.I.DstReg.Index = tmp_sum; @@ -199,6 +201,8 @@ int radeonTransformTEX( inst_cmp->U.I.SrcReg[pass].File = RC_FILE_NONE; inst_cmp->U.I.SrcReg[pass].Swizzle = RC_SWIZZLE_1111; inst_cmp->U.I.SrcReg[fail] = shadow_ambient(compiler, inst->U.I.TexSrcUnit); + + assert(tmp_texsample != tmp_sum && tmp_sum != tmp_recip_w); } } diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_remove_constants.c b/src/mesa/drivers/dri/r300/compiler/radeon_remove_constants.c new file mode 100644 index 0000000000..be89e9fa5b --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_remove_constants.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2010 Marek Olšák <maraeo@gmail.com> + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "radeon_remove_constants.h" + +void rc_remove_unused_constants(struct radeon_compiler *c, + unsigned **out_remap_table) +{ + unsigned char *const_used; + unsigned *remap_table; + unsigned *inv_remap_table; + unsigned has_rel_addr = 0; + unsigned is_identity = 1; + unsigned are_externals_remapped = 0; + struct rc_constant *constants = c->Program.Constants.Constants; + + if (!c->Program.Constants.Count) { + *out_remap_table = NULL; + return; + } + + const_used = malloc(c->Program.Constants.Count); + memset(const_used, 0, c->Program.Constants.Count); + + /* Pass 1: Mark used constants. */ + for (struct rc_instruction *inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info *opcode = rc_get_opcode_info(inst->U.I.Opcode); + + for (unsigned i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->U.I.SrcReg[i].File == RC_FILE_CONSTANT) { + if (inst->U.I.SrcReg[i].RelAddr) { + has_rel_addr = 1; + } else { + const_used[inst->U.I.SrcReg[i].Index] = 1; + } + } + } + } + + /* Pass 2: If there is relative addressing, mark all externals as used. */ + if (has_rel_addr) { + for (unsigned i = 0; i < c->Program.Constants.Count; i++) + if (constants[i].Type == RC_CONSTANT_EXTERNAL) + const_used[i] = 1; + } + + /* Pass 3: Make the remapping table and remap constants. + * This pass removes unused constants simply by overwriting them by other constants. */ + remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned)); + inv_remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned)); + unsigned new_count = 0; + + for (unsigned i = 0; i < c->Program.Constants.Count; i++) { + if (const_used[i]) { + remap_table[new_count] = i; + inv_remap_table[i] = new_count; + + if (i != new_count) { + if (constants[i].Type == RC_CONSTANT_EXTERNAL) + are_externals_remapped = 1; + + constants[new_count] = constants[i]; + is_identity = 0; + } + new_count++; + } + } + + /* is_identity ==> new_count == old_count + * !is_identity ==> new_count < old_count */ + assert( is_identity || new_count < c->Program.Constants.Count); + assert(!(has_rel_addr && are_externals_remapped)); + + /* Pass 4: Redirect reads of all constants to their new locations. */ + if (!is_identity) { + for (struct rc_instruction *inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info *opcode = rc_get_opcode_info(inst->U.I.Opcode); + + for (unsigned i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->U.I.SrcReg[i].File == RC_FILE_CONSTANT) { + inst->U.I.SrcReg[i].Index = inv_remap_table[inst->U.I.SrcReg[i].Index]; + } + } + } + + } + + /* Set the new constant count. Note that new_count may be less than + * Count even though the remapping function is identity. In that case, + * the constants have been removed at the end of the array. */ + c->Program.Constants.Count = new_count; + + if (are_externals_remapped) { + *out_remap_table = remap_table; + } else { + *out_remap_table = NULL; + free(remap_table); + } + + free(const_used); + free(inv_remap_table); +} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_remove_constants.h b/src/mesa/drivers/dri/r300/compiler/radeon_remove_constants.h new file mode 100644 index 0000000000..0d3a26ca1c --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_remove_constants.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Marek Olšák <maraeo@gmail.com> + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef RADEON_REMOVE_CONSTANTS_H +#define RADEON_REMOVE_CONSTANTS_H + +#include "radeon_compiler.h" + +void rc_remove_unused_constants(struct radeon_compiler *c, + unsigned **out_remap_table); + +#endif diff --git a/src/mesa/drivers/dri/r300/r300_fragprog_common.c b/src/mesa/drivers/dri/r300/r300_fragprog_common.c index 95f4306f60..7b6521c748 100644 --- a/src/mesa/drivers/dri/r300/r300_fragprog_common.c +++ b/src/mesa/drivers/dri/r300/r300_fragprog_common.c @@ -38,7 +38,6 @@ #include "r300_fragprog_common.h" -#include "program/prog_parameter.h" #include "program/prog_print.h" #include "compiler/radeon_compiler.h" diff --git a/src/mesa/drivers/dri/r600/Makefile b/src/mesa/drivers/dri/r600/Makefile index 17915621ee..03c17540e0 100644 --- a/src/mesa/drivers/dri/r600/Makefile +++ b/src/mesa/drivers/dri/r600/Makefile @@ -59,6 +59,15 @@ DRIVER_SOURCES = \ r600_texstate.c \ r600_blit.c \ r700_debug.c \ + evergreen_context.c \ + evergreen_state.c \ + evergreen_tex.c \ + evergreen_ioctl.c \ + evergreen_render.c \ + evergreen_chip.c \ + evergreen_vertprog.c \ + evergreen_fragprog.c \ + evergreen_oglprog.c \ $(RADEON_COMMON_SOURCES) \ $(EGL_SOURCES) \ $(CS_SOURCES) diff --git a/src/mesa/drivers/dri/r600/evergreen_chip.c b/src/mesa/drivers/dri/r600/evergreen_chip.c new file mode 100644 index 0000000000..f925f215bc --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_chip.c @@ -0,0 +1,1289 @@ +/* + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#include "main/imports.h" +#include "main/glheader.h" +#include "main/simple_list.h" + +#include "r600_context.h" +#include "r600_cmdbuf.h" + +#include "evergreen_chip.h" +#include "evergreen_off.h" +#include "evergreen_diff.h" +#include "evergreen_fragprog.h" +#include "evergreen_vertprog.h" + +#include "radeon_mipmap_tree.h" + +void evergreenCreateChip(context_t *context) +{ + EVERGREEN_CHIP_CONTEXT * evergreen = + (EVERGREEN_CHIP_CONTEXT*) CALLOC(sizeof(EVERGREEN_CHIP_CONTEXT)); + + context->pChip = (void*)evergreen; +} + +#define EVERGREEN_ALLOC_STATE( ATOM, CHK, SZ, EMIT ) \ +do { \ + context->evergreen_atoms.ATOM.cmd_size = (SZ); \ + context->evergreen_atoms.ATOM.cmd = NULL; \ + context->evergreen_atoms.ATOM.name = #ATOM; \ + context->evergreen_atoms.ATOM.idx = 0; \ + context->evergreen_atoms.ATOM.check = check_##CHK; \ + context->evergreen_atoms.ATOM.dirty = GL_FALSE; \ + context->evergreen_atoms.ATOM.emit = (EMIT); \ + context->radeon.hw.max_state_size += (SZ); \ + insert_at_tail(&context->radeon.hw.atomlist, &context->evergreen_atoms.ATOM); \ +} while (0) + +/* +static void evergreen_init_query_stateobj(radeonContextPtr radeon, int SZ) +{ + radeon->query.queryobj.cmd_size = (SZ); + radeon->query.queryobj.cmd = NULL; + radeon->query.queryobj.name = "queryobj"; + radeon->query.queryobj.idx = 0; + radeon->query.queryobj.check = check_queryobj; + radeon->query.queryobj.dirty = GL_FALSE; + radeon->query.queryobj.emit = r700SendQueryBegin; + radeon->hw.max_state_size += (SZ); + insert_at_tail(&radeon->hw.atomlist, &radeon->query.queryobj); +} +*/ + +static int check_always(GLcontext *ctx, struct radeon_state_atom *atom) +{ + return atom->cmd_size; +} + +static void evergreenSendTexState(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + struct evergreen_vertex_program *vp = context->selected_vp; + + struct radeon_bo *bo = NULL; + unsigned int i; + unsigned int nBorderSet = 0; + BATCH_LOCALS(&context->radeon); + + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + for (i = 0; i < R700_TEXTURE_NUMBERUNITS; i++) { + if (ctx->Texture.Unit[i]._ReallyEnabled) { + radeonTexObj *t = evergreen->textures[i]; + + if (t) { + /* Tex resource */ + if (!t->image_override) { + bo = t->mt->bo; + } else { + bo = t->bo; + } + if (bo) + { + radeon_bo_unmap(bo); + + r700SyncSurf(context, bo, + RADEON_GEM_DOMAIN_GTT|RADEON_GEM_DOMAIN_VRAM, + 0, TC_ACTION_ENA_bit); + + BEGIN_BATCH_NO_AUTOSTATE(10 + 4); + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_RESOURCE, 8)); + + if( (1<<i) & vp->r700AsmCode.unVetTexBits ) + { /* vs texture */ + R600_OUT_BATCH((i + VERT_ATTRIB_MAX + EG_SQ_FETCH_RESOURCE_VS_OFFSET) * FETCH_RESOURCE_STRIDE); + } + else + { + R600_OUT_BATCH(i * EG_FETCH_RESOURCE_STRIDE); + } + + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_RESOURCE0); + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_RESOURCE1); + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_RESOURCE2); + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_RESOURCE3); + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_RESOURCE4); + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_RESOURCE5); + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_RESOURCE6); + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_RESOURCE7); + + R600_OUT_BATCH_RELOC(evergreen->textures[i]->SQ_TEX_RESOURCE2, + bo, + evergreen->textures[i]->SQ_TEX_RESOURCE2, + RADEON_GEM_DOMAIN_GTT|RADEON_GEM_DOMAIN_VRAM, 0, 0); + R600_OUT_BATCH_RELOC(evergreen->textures[i]->SQ_TEX_RESOURCE3, + bo, + evergreen->textures[i]->SQ_TEX_RESOURCE3, + RADEON_GEM_DOMAIN_GTT|RADEON_GEM_DOMAIN_VRAM, 0, 0); + END_BATCH(); + COMMIT_BATCH(); + } + /* Tex sampler */ + BEGIN_BATCH_NO_AUTOSTATE(5); + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_SAMPLER, 3)); + + if( (1<<i) & vp->r700AsmCode.unVetTexBits ) + { /* vs texture */ + R600_OUT_BATCH((i+SQ_TEX_SAMPLER_VS_OFFSET) * 3); + } + else + { + R600_OUT_BATCH(i * 3); + } + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_SAMPLER0); + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_SAMPLER1); + R600_OUT_BATCH(evergreen->textures[i]->SQ_TEX_SAMPLER2); + + END_BATCH(); + COMMIT_BATCH(); + + /* Tex border color */ + if(0 == nBorderSet) + { + BEGIN_BATCH_NO_AUTOSTATE(2 + 4); + R600_OUT_BATCH_REGSEQ(EG_TD_PS_BORDER_COLOR_RED, 4); + R600_OUT_BATCH(evergreen->textures[i]->TD_PS_SAMPLER0_BORDER_RED); + R600_OUT_BATCH(evergreen->textures[i]->TD_PS_SAMPLER0_BORDER_GREEN); + R600_OUT_BATCH(evergreen->textures[i]->TD_PS_SAMPLER0_BORDER_BLUE); + R600_OUT_BATCH(evergreen->textures[i]->TD_PS_SAMPLER0_BORDER_ALPHA); + END_BATCH(); + COMMIT_BATCH(); + + nBorderSet = 1; + } + } + } + } +} + +static int check_evergreen_tx(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + unsigned int i, count = 0; + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + for (i = 0; i < R700_TEXTURE_NUMBERUNITS; i++) { + if (ctx->Texture.Unit[i]._ReallyEnabled) { + radeonTexObj *t = evergreen->textures[i]; + if (t) + count++; + } + } + radeon_print(RADEON_STATE, RADEON_TRACE, "%s %d\n", __func__, count); + return count * 37 + 6; +} + +static void evergreenSendSQConfig(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + BEGIN_BATCH_NO_AUTOSTATE(19); + //6 + EVERGREEN_OUT_BATCH_REGVAL(EG_SPI_CONFIG_CNTL, evergreen->evergreen_config.SPI_CONFIG_CNTL.u32All); + EVERGREEN_OUT_BATCH_REGVAL(EG_SPI_CONFIG_CNTL_1, evergreen->evergreen_config.SPI_CONFIG_CNTL_1.u32All); + //6 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_CONFIG, 4); + R600_OUT_BATCH(evergreen->evergreen_config.SQ_CONFIG.u32All); + R600_OUT_BATCH(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_1.u32All); + R600_OUT_BATCH(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_2.u32All); + R600_OUT_BATCH(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_3.u32All); + //7 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_THREAD_RESOURCE_MGMT, 5); + R600_OUT_BATCH(evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT.u32All); + R600_OUT_BATCH(evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT_2.u32All); + R600_OUT_BATCH(evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_1.u32All); + R600_OUT_BATCH(evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_2.u32All); + R600_OUT_BATCH(evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_3.u32All); + + END_BATCH(); + + COMMIT_BATCH(); +} + +extern int evergreen_getTypeSize(GLenum type); +static void evergreenSetupVTXConstants(GLcontext * ctx, + void * pAos, + StreamDesc * pStreamDesc) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + struct radeon_aos * paos = (struct radeon_aos *)pAos; + unsigned int nVBsize; + BATCH_LOCALS(&context->radeon); + + unsigned int uSQ_VTX_CONSTANT_WORD0_0; + unsigned int uSQ_VTX_CONSTANT_WORD1_0; + unsigned int uSQ_VTX_CONSTANT_WORD2_0 = 0; + unsigned int uSQ_VTX_CONSTANT_WORD3_0 = 0; + unsigned int uSQ_VTX_CONSTANT_WORD7_0 = 0; + + if (!paos->bo) + return; + + r700SyncSurf(context, paos->bo, RADEON_GEM_DOMAIN_GTT, 0, VC_ACTION_ENA_bit); + + if(0 == pStreamDesc->stride) + { + nVBsize = paos->count * pStreamDesc->size * getTypeSize(pStreamDesc->type); + } + else + { + nVBsize = (paos->count - 1) * pStreamDesc->stride + + pStreamDesc->size * getTypeSize(pStreamDesc->type); + } + + //uSQ_VTX_CONSTANT_WORD0_0 + uSQ_VTX_CONSTANT_WORD0_0 = paos->offset; + + //uSQ_VTX_CONSTANT_WORD1_0 + uSQ_VTX_CONSTANT_WORD1_0 = nVBsize; + + //uSQ_VTX_CONSTANT_WORD2_0 + SETfield(uSQ_VTX_CONSTANT_WORD2_0, + pStreamDesc->stride, + SQ_VTX_CONSTANT_WORD2_0__STRIDE_shift, + SQ_VTX_CONSTANT_WORD2_0__STRIDE_mask); + SETfield(uSQ_VTX_CONSTANT_WORD2_0, GetSurfaceFormat(pStreamDesc->type, pStreamDesc->size, NULL), + SQ_VTX_CONSTANT_WORD2_0__DATA_FORMAT_shift, + SQ_VTX_CONSTANT_WORD2_0__DATA_FORMAT_mask); // TODO : trace back api for initial data type, not only GL_FLOAT + SETfield(uSQ_VTX_CONSTANT_WORD2_0, 0, BASE_ADDRESS_HI_shift, BASE_ADDRESS_HI_mask); // TODO + if(GL_TRUE == pStreamDesc->normalize) + { + SETfield(uSQ_VTX_CONSTANT_WORD2_0, SQ_NUM_FORMAT_NORM, + SQ_VTX_CONSTANT_WORD2_0__NUM_FORMAT_ALL_shift, SQ_VTX_CONSTANT_WORD2_0__NUM_FORMAT_ALL_mask); + } + else + { + SETfield(uSQ_VTX_CONSTANT_WORD2_0, SQ_NUM_FORMAT_SCALED, + SQ_VTX_CONSTANT_WORD2_0__NUM_FORMAT_ALL_shift, SQ_VTX_CONSTANT_WORD2_0__NUM_FORMAT_ALL_mask); + } + if(1 == pStreamDesc->_signed) + { + SETbit(uSQ_VTX_CONSTANT_WORD2_0, SQ_VTX_CONSTANT_WORD2_0__FORMAT_COMP_ALL_bit); + } + + //uSQ_VTX_CONSTANT_WORD3_0 + SETfield(uSQ_VTX_CONSTANT_WORD3_0, SQ_SEL_X, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_X_shift, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_X_mask); + SETfield(uSQ_VTX_CONSTANT_WORD3_0, SQ_SEL_Y, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_Y_shift, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_Y_mask); + SETfield(uSQ_VTX_CONSTANT_WORD3_0, SQ_SEL_Z, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_Z_shift, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_Z_mask); + SETfield(uSQ_VTX_CONSTANT_WORD3_0, SQ_SEL_W, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_W_shift, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_W_mask); + + //uSQ_VTX_CONSTANT_WORD7_0 + SETfield(uSQ_VTX_CONSTANT_WORD7_0, SQ_TEX_VTX_VALID_BUFFER, + SQ_TEX_RESOURCE_WORD6_0__TYPE_shift, SQ_TEX_RESOURCE_WORD6_0__TYPE_mask); + + BEGIN_BATCH_NO_AUTOSTATE(10 + 2); + + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_RESOURCE, 8)); + R600_OUT_BATCH((pStreamDesc->element + EG_SQ_FETCH_RESOURCE_VS_OFFSET) * EG_FETCH_RESOURCE_STRIDE); + R600_OUT_BATCH(uSQ_VTX_CONSTANT_WORD0_0); + R600_OUT_BATCH(uSQ_VTX_CONSTANT_WORD1_0); + R600_OUT_BATCH(uSQ_VTX_CONSTANT_WORD2_0); + R600_OUT_BATCH(uSQ_VTX_CONSTANT_WORD3_0); + R600_OUT_BATCH(0); + R600_OUT_BATCH(0); + R600_OUT_BATCH(0); + R600_OUT_BATCH(uSQ_VTX_CONSTANT_WORD7_0); + R600_OUT_BATCH_RELOC(uSQ_VTX_CONSTANT_WORD0_0, + paos->bo, + uSQ_VTX_CONSTANT_WORD0_0, + RADEON_GEM_DOMAIN_GTT, 0, 0); + END_BATCH(); + + COMMIT_BATCH(); +} + +static int check_evergreen_vtx(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + int count = context->radeon.tcl.aos_count * 12; + + if (count) + count += 6; + + radeon_print(RADEON_STATE, RADEON_TRACE, "%s %d\n", __func__, count); + return count; +} + +static void evergreenSendVTX(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + struct evergreen_vertex_program *vp = (struct evergreen_vertex_program *)(context->selected_vp); + unsigned int i, j = 0; + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + if (context->radeon.tcl.aos_count == 0) + return; + + BEGIN_BATCH_NO_AUTOSTATE(6); + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_CTL_CONST, 1)); + R600_OUT_BATCH(mmSQ_VTX_BASE_VTX_LOC - ASIC_CTL_CONST_BASE_INDEX); + R600_OUT_BATCH(0); + + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_CTL_CONST, 1)); + R600_OUT_BATCH(mmSQ_VTX_START_INST_LOC - ASIC_CTL_CONST_BASE_INDEX); + R600_OUT_BATCH(0); + END_BATCH(); + COMMIT_BATCH(); + + for(i=0; i<VERT_ATTRIB_MAX; i++) { + if(vp->mesa_program->Base.InputsRead & (1 << i)) + { + evergreenSetupVTXConstants(ctx, + (void*)(&context->radeon.tcl.aos[j]), + &(context->stream_desc[j])); + j++; + } + } +} +static void evergreenSendPA(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + int id = 0; + + BEGIN_BATCH_NO_AUTOSTATE(3); + EVERGREEN_OUT_BATCH_REGVAL(EG_PA_SU_HARDWARE_SCREEN_OFFSET, 0); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(22); + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_SC_SCREEN_SCISSOR_TL, 2); + R600_OUT_BATCH(evergreen->PA_SC_SCREEN_SCISSOR_TL.u32All); + R600_OUT_BATCH(evergreen->PA_SC_SCREEN_SCISSOR_BR.u32All); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_SC_WINDOW_OFFSET, 12); + R600_OUT_BATCH(evergreen->PA_SC_WINDOW_OFFSET.u32All); + R600_OUT_BATCH(evergreen->PA_SC_WINDOW_SCISSOR_TL.u32All); + R600_OUT_BATCH(evergreen->PA_SC_WINDOW_SCISSOR_BR.u32All); + R600_OUT_BATCH(evergreen->PA_SC_CLIPRECT_RULE.u32All); + R600_OUT_BATCH(evergreen->PA_SC_CLIPRECT_0_TL.u32All); + R600_OUT_BATCH(evergreen->PA_SC_CLIPRECT_0_BR.u32All); + R600_OUT_BATCH(evergreen->PA_SC_CLIPRECT_1_TL.u32All); + R600_OUT_BATCH(evergreen->PA_SC_CLIPRECT_1_BR.u32All); + R600_OUT_BATCH(evergreen->PA_SC_CLIPRECT_2_TL.u32All); + R600_OUT_BATCH(evergreen->PA_SC_CLIPRECT_2_BR.u32All); + R600_OUT_BATCH(evergreen->PA_SC_CLIPRECT_3_TL.u32All); + R600_OUT_BATCH(evergreen->PA_SC_CLIPRECT_3_BR.u32All); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_SC_GENERIC_SCISSOR_TL, 2); + R600_OUT_BATCH(evergreen->PA_SC_GENERIC_SCISSOR_TL.u32All); + R600_OUT_BATCH(evergreen->PA_SC_GENERIC_SCISSOR_BR.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3); + EVERGREEN_OUT_BATCH_REGVAL(EG_PA_SC_EDGERULE, evergreen->PA_SC_EDGERULE.u32All); + END_BATCH(); + + + BEGIN_BATCH_NO_AUTOSTATE(18); + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_SC_VPORT_SCISSOR_0_TL, 4); + R600_OUT_BATCH(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_TL.u32All); + R600_OUT_BATCH(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_BR.u32All); + R600_OUT_BATCH(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_TL.u32All); + R600_OUT_BATCH(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_BR.u32All); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_SC_VPORT_ZMIN_0, 2); + R600_OUT_BATCH(evergreen->viewport[id].PA_SC_VPORT_ZMIN_0.u32All); + R600_OUT_BATCH(evergreen->viewport[id].PA_SC_VPORT_ZMAX_0.u32All); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_CL_VPORT_XSCALE, 6); + R600_OUT_BATCH(evergreen->viewport[id].PA_CL_VPORT_XSCALE.u32All); + R600_OUT_BATCH(evergreen->viewport[id].PA_CL_VPORT_XOFFSET.u32All); + R600_OUT_BATCH(evergreen->viewport[id].PA_CL_VPORT_YSCALE.u32All); + R600_OUT_BATCH(evergreen->viewport[id].PA_CL_VPORT_YOFFSET.u32All); + R600_OUT_BATCH(evergreen->viewport[id].PA_CL_VPORT_ZSCALE.u32All); + R600_OUT_BATCH(evergreen->viewport[id].PA_CL_VPORT_ZOFFSET.u32All); + END_BATCH(); + + + for (id = 0; id < EVERGREEN_MAX_UCP; id++) { + if (evergreen->ucp[id].enabled) { + BEGIN_BATCH_NO_AUTOSTATE(6); + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_CL_UCP_0_X + (4 * id), 4); + R600_OUT_BATCH(evergreen->ucp[id].PA_CL_UCP_0_X.u32All); + R600_OUT_BATCH(evergreen->ucp[id].PA_CL_UCP_0_Y.u32All); + R600_OUT_BATCH(evergreen->ucp[id].PA_CL_UCP_0_Z.u32All); + R600_OUT_BATCH(evergreen->ucp[id].PA_CL_UCP_0_W.u32All); + END_BATCH(); + } + } + + BEGIN_BATCH_NO_AUTOSTATE(42); + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_CL_CLIP_CNTL, 5); + R600_OUT_BATCH(evergreen->PA_CL_CLIP_CNTL.u32All); + R600_OUT_BATCH(evergreen->PA_SU_SC_MODE_CNTL.u32All); + R600_OUT_BATCH(evergreen->PA_CL_VTE_CNTL.u32All); + R600_OUT_BATCH(evergreen->PA_CL_VS_OUT_CNTL.u32All); + R600_OUT_BATCH(evergreen->PA_CL_NANINF_CNTL.u32All); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_SU_POINT_SIZE, 3); + R600_OUT_BATCH(evergreen->PA_SU_POINT_SIZE.u32All); + R600_OUT_BATCH(evergreen->PA_SU_POINT_MINMAX.u32All); + R600_OUT_BATCH(evergreen->PA_SU_LINE_CNTL.u32All); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_SC_MODE_CNTL_0, 2); + R600_OUT_BATCH(evergreen->PA_SC_MODE_CNTL_0.u32All); + R600_OUT_BATCH(evergreen->PA_SC_MODE_CNTL_1.u32All); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_SU_POLY_OFFSET_DB_FMT_CNTL, 6); + R600_OUT_BATCH(evergreen->PA_SU_POLY_OFFSET_DB_FMT_CNTL.u32All); + R600_OUT_BATCH(evergreen->PA_SU_POLY_OFFSET_CLAMP.u32All); + R600_OUT_BATCH(evergreen->PA_SU_POLY_OFFSET_FRONT_SCALE.u32All); + R600_OUT_BATCH(evergreen->PA_SU_POLY_OFFSET_FRONT_OFFSET.u32All); + R600_OUT_BATCH(evergreen->PA_SU_POLY_OFFSET_BACK_SCALE.u32All); + R600_OUT_BATCH(evergreen->PA_SU_POLY_OFFSET_BACK_OFFSET.u32All); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_PA_SC_LINE_CNTL, 16); + R600_OUT_BATCH(evergreen->PA_SC_LINE_CNTL.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_CONFIG.u32All); + R600_OUT_BATCH(evergreen->PA_SU_VTX_CNTL.u32All); + R600_OUT_BATCH(evergreen->PA_CL_GB_VERT_CLIP_ADJ.u32All); + R600_OUT_BATCH(evergreen->PA_CL_GB_VERT_DISC_ADJ.u32All); + R600_OUT_BATCH(evergreen->PA_CL_GB_HORZ_CLIP_ADJ.u32All); + R600_OUT_BATCH(evergreen->PA_CL_GB_HORZ_DISC_ADJ.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_SAMPLE_LOCS_0.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_SAMPLE_LOCS_1.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_SAMPLE_LOCS_2.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_SAMPLE_LOCS_3.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_SAMPLE_LOCS_4.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_SAMPLE_LOCS_5.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_SAMPLE_LOCS_6.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_SAMPLE_LOCS_7.u32All); + R600_OUT_BATCH(evergreen->PA_SC_AA_MASK.u32All); + + END_BATCH(); + + COMMIT_BATCH(); +} +static void evergreenSendTP(GLcontext *ctx, struct radeon_state_atom *atom) +{ + /* + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + COMMIT_BATCH(); + */ +} + +static void evergreenSendPSresource(GLcontext *ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct radeon_bo * pbo; + + struct radeon_bo * pbo_const; + + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + pbo = (struct radeon_bo *)evergreenGetActiveFpShaderBo(GL_CONTEXT(context)); + + if (!pbo) + return; + + r700SyncSurf(context, pbo, RADEON_GEM_DOMAIN_GTT, 0, SH_ACTION_ENA_bit); + + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_PGM_START_PS, 1); + R600_OUT_BATCH(evergreen->ps.SQ_PGM_START_PS.u32All); + R600_OUT_BATCH_RELOC(evergreen->ps.SQ_PGM_START_PS.u32All, + pbo, + evergreen->ps.SQ_PGM_START_PS.u32All, + RADEON_GEM_DOMAIN_GTT, 0, 0); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3); + EVERGREEN_OUT_BATCH_REGVAL(EG_SQ_LOOP_CONST_0, 0x01000FFF); + END_BATCH(); + + pbo_const = (struct radeon_bo *)(context->fp_Constbo); + + if(NULL != pbo_const) + { + r700SyncSurf(context, pbo_const, RADEON_GEM_DOMAIN_GTT, 0, SH_ACTION_ENA_bit); + + BEGIN_BATCH_NO_AUTOSTATE(3); + + if(evergreen->ps.num_consts < 4) + { + EVERGREEN_OUT_BATCH_REGVAL(EG_SQ_ALU_CONST_BUFFER_SIZE_PS_0, 1); + } + else + { + EVERGREEN_OUT_BATCH_REGVAL(EG_SQ_ALU_CONST_BUFFER_SIZE_PS_0, (evergreen->ps.num_consts * 4)/16 ); + } + + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_ALU_CONST_CACHE_PS_0, 1); + R600_OUT_BATCH(context->fp_bo_offset >> 8); + R600_OUT_BATCH_RELOC(0, + pbo_const, + 0, + RADEON_GEM_DOMAIN_GTT, 0, 0); + END_BATCH(); + } + + COMMIT_BATCH(); +} + +static void evergreenSendVSresource(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct radeon_bo * pbo; + + struct radeon_bo * pbo_const; + + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + pbo = (struct radeon_bo *)evergreenGetActiveVpShaderBo(GL_CONTEXT(context)); + + if (!pbo) + return; + + r700SyncSurf(context, pbo, RADEON_GEM_DOMAIN_GTT, 0, SH_ACTION_ENA_bit); + + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_PGM_START_VS, 1); + R600_OUT_BATCH(evergreen->vs.SQ_PGM_START_VS.u32All); + R600_OUT_BATCH_RELOC(evergreen->vs.SQ_PGM_START_VS.u32All, + pbo, + evergreen->vs.SQ_PGM_START_VS.u32All, + RADEON_GEM_DOMAIN_GTT, 0, 0); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3); + EVERGREEN_OUT_BATCH_REGVAL((EG_SQ_LOOP_CONST_0 + 32*1), 0x0100000F); //consts == 1 + //EVERGREEN_OUT_BATCH_REGVAL((EG_SQ_LOOP_CONST_0 + (SQ_LOOP_CONST_vs<2)), 0x0100000F); + END_BATCH(); + + pbo_const = (struct radeon_bo *)(context->vp_Constbo); + + if(NULL != pbo_const) + { + r700SyncSurf(context, pbo_const, RADEON_GEM_DOMAIN_GTT, 0, SH_ACTION_ENA_bit); + + BEGIN_BATCH_NO_AUTOSTATE(3); + + if(evergreen->vs.num_consts < 4) + { + EVERGREEN_OUT_BATCH_REGVAL(EG_SQ_ALU_CONST_BUFFER_SIZE_VS_0, 1); + } + else + { + EVERGREEN_OUT_BATCH_REGVAL(EG_SQ_ALU_CONST_BUFFER_SIZE_VS_0, (evergreen->vs.num_consts * 4)/16 ); + } + + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_ALU_CONST_CACHE_VS_0, 1); + R600_OUT_BATCH(context->vp_bo_offset >> 8); + R600_OUT_BATCH_RELOC(0, + pbo_const, + 0, + RADEON_GEM_DOMAIN_GTT, 0, 0); + END_BATCH(); + } + + COMMIT_BATCH(); +} + +static void evergreenSendSQ(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + evergreenSendPSresource(ctx); //16 entries now + + BEGIN_BATCH_NO_AUTOSTATE(77); + + //34 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_VTX_SEMANTIC_0, 32); + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_0.u32All); //// // = 0x28380, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_1.u32All); //// // = 0x28384, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_2.u32All); //// // = 0x28388, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_3.u32All); //// // = 0x2838C, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_4.u32All); //// // = 0x28390, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_5.u32All); //// // = 0x28394, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_6.u32All); //// // = 0x28398, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_7.u32All); //// // = 0x2839C, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_8.u32All); //// // = 0x283A0, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_9.u32All); //// // = 0x283A4, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_10.u32All); //// // = 0x283A8, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_11.u32All); //// // = 0x283AC, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_12.u32All); //// // = 0x283B0, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_13.u32All); //// // = 0x283B4, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_14.u32All); //// // = 0x283B8, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_15.u32All); //// // = 0x283BC, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_16.u32All); //// // = 0x283C0, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_17.u32All); //// // = 0x283C4, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_18.u32All); //// // = 0x283C8, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_19.u32All); //// // = 0x283CC, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_20.u32All); //// // = 0x283D0, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_21.u32All); //// // = 0x283D4, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_22.u32All); //// // = 0x283D8, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_23.u32All); //// // = 0x283DC, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_24.u32All); //// // = 0x283E0, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_25.u32All); //// // = 0x283E4, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_26.u32All); //// // = 0x283E8, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_27.u32All); //// // = 0x283EC, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_28.u32All); //// // = 0x283F0, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_29.u32All); //// // = 0x283F4, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_30.u32All); //// // = 0x283F8, // SAME + R600_OUT_BATCH(evergreen->SQ_VTX_SEMANTIC_31.u32All); //// // = 0x283FC, // SAME + + + //3 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_DYN_GPR_RESOURCE_LIMIT_1, 1); + R600_OUT_BATCH(evergreen->SQ_DYN_GPR_RESOURCE_LIMIT_1.u32All);//// // = 0x28838, // + + //5 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_PGM_RESOURCES_PS, 3); + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_PS.u32All); //// // = 0x28844, // DIFF 0x28850 + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_2_PS.u32All); //// // = 0x28848, // + R600_OUT_BATCH(evergreen->SQ_PGM_EXPORTS_PS.u32All); //// // = 0x2884C, // SAME 0x28854 + + //4 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_PGM_RESOURCES_VS, 2); + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_VS.u32All);//// // = 0x28860, // DIFF 0x28868 + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_2_VS.u32All); //// // = 0x28864, // + + //5 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_PGM_RESOURCES_GS, 2); + /* + R600_OUT_BATCH(evergreen->SQ_PGM_START_GS.u32All); //// // = 0x28874, // SAME 0x2886C + */ + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_GS.u32All); //// // = 0x28878, // DIFF 0x2887C + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_2_GS.u32All); //// // = 0x2887C, // + + //5 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_PGM_RESOURCES_ES, 2); + /* + R600_OUT_BATCH(evergreen->SQ_PGM_START_ES.u32All); //// // = 0x2888C, // SAME 0x28880 + */ + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_ES.u32All); //// // = 0x28890, // DIFF + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_2_ES.u32All); //// // = 0x28894, // + + //4 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_PGM_RESOURCES_FS, 1); + /* + R600_OUT_BATCH(evergreen->SQ_PGM_START_FS.u32All); //// // = 0x288A4, // SAME 0x28894 + */ + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_FS.u32All); //// // = 0x288A8, // DIFF 0x288A4 + + //3 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_PGM_RESOURCES_2_HS, 1); + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_2_HS.u32All);//// // = 0x288C0, // + + //3 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_PGM_RESOURCES_2_LS, 1); + R600_OUT_BATCH(evergreen->SQ_PGM_RESOURCES_2_LS.u32All); //// // = 0x288D8, // + + //3 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_LDS_ALLOC_PS, 1); + R600_OUT_BATCH(evergreen->SQ_LDS_ALLOC_PS.u32All); //// // = 0x288EC, // + + //8 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_ESGS_RING_ITEMSIZE, 6); + R600_OUT_BATCH(evergreen->SQ_ESGS_RING_ITEMSIZE.u32All); //// // = 0x28900, // SAME 0x288A8 + R600_OUT_BATCH(evergreen->SQ_GSVS_RING_ITEMSIZE.u32All); //// // = 0x28904, // SAME 0x288AC + R600_OUT_BATCH(evergreen->SQ_ESTMP_RING_ITEMSIZE.u32All); //// // = 0x28908, // SAME 0x288B0 + R600_OUT_BATCH(evergreen->SQ_GSTMP_RING_ITEMSIZE.u32All); //// // = 0x2890C, // SAME 0x288B4 + R600_OUT_BATCH(evergreen->SQ_VSTMP_RING_ITEMSIZE.u32All); //// // = 0x28910, // SAME 0x288B8 + R600_OUT_BATCH(evergreen->SQ_PSTMP_RING_ITEMSIZE.u32All); //// // = 0x28914, // SAME 0x288BC + + //3 + EVERGREEN_OUT_BATCH_REGSEQ(EG_SQ_GS_VERT_ITEMSIZE, 1); + R600_OUT_BATCH(evergreen->SQ_GS_VERT_ITEMSIZE.u32All); //// // = 0x2891C, // SAME 0x288C8 + + END_BATCH(); + + COMMIT_BATCH(); + +} +static void evergreenSendSPI(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + BEGIN_BATCH_NO_AUTOSTATE(59); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_SPI_VS_OUT_ID_0, 10); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_0.u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_1.u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_2.u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_3.u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_4.u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_5.u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_6.u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_7.u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_8.u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_ID_9.u32All); + + EVERGREEN_OUT_BATCH_REGSEQ(EG_SPI_PS_INPUT_CNTL_0, 45); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[0].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[1].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[2].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[3].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[4].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[5].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[6].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[7].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[8].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[9].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[10].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[11].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[12].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[13].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[14].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[15].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[16].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[17].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[18].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[19].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[20].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[21].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[22].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[23].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[24].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[25].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[26].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[27].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[28].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[29].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[30].u32All); + R600_OUT_BATCH(evergreen->SPI_PS_INPUT_CNTL[31].u32All); + R600_OUT_BATCH(evergreen->SPI_VS_OUT_CONFIG.u32All); + R600_OUT_BATCH(evergreen->SPI_THREAD_GROUPING.u32All); + R600_OUT_BATCH(evergreen->SPI_PS_IN_CONTROL_0.u32All); + R600_OUT_BATCH(evergreen->SPI_PS_IN_CONTROL_1.u32All); + R600_OUT_BATCH(evergreen->SPI_INTERP_CONTROL_0.u32All); + R600_OUT_BATCH(evergreen->SPI_INPUT_Z.u32All); + R600_OUT_BATCH(evergreen->SPI_FOG_CNTL.u32All); + R600_OUT_BATCH(evergreen->SPI_BARYC_CNTL.u32All); + R600_OUT_BATCH(evergreen->SPI_PS_IN_CONTROL_2.u32All); + R600_OUT_BATCH(evergreen->SPI_COMPUTE_INPUT_CNTL.u32All); + R600_OUT_BATCH(evergreen->SPI_COMPUTE_NUM_THREAD_X.u32All); + R600_OUT_BATCH(evergreen->SPI_COMPUTE_NUM_THREAD_Y.u32All); + R600_OUT_BATCH(evergreen->SPI_COMPUTE_NUM_THREAD_Z.u32All); + + END_BATCH(); + + COMMIT_BATCH(); +} +static void evergreenSendSX(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + BEGIN_BATCH_NO_AUTOSTATE(9); + + EVERGREEN_OUT_BATCH_REGVAL(EG_SX_MISC, evergreen->SX_MISC.u32All); + EVERGREEN_OUT_BATCH_REGVAL(EG_SX_ALPHA_TEST_CONTROL, evergreen->SX_ALPHA_TEST_CONTROL.u32All); + EVERGREEN_OUT_BATCH_REGVAL(EG_SX_ALPHA_REF, evergreen->SX_ALPHA_REF.u32All); + + END_BATCH(); + + COMMIT_BATCH(); +} + +static void evergreenSetDepthTarget(context_t *context) +{ + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct radeon_renderbuffer *rrb; + unsigned int nPitchInPixel; + + rrb = radeon_get_depthbuffer(&context->radeon); + if (!rrb) + { + return; + } + + EVERGREEN_STATECHANGE(context, db); + + evergreen->DB_DEPTH_SIZE.u32All = 0; + + SETfield(evergreen->DB_DEPTH_SIZE.u32All, (nPitchInPixel/8)-1, + EG_DB_DEPTH_SIZE__PITCH_TILE_MAX_shift, + EG_DB_DEPTH_SIZE__PITCH_TILE_MAX_mask); + SETfield(evergreen->DB_DEPTH_SIZE.u32All, (context->radeon.radeonScreen->driScreen->fbHeight/8)-1, + EG_DB_DEPTH_SIZE__HEIGHT_TILE_MAX_shift, + EG_DB_DEPTH_SIZE__HEIGHT_TILE_MAX_mask); + evergreen->DB_DEPTH_SLICE.u32All = ( (nPitchInPixel * context->radeon.radeonScreen->driScreen->fbHeight)/64 )-1; + + if(4 == rrb->cpp) + { + SETfield(evergreen->DB_Z_INFO.u32All, DEPTH_8_24, + EG_DB_Z_INFO__FORMAT_shift, + EG_DB_Z_INFO__FORMAT_mask); + } + else + { + SETfield(evergreen->DB_Z_INFO.u32All, DEPTH_16, + EG_DB_Z_INFO__FORMAT_shift, + EG_DB_Z_INFO__FORMAT_mask); + } + SETfield(evergreen->DB_Z_INFO.u32All, ARRAY_1D_TILED_THIN1, + EG_DB_Z_INFO__ARRAY_MODE_shift, + EG_DB_Z_INFO__ARRAY_MODE_mask); +} + +static void evergreenSendDB(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct radeon_renderbuffer *rrb; + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + evergreenSetDepthTarget(context); + + //8 + BEGIN_BATCH_NO_AUTOSTATE(7); + EVERGREEN_OUT_BATCH_REGSEQ(EG_DB_RENDER_CONTROL, 5); + R600_OUT_BATCH(evergreen->DB_RENDER_CONTROL.u32All); + R600_OUT_BATCH(evergreen->DB_COUNT_CONTROL.u32All); + R600_OUT_BATCH(evergreen->DB_DEPTH_VIEW.u32All); + R600_OUT_BATCH(evergreen->DB_RENDER_OVERRIDE.u32All); + R600_OUT_BATCH(evergreen->DB_RENDER_OVERRIDE2.u32All); + /* + R600_OUT_BATCH(evergreen->DB_HTILE_DATA_BASE.u32All); + */ + END_BATCH(); + + //4 + BEGIN_BATCH_NO_AUTOSTATE(4); + EVERGREEN_OUT_BATCH_REGSEQ(EG_DB_STENCIL_CLEAR, 2); + R600_OUT_BATCH(evergreen->DB_STENCIL_CLEAR.u32All); + R600_OUT_BATCH(evergreen->DB_DEPTH_CLEAR.u32All); + END_BATCH(); + + //4 + BEGIN_BATCH_NO_AUTOSTATE(4); + EVERGREEN_OUT_BATCH_REGSEQ(EG_DB_DEPTH_SIZE, 2); + R600_OUT_BATCH(evergreen->DB_DEPTH_SIZE.u32All); + R600_OUT_BATCH(evergreen->DB_DEPTH_SLICE.u32All); + END_BATCH(); + + //3 + BEGIN_BATCH_NO_AUTOSTATE(3); + EVERGREEN_OUT_BATCH_REGVAL(EG_DB_DEPTH_CONTROL, evergreen->DB_DEPTH_CONTROL.u32All); + END_BATCH(); + + //3 + BEGIN_BATCH_NO_AUTOSTATE(3); + EVERGREEN_OUT_BATCH_REGVAL(EG_DB_SHADER_CONTROL, evergreen->DB_SHADER_CONTROL.u32All); + END_BATCH(); + + //5 + BEGIN_BATCH_NO_AUTOSTATE(5); + EVERGREEN_OUT_BATCH_REGSEQ(EG_DB_SRESULTS_COMPARE_STATE0, 3); + R600_OUT_BATCH(evergreen->DB_SRESULTS_COMPARE_STATE0.u32All); + R600_OUT_BATCH(evergreen->DB_SRESULTS_COMPARE_STATE1.u32All); + R600_OUT_BATCH(evergreen->DB_PRELOAD_CONTROL.u32All); + END_BATCH(); + + //3 + BEGIN_BATCH_NO_AUTOSTATE(3); + EVERGREEN_OUT_BATCH_REGVAL(EG_DB_ALPHA_TO_MASK, evergreen->DB_ALPHA_TO_MASK.u32All); + END_BATCH(); + + rrb = radeon_get_depthbuffer(&context->radeon); + if( (rrb != NULL) && (rrb->bo != NULL) ) + { + //5 + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGVAL(EG_DB_Z_INFO, evergreen->DB_Z_INFO.u32All); + R600_OUT_BATCH_RELOC(evergreen->DB_Z_INFO.u32All, + rrb->bo, + evergreen->DB_Z_INFO.u32All, + 0, RADEON_GEM_DOMAIN_VRAM, 0); + END_BATCH(); + + //5 + if((evergreen->DB_DEPTH_CONTROL.u32All & Z_ENABLE_bit) > 0) + { + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGVAL(EG_DB_Z_READ_BASE, evergreen->DB_Z_READ_BASE.u32All); + R600_OUT_BATCH_RELOC(evergreen->DB_Z_READ_BASE.u32All, + rrb->bo, + evergreen->DB_Z_READ_BASE.u32All, + 0, RADEON_GEM_DOMAIN_VRAM, 0); + END_BATCH(); + } + //5 + if((evergreen->DB_DEPTH_CONTROL.u32All & Z_WRITE_ENABLE_bit) > 0) + { + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGVAL(EG_DB_Z_WRITE_BASE, evergreen->DB_Z_READ_BASE.u32All); + R600_OUT_BATCH_RELOC(evergreen->DB_Z_WRITE_BASE.u32All, + rrb->bo, + evergreen->DB_Z_WRITE_BASE.u32All, + 0, RADEON_GEM_DOMAIN_VRAM, 0); + END_BATCH(); + } + } +/* + if (ctx->DrawBuffer) + { + rrb = radeon_get_renderbuffer(ctx->DrawBuffer, BUFFER_STENCIL); + + if((rrb != NULL) && (rrb->bo != NULL)) + { + //5 + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGVAL(EG_DB_STENCIL_INFO, evergreen->DB_Z_INFO.u32All); + R600_OUT_BATCH_RELOC(evergreen->DB_STENCIL_INFO.u32All, + rrb->bo, + evergreen->DB_STENCIL_INFO.u32All, + 0, RADEON_GEM_DOMAIN_VRAM, 0); + END_BATCH(); + + //10 + if((evergreen->DB_DEPTH_CONTROL.u32All & STENCIL_ENABLE_bit) > 0) + { + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGVAL(EG_DB_STENCIL_READ_BASE, evergreen->DB_STENCIL_READ_BASE.u32All); + R600_OUT_BATCH_RELOC(evergreen->DB_STENCIL_READ_BASE.u32All, + rrb->bo, + evergreen->DB_STENCIL_READ_BASE.u32All, + 0, RADEON_GEM_DOMAIN_VRAM, 0); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGVAL(EG_DB_STENCIL_WRITE_BASE, evergreen->DB_STENCIL_WRITE_BASE.u32All); + R600_OUT_BATCH_RELOC(evergreen->DB_STENCIL_WRITE_BASE.u32All, + rrb->bo, + evergreen->DB_STENCIL_WRITE_BASE.u32All, + 0, RADEON_GEM_DOMAIN_VRAM, 0); + END_BATCH(); + } + } + } +*/ + COMMIT_BATCH(); +} + +static void evergreenSetRenderTarget(context_t *context, int id) +{ + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + struct radeon_renderbuffer *rrb; + unsigned int nPitchInPixel; + + rrb = radeon_get_colorbuffer(&context->radeon); + if (!rrb || !rrb->bo) { + return; + } + + EVERGREEN_STATECHANGE(context, cb); + + /* addr */ + evergreen->render_target[id].CB_COLOR0_BASE.u32All = context->radeon.state.color.draw_offset / 256; + + /* pitch */ + nPitchInPixel = rrb->pitch/rrb->cpp; + + SETfield(evergreen->render_target[id].CB_COLOR0_PITCH.u32All, (nPitchInPixel/8)-1, + EG_CB_COLOR0_PITCH__TILE_MAX_shift, + EG_CB_COLOR0_PITCH__TILE_MAX_mask); + + /* skice */ + SETfield(evergreen->render_target[id].CB_COLOR0_SLICE.u32All, + //( (nPitchInPixel * context->radeon.radeonScreen->driScreen->fbHeight)/64 )-1, + ( (nPitchInPixel * 240)/64 )-1, + EG_CB_COLOR0_SLICE__TILE_MAX_shift, + EG_CB_COLOR0_SLICE__TILE_MAX_mask); + + /* CB_COLOR0_ATTRIB */ /* TODO : for z clear, this should be set to 0 */ + SETbit(evergreen->render_target[id].CB_COLOR0_ATTRIB.u32All, + EG_CB_COLOR0_ATTRIB__NON_DISP_TILING_ORDER_bit); + + /* CB_COLOR0_INFO */ + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + ENDIAN_NONE, + EG_CB_COLOR0_INFO__ENDIAN_shift, + EG_CB_COLOR0_INFO__ENDIAN_mask); + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + ARRAY_LINEAR_GENERAL, + EG_CB_COLOR0_INFO__ARRAY_MODE_shift, + EG_CB_COLOR0_INFO__ARRAY_MODE_mask); + if(4 == rrb->cpp) + { + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + COLOR_8_8_8_8, + EG_CB_COLOR0_INFO__FORMAT_shift, + EG_CB_COLOR0_INFO__FORMAT_mask); + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + SWAP_ALT, //SWAP_STD + EG_CB_COLOR0_INFO__COMP_SWAP_shift, + EG_CB_COLOR0_INFO__COMP_SWAP_mask); + } + else + { + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + COLOR_5_6_5, + EG_CB_COLOR0_INFO__FORMAT_shift, + EG_CB_COLOR0_INFO__FORMAT_mask); + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + SWAP_ALT_REV, + EG_CB_COLOR0_INFO__COMP_SWAP_shift, + EG_CB_COLOR0_INFO__COMP_SWAP_mask); + } + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + 1, + EG_CB_COLOR0_INFO__SOURCE_FORMAT_shift, + EG_CB_COLOR0_INFO__SOURCE_FORMAT_mask); + SETbit(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + EG_CB_COLOR0_INFO__BLEND_CLAMP_bit); + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + NUMBER_UNORM, + EG_CB_COLOR0_INFO__NUMBER_TYPE_shift, + EG_CB_COLOR0_INFO__NUMBER_TYPE_mask); + + evergreen->render_target[id].CB_COLOR0_VIEW.u32All = 0; + evergreen->render_target[id].CB_COLOR0_CMASK.u32All = 0; + evergreen->render_target[id].CB_COLOR0_FMASK.u32All = 0; + evergreen->render_target[id].CB_COLOR0_FMASK_SLICE.u32All = 0; + + evergreen->render_target[id].enabled = GL_TRUE; +} + +static void evergreenSendCB(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct radeon_renderbuffer *rrb; + BATCH_LOCALS(&context->radeon); + int id = 0; + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + rrb = radeon_get_colorbuffer(&context->radeon); + if (!rrb || !rrb->bo) { + return; + } + + evergreenSetRenderTarget(context, 0); + + if (!evergreen->render_target[id].enabled) + return; + + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGSEQ(EG_CB_COLOR0_BASE + (4 * id), 1); + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_BASE.u32All); + R600_OUT_BATCH_RELOC(evergreen->render_target[id].CB_COLOR0_BASE.u32All, + rrb->bo, + evergreen->render_target[id].CB_COLOR0_BASE.u32All, + 0, RADEON_GEM_DOMAIN_VRAM, 0); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + EVERGREEN_OUT_BATCH_REGVAL(EG_CB_COLOR0_INFO, evergreen->render_target[id].CB_COLOR0_INFO.u32All); + R600_OUT_BATCH_RELOC(evergreen->render_target[id].CB_COLOR0_INFO.u32All, + rrb->bo, + evergreen->render_target[id].CB_COLOR0_INFO.u32All, + 0, RADEON_GEM_DOMAIN_VRAM, 0); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(5); + EVERGREEN_OUT_BATCH_REGSEQ(EG_CB_COLOR0_PITCH, 3); + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_PITCH.u32All); + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_SLICE.u32All); + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_VIEW.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(4); + EVERGREEN_OUT_BATCH_REGSEQ(EG_CB_COLOR0_ATTRIB, 2); + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_ATTRIB.u32All); + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_DIM.u32All); + /* + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_CMASK.u32All); + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_CMASK_SLICE.u32All); + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_FMASK.u32All); + R600_OUT_BATCH(evergreen->render_target[id].CB_COLOR0_FMASK_SLICE.u32All); + */ + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(4); + EVERGREEN_OUT_BATCH_REGSEQ(EG_CB_TARGET_MASK, 2); + R600_OUT_BATCH(evergreen->CB_TARGET_MASK.u32All); + R600_OUT_BATCH(evergreen->CB_SHADER_MASK.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(5); + EVERGREEN_OUT_BATCH_REGSEQ(EG_CB_BLEND_RED, 3); + R600_OUT_BATCH(evergreen->CB_BLEND_RED.u32All); + R600_OUT_BATCH(evergreen->CB_BLEND_GREEN.u32All); + R600_OUT_BATCH(evergreen->CB_BLEND_BLUE.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(9); + EVERGREEN_OUT_BATCH_REGVAL(EG_CB_BLEND_ALPHA, evergreen->CB_BLEND_ALPHA.u32All); + EVERGREEN_OUT_BATCH_REGVAL(EG_CB_BLEND0_CONTROL, evergreen->CB_BLEND0_CONTROL.u32All); + EVERGREEN_OUT_BATCH_REGVAL(EG_CB_COLOR_CONTROL, evergreen->CB_COLOR_CONTROL.u32All); + END_BATCH(); + + COMMIT_BATCH(); +} +static void evergreenSendCP(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + + //first to send + //r700Start3D + BEGIN_BATCH_NO_AUTOSTATE(3); + R600_OUT_BATCH(CP_PACKET3(R600_IT_CONTEXT_CONTROL, 1)); //IT_CONTEXT_CONTROL 0x28 + R600_OUT_BATCH(0x80000000); + R600_OUT_BATCH(0x80000000); + END_BATCH(); + + COMMIT_BATCH(); +} +static void evergreenSendVGT(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); + +/* moved to draw: + VGT_DRAW_INITIATOR + VGT_INDEX_TYPE + VGT_PRIMITIVE_TYPE +*/ + BEGIN_BATCH_NO_AUTOSTATE(5); + EVERGREEN_OUT_BATCH_REGSEQ(EG_VGT_MAX_VTX_INDX, 3); + R600_OUT_BATCH(evergreen->VGT_MAX_VTX_INDX.u32All); + R600_OUT_BATCH(evergreen->VGT_MIN_VTX_INDX.u32All); + R600_OUT_BATCH(evergreen->VGT_INDX_OFFSET.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(6); + EVERGREEN_OUT_BATCH_REGVAL(EG_VGT_OUTPUT_PATH_CNTL, evergreen->VGT_OUTPUT_PATH_CNTL.u32All); + + EVERGREEN_OUT_BATCH_REGVAL(EG_VGT_GS_MODE, evergreen->VGT_GS_MODE.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3); + EVERGREEN_OUT_BATCH_REGSEQ(EG_VGT_PRIMITIVEID_EN, 1); + R600_OUT_BATCH(evergreen->VGT_PRIMITIVEID_EN.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(4); + EVERGREEN_OUT_BATCH_REGSEQ(EG_VGT_INSTANCE_STEP_RATE_0, 2); + R600_OUT_BATCH(evergreen->VGT_INSTANCE_STEP_RATE_0.u32All); + R600_OUT_BATCH(evergreen->VGT_INSTANCE_STEP_RATE_1.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(4); + EVERGREEN_OUT_BATCH_REGSEQ(EG_VGT_REUSE_OFF, 2); + R600_OUT_BATCH(evergreen->VGT_REUSE_OFF.u32All); + R600_OUT_BATCH(evergreen->VGT_VTX_CNT_EN.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3); + EVERGREEN_OUT_BATCH_REGVAL(EG_VGT_SHADER_STAGES_EN, evergreen->VGT_SHADER_STAGES_EN.u32All); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(4); + EVERGREEN_OUT_BATCH_REGSEQ(EG_VGT_STRMOUT_CONFIG, 2); + R600_OUT_BATCH(evergreen->VGT_STRMOUT_CONFIG.u32All); + R600_OUT_BATCH(evergreen->VGT_STRMOUT_BUFFER_CONFIG.u32All); + END_BATCH(); + + COMMIT_BATCH(); +} + +static void evergreenSendTIMESTAMP(GLcontext *ctx, struct radeon_state_atom *atom) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + BATCH_LOCALS(&context->radeon); + radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); +} + +void evergreenInitAtoms(context_t *context) +{ + radeon_print(RADEON_STATE, RADEON_NORMAL, "%s %p\n", __func__, context); + context->radeon.hw.max_state_size = 10 + 5 + 14 + 3; /* start 3d, idle, cb/db flush, 3 for time stamp */ + + /* Setup the atom linked list */ + make_empty_list(&context->radeon.hw.atomlist); + context->radeon.hw.atomlist.name = "atom-list"; + + EVERGREEN_ALLOC_STATE(init, always, 19, evergreenSendSQConfig); + + //make sure send first + EVERGREEN_ALLOC_STATE(cp, always, 3, evergreenSendCP); + + EVERGREEN_ALLOC_STATE(vtx, evergreen_vtx, (6 + (VERT_ATTRIB_MAX * 12)), evergreenSendVTX); + EVERGREEN_ALLOC_STATE(pa, always, 124, evergreenSendPA); + EVERGREEN_ALLOC_STATE(tp, always, 0, evergreenSendTP); + EVERGREEN_ALLOC_STATE(sq, always, 86, evergreenSendSQ); /* 85 */ + EVERGREEN_ALLOC_STATE(vs, always, 16, evergreenSendVSresource); + EVERGREEN_ALLOC_STATE(spi, always, 59, evergreenSendSPI); + EVERGREEN_ALLOC_STATE(sx, always, 9, evergreenSendSX); + EVERGREEN_ALLOC_STATE(tx, evergreen_tx, (R700_TEXTURE_NUMBERUNITS * (21+5) + 6), evergreenSendTexState); /* 21 for resource, 5 for sampler */ + EVERGREEN_ALLOC_STATE(db, always, 60, evergreenSendDB); + EVERGREEN_ALLOC_STATE(cb, always, 35, evergreenSendCB); + EVERGREEN_ALLOC_STATE(vgt, always, 29, evergreenSendVGT); + EVERGREEN_ALLOC_STATE(timestamp, always, 3, evergreenSendTIMESTAMP); + + //evergreen_init_query_stateobj(&context->radeon, 6 * 2); + + context->radeon.hw.is_dirty = GL_TRUE; + context->radeon.hw.all_dirty = GL_TRUE; +} diff --git a/src/mesa/drivers/dri/r600/evergreen_chip.h b/src/mesa/drivers/dri/r600/evergreen_chip.h new file mode 100644 index 0000000000..2ea5cd213c --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_chip.h @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#ifndef _EVERGREEN_CHIP_H_ +#define _EVERGREEN_CHIP_H_ + +#include "r700_chip.h" + +#define EVERGREEN_MAX_DX9_CONSTS 256 +#define EVERGREEN_MAX_SHADER_EXPORTS 32 +#define EVERGREEN_MAX_VIEWPORTS 16 + +typedef struct _EVERGREEN_VIEWPORT_STATE +{ + union UINT_FLOAT PA_SC_VPORT_SCISSOR_0_TL; ////0,1 // = 0x28250, // DIFF + union UINT_FLOAT PA_SC_VPORT_SCISSOR_0_BR; ////0,1 // = 0x28254, // DIFF + union UINT_FLOAT PA_SC_VPORT_ZMIN_0; ////0 // = 0x282D0, // SAME + union UINT_FLOAT PA_SC_VPORT_ZMAX_0; ////0 // = 0x282D4, // SAME + union UINT_FLOAT PA_CL_VPORT_XSCALE; //// // = 0x2843C, // SAME + union UINT_FLOAT PA_CL_VPORT_XOFFSET; //// // = 0x28440, // SAME + union UINT_FLOAT PA_CL_VPORT_YSCALE; //// // = 0x28444, // SAME + union UINT_FLOAT PA_CL_VPORT_YOFFSET; //// // = 0x28448, // SAME + union UINT_FLOAT PA_CL_VPORT_ZSCALE; //// // = 0x2844C, // SAME + union UINT_FLOAT PA_CL_VPORT_ZOFFSET; //// // = 0x28450, // SAME + GLboolean enabled; + GLboolean dirty; +} EVERGREEN_VIEWPORT_STATE; + +#define EVERGREEN_MAX_UCP 6 + +typedef struct _EVERGREEN_UCP_STATE +{ + union UINT_FLOAT PA_CL_UCP_0_X; // = 0x285BC, // SAME 0x28E20 + union UINT_FLOAT PA_CL_UCP_0_Y; // = 0x285C0, // SAME 0x28E24 + union UINT_FLOAT PA_CL_UCP_0_Z; // = 0x285C4, // SAME 0x28E28 + union UINT_FLOAT PA_CL_UCP_0_W; // = 0x285C8, // SAME 0x28E2C + GLboolean enabled; + GLboolean dirty; +} EVERGREEN_UCP_STATE; + +#define EVERGREEN_MAX_RENDER_TARGETS 12 + +typedef struct _EVERGREEN_RENDER_TARGET_STATE +{ + union UINT_FLOAT CB_COLOR0_BASE; ////0 // = 0x28C60, // SAME 0x28040 + union UINT_FLOAT CB_COLOR0_PITCH; ////0 // = 0x28C64, // + union UINT_FLOAT CB_COLOR0_SLICE; ////0 // = 0x28C68, // + union UINT_FLOAT CB_COLOR0_VIEW; ////0 // = 0x28C6C, // SAME 0x28080 + union UINT_FLOAT CB_COLOR0_INFO; ////0,1,2,3,4,5,6,78,9,10,11 // = 0x28C70, // DIFF 0x280A0 + union UINT_FLOAT CB_COLOR0_ATTRIB; ////0 // = 0x28C74, // + union UINT_FLOAT CB_COLOR0_DIM; // = 0x28C78, // + union UINT_FLOAT CB_COLOR0_CMASK; ////0 // = 0x28C7C, // + union UINT_FLOAT CB_COLOR0_CMASK_SLICE; ////0 // = 0x28C80, // + union UINT_FLOAT CB_COLOR0_FMASK; ////0 // = 0x28C84, // + union UINT_FLOAT CB_COLOR0_FMASK_SLICE; ////0 // = 0x28C88, // + union UINT_FLOAT CB_COLOR0_CLEAR_WORD0; // = 0x28C8C, // + union UINT_FLOAT CB_COLOR0_CLEAR_WORD1; // = 0x28C90, // + union UINT_FLOAT CB_COLOR0_CLEAR_WORD2; // = 0x28C94, // + union UINT_FLOAT CB_COLOR0_CLEAR_WORD3; // = 0x28C98, // + GLboolean enabled; + GLboolean dirty; +} EVERGREEN_RENDER_TARGET_STATE; + +typedef struct _EVERGREEN_CONFIG +{ + union UINT_FLOAT SPI_CONFIG_CNTL; // = 0x9100, // DIFF + union UINT_FLOAT SPI_CONFIG_CNTL_1; // = 0x913C, // DIFF + union UINT_FLOAT CP_PERFMON_CNTL; // = 0x87FC, // SAME + union UINT_FLOAT SQ_MS_FIFO_SIZES; // = 0x8CF0, // SAME + + union UINT_FLOAT SQ_CONFIG; // = 0x8C00, // DIFF + union UINT_FLOAT SQ_GPR_RESOURCE_MGMT_1; // = 0x8C04, // SAME + union UINT_FLOAT SQ_GPR_RESOURCE_MGMT_2; // = 0x8C08, // SAME + union UINT_FLOAT SQ_GPR_RESOURCE_MGMT_3; // = 0x8C0C, // + + union UINT_FLOAT SQ_THREAD_RESOURCE_MGMT; // = 0x8C18, // SAME 0x8C0C + union UINT_FLOAT SQ_THREAD_RESOURCE_MGMT_2; // = 0x8C1C, // + union UINT_FLOAT SQ_STACK_RESOURCE_MGMT_1; // = 0x8C20, // SAME 0x8C10 + union UINT_FLOAT SQ_STACK_RESOURCE_MGMT_2; // = 0x8C24, // SAME 0x8C14 + union UINT_FLOAT SQ_STACK_RESOURCE_MGMT_3; // = 0x8C28, // + + union UINT_FLOAT SQ_DYN_GPR_CNTL_PS_FLUSH_REQ; // = 0x8D8C, // DIFF + union UINT_FLOAT SQ_LDS_RESOURCE_MGMT; // = 0x8E2C, // + union UINT_FLOAT VGT_CACHE_INVALIDATION; // = 0x88C4, // DIFF + union UINT_FLOAT VGT_GS_VERTEX_REUSE; // = 0x88D4, // SAME + union UINT_FLOAT PA_SC_FORCE_EOV_MAX_CNTS; // = 0x8B24, // SAME + union UINT_FLOAT PA_SC_LINE_STIPPLE_STATE; // = 0x8B10, // SAME + union UINT_FLOAT PA_CL_ENHANCE; // = 0x8A14, // SAME +} EVERGREEN_CONFIG; + +typedef struct _EVERGREEN_PS_RES +{ + union UINT_FLOAT SQ_PGM_START_PS; //// // = 0x28840, // SAME + GLboolean dirty; + + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_0; // = 0x28940, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_1; // = 0x28944, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_2; // = 0x28948, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_3; // = 0x2894C, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_4; // = 0x28950, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_5; // = 0x28954, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_6; // = 0x28958, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_7; // = 0x2895C, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_8; // = 0x28960, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_9; // = 0x28964, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_10; // = 0x28968, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_11; // = 0x2896C, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_12; // = 0x28970, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_13; // = 0x28974, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_14; // = 0x28978, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_PS_15; // = 0x2897C, // SAME + + int num_consts; + union UINT_FLOAT consts[EVERGREEN_MAX_DX9_CONSTS][4]; +} EVERGREEN_PS_RES; + +typedef struct _EVERGREEN_VS_RES +{ + union UINT_FLOAT SQ_PGM_START_VS; //// // = 0x2885C, // SAME 0x28858 + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_VS_0; //// // = 0x28180, //? + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_0; //// // = 0x28980, // SAME + + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_1; // = 0x28984, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_2; // = 0x28988, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_3; // = 0x2898C, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_4; // = 0x28990, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_5; // = 0x28994, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_6; // = 0x28998, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_7; // = 0x2899C, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_8; // = 0x289A0, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_9; // = 0x289A4, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_10; // = 0x289A8, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_11; // = 0x289AC, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_12; // = 0x289B0, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_13; // = 0x289B4, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_14; // = 0x289B8, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_15; // = 0x289BC, // SAME + + GLboolean dirty; + int num_consts; + union UINT_FLOAT consts[EVERGREEN_MAX_DX9_CONSTS][4]; +} EVERGREEN_VS_RES; + +typedef struct _EVERGREEN_CHIP_CONTEXT +{ +/* Registers from PA block: */ + union UINT_FLOAT PA_SC_SCREEN_SCISSOR_TL; //// // = 0x28030, // DIFF + union UINT_FLOAT PA_SC_SCREEN_SCISSOR_BR; //// // = 0x28034, // DIFF + union UINT_FLOAT PA_SC_WINDOW_OFFSET; //// // = 0x28200, // DIFF + union UINT_FLOAT PA_SC_WINDOW_SCISSOR_TL; //// // = 0x28204, // DIFF + union UINT_FLOAT PA_SC_WINDOW_SCISSOR_BR; //// // = 0x28208, // DIFF + union UINT_FLOAT PA_SC_CLIPRECT_RULE; //// // = 0x2820C, // SAME + union UINT_FLOAT PA_SC_CLIPRECT_0_TL; //// // = 0x28210, // DIFF + union UINT_FLOAT PA_SC_CLIPRECT_0_BR; //// // = 0x28214, // DIFF + union UINT_FLOAT PA_SC_CLIPRECT_1_TL; //// // = 0x28218, // DIFF + union UINT_FLOAT PA_SC_CLIPRECT_1_BR; //// // = 0x2821C, // DIFF + union UINT_FLOAT PA_SC_CLIPRECT_2_TL; //// // = 0x28220, // DIFF + union UINT_FLOAT PA_SC_CLIPRECT_2_BR; //// // = 0x28224, // DIFF + union UINT_FLOAT PA_SC_CLIPRECT_3_TL; //// // = 0x28228, // DIFF + union UINT_FLOAT PA_SC_CLIPRECT_3_BR; //// // = 0x2822C, // DIFF + union UINT_FLOAT PA_SC_EDGERULE; // = 0x28230, // SAME + union UINT_FLOAT PA_SU_HARDWARE_SCREEN_OFFSET; // = 0x28234, // + union UINT_FLOAT PA_SC_GENERIC_SCISSOR_TL; //// // = 0x28240, // DIFF + union UINT_FLOAT PA_SC_GENERIC_SCISSOR_BR; //// // = 0x28244, // DIFF + + EVERGREEN_VIEWPORT_STATE viewport[EVERGREEN_MAX_VIEWPORTS]; + EVERGREEN_UCP_STATE ucp[EVERGREEN_MAX_UCP]; + + union UINT_FLOAT PA_CL_POINT_X_RAD; // = 0x287D4, // SAME 0x28E10 + union UINT_FLOAT PA_CL_POINT_Y_RAD; // = 0x287D8, // SAME 0x28E14 + union UINT_FLOAT PA_CL_POINT_SIZE; // = 0x287DC, // SAME 0x28E18 + union UINT_FLOAT PA_CL_POINT_CULL_RAD; // = 0x287E0, // SAME 0x28E1C + union UINT_FLOAT PA_CL_CLIP_CNTL; //// // = 0x28810, // SAME + union UINT_FLOAT PA_SU_SC_MODE_CNTL; //// // = 0x28814, // SAME + union UINT_FLOAT PA_CL_VTE_CNTL; //// // = 0x28818, // SAME + union UINT_FLOAT PA_CL_VS_OUT_CNTL; //// // = 0x2881C, // SAME + union UINT_FLOAT PA_CL_NANINF_CNTL; //// // = 0x28820, // SAME + union UINT_FLOAT PA_SU_LINE_STIPPLE_CNTL; // = 0x28824, // + union UINT_FLOAT PA_SU_LINE_STIPPLE_SCALE; // = 0x28828, // + union UINT_FLOAT PA_SU_PRIM_FILTER_CNTL; // = 0x2882C, // + union UINT_FLOAT PA_SU_POINT_SIZE; //// // = 0x28A00, // SAME + union UINT_FLOAT PA_SU_POINT_MINMAX; //// // = 0x28A04, // SAME + union UINT_FLOAT PA_SU_LINE_CNTL; //// // = 0x28A08, // SAME + union UINT_FLOAT PA_SC_LINE_STIPPLE; // = 0x28A0C, // SAME + union UINT_FLOAT PA_SC_MODE_CNTL_0; //// // = 0x28A48, // + union UINT_FLOAT PA_SC_MODE_CNTL_1; //// // = 0x28A4C, // + union UINT_FLOAT PA_SU_POLY_OFFSET_DB_FMT_CNTL; //// // = 0x28B78, // SAME 0x28DF8 + union UINT_FLOAT PA_SU_POLY_OFFSET_CLAMP; //// // = 0x28B7C, // SAME 0x28DFC + union UINT_FLOAT PA_SU_POLY_OFFSET_FRONT_SCALE;//// // = 0x28B80, // SAME 0x28E00 + union UINT_FLOAT PA_SU_POLY_OFFSET_FRONT_OFFSET; //// // = 0x28B84, // SAME 0x28E04 + union UINT_FLOAT PA_SU_POLY_OFFSET_BACK_SCALE; //// // = 0x28B88, // SAME 0x28E08 + union UINT_FLOAT PA_SU_POLY_OFFSET_BACK_OFFSET; //// // = 0x28B8C, // SAME 0x28E0C + union UINT_FLOAT PA_SC_LINE_CNTL; //// // = 0x28C00, // DIFF + union UINT_FLOAT PA_SC_AA_CONFIG; //// // = 0x28C04, // SAME + union UINT_FLOAT PA_SU_VTX_CNTL; //// // = 0x28C08, // SAME + union UINT_FLOAT PA_CL_GB_VERT_CLIP_ADJ; //// // = 0x28C0C, // SAME + union UINT_FLOAT PA_CL_GB_VERT_DISC_ADJ; //// // = 0x28C10, // SAME + union UINT_FLOAT PA_CL_GB_HORZ_CLIP_ADJ; //// // = 0x28C14, // SAME + union UINT_FLOAT PA_CL_GB_HORZ_DISC_ADJ; //// // = 0x28C18, // SAME + union UINT_FLOAT PA_SC_AA_SAMPLE_LOCS_0; //// // = 0x28C1C, // + union UINT_FLOAT PA_SC_AA_SAMPLE_LOCS_1; //// // = 0x28C20, // + union UINT_FLOAT PA_SC_AA_SAMPLE_LOCS_2; //// // = 0x28C24, // + union UINT_FLOAT PA_SC_AA_SAMPLE_LOCS_3; //// // = 0x28C28, // + union UINT_FLOAT PA_SC_AA_SAMPLE_LOCS_4; //// // = 0x28C2C, // + union UINT_FLOAT PA_SC_AA_SAMPLE_LOCS_5; //// // = 0x28C30, // + union UINT_FLOAT PA_SC_AA_SAMPLE_LOCS_6; //// // = 0x28C34, // + union UINT_FLOAT PA_SC_AA_SAMPLE_LOCS_7; //// // = 0x28C38, // + union UINT_FLOAT PA_SC_AA_MASK; //// // = 0x28C3C, // SAME 0x28C48 + +/* Registers from VGT block: */ + union UINT_FLOAT VGT_INDEX_TYPE; // = 0x895C, // SAME + union UINT_FLOAT VGT_PRIMITIVE_TYPE; // = 0x8958, // SAME + union UINT_FLOAT VGT_MAX_VTX_INDX; //// // = 0x28400, // SAME + union UINT_FLOAT VGT_MIN_VTX_INDX; //// // = 0x28404, // SAME + union UINT_FLOAT VGT_INDX_OFFSET; //// // = 0x28408, // SAME + union UINT_FLOAT VGT_MULTI_PRIM_IB_RESET_INDX; // = 0x2840C, // SAME + + union UINT_FLOAT VGT_DRAW_INITIATOR; // = 0x287F0, // SAME + union UINT_FLOAT VGT_IMMED_DATA; // = 0x287F4, // SAME + + union UINT_FLOAT VGT_OUTPUT_PATH_CNTL; //// // = 0x28A10, // DIFF + union UINT_FLOAT VGT_HOS_CNTL; // = 0x28A14, // SAME + union UINT_FLOAT VGT_HOS_MAX_TESS_LEVEL; // = 0x28A18, // SAME + union UINT_FLOAT VGT_HOS_MIN_TESS_LEVEL; // = 0x28A1C, // SAME + union UINT_FLOAT VGT_HOS_REUSE_DEPTH; // = 0x28A20, // SAME + union UINT_FLOAT VGT_GROUP_PRIM_TYPE; // = 0x28A24, // SAME + union UINT_FLOAT VGT_GROUP_FIRST_DECR; // = 0x28A28, // SAME + union UINT_FLOAT VGT_GROUP_DECR; // = 0x28A2C, // SAME + union UINT_FLOAT VGT_GROUP_VECT_0_CNTL; // = 0x28A30, // SAME + union UINT_FLOAT VGT_GROUP_VECT_1_CNTL; // = 0x28A34, // SAME + union UINT_FLOAT VGT_GROUP_VECT_0_FMT_CNTL; // = 0x28A38, // SAME + union UINT_FLOAT VGT_GROUP_VECT_1_FMT_CNTL; // = 0x28A3C, // SAME + union UINT_FLOAT VGT_GS_MODE; //// // = 0x28A40, // DIFF + + union UINT_FLOAT VGT_PRIMITIVEID_EN; //// // = 0x28A84, // SAME + union UINT_FLOAT VGT_DMA_NUM_INSTANCES; //// // = 0x28A88, // SAME + union UINT_FLOAT VGT_EVENT_INITIATOR; // = 0x28A90, // SAME + union UINT_FLOAT VGT_MULTI_PRIM_IB_RESET_EN; // = 0x28A94, // SAME + union UINT_FLOAT VGT_INSTANCE_STEP_RATE_0; //// // = 0x28AA0, // SAME + union UINT_FLOAT VGT_INSTANCE_STEP_RATE_1; //// // = 0x28AA4, // SAME + union UINT_FLOAT VGT_REUSE_OFF; //// // = 0x28AB4, // SAME + union UINT_FLOAT VGT_VTX_CNT_EN; //// // = 0x28AB8, // SAME + + union UINT_FLOAT VGT_SHADER_STAGES_EN; //// // = 0x28B54, // + + union UINT_FLOAT VGT_STRMOUT_CONFIG; //// // = 0x28B94, // + union UINT_FLOAT VGT_STRMOUT_BUFFER_CONFIG; //// // = 0x28B98, // + union UINT_FLOAT VGT_VERTEX_REUSE_BLOCK_CNTL;//// // = 0x28C58, // SAME + union UINT_FLOAT VGT_OUT_DEALLOC_CNTL; //// // = 0x28C5C, // SAME + +/* Registers from SQ block: */ + union UINT_FLOAT SQ_VTX_SEMANTIC_0; //// // = 0x28380, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_1; //// // = 0x28384, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_2; //// // = 0x28388, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_3; //// // = 0x2838C, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_4; //// // = 0x28390, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_5; //// // = 0x28394, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_6; //// // = 0x28398, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_7; //// // = 0x2839C, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_8; //// // = 0x283A0, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_9; //// // = 0x283A4, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_10; //// // = 0x283A8, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_11; //// // = 0x283AC, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_12; //// // = 0x283B0, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_13; //// // = 0x283B4, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_14; //// // = 0x283B8, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_15; //// // = 0x283BC, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_16; //// // = 0x283C0, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_17; //// // = 0x283C4, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_18; //// // = 0x283C8, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_19; //// // = 0x283CC, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_20; //// // = 0x283D0, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_21; //// // = 0x283D4, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_22; //// // = 0x283D8, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_23; //// // = 0x283DC, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_24; //// // = 0x283E0, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_25; //// // = 0x283E4, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_26; //// // = 0x283E8, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_27; //// // = 0x283EC, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_28; //// // = 0x283F0, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_29; //// // = 0x283F4, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_30; //// // = 0x283F8, // SAME + union UINT_FLOAT SQ_VTX_SEMANTIC_31; //// // = 0x283FC, // SAME + union UINT_FLOAT SQ_DYN_GPR_RESOURCE_LIMIT_1;//// // = 0x28838, // + + union UINT_FLOAT SQ_PGM_RESOURCES_PS; //// // = 0x28844, // DIFF 0x28850 + union UINT_FLOAT SQ_PGM_RESOURCES_2_PS; //// // = 0x28848, // + union UINT_FLOAT SQ_PGM_EXPORTS_PS; //// // = 0x2884C, // SAME 0x28854 + + union UINT_FLOAT SQ_PGM_RESOURCES_VS;//// // = 0x28860, // DIFF 0x28868 + union UINT_FLOAT SQ_PGM_RESOURCES_2_VS; //// // = 0x28864, // + union UINT_FLOAT SQ_PGM_START_GS; //// // = 0x28874, // SAME 0x2886C + union UINT_FLOAT SQ_PGM_RESOURCES_GS; //// // = 0x28878, // DIFF 0x2887C + union UINT_FLOAT SQ_PGM_RESOURCES_2_GS; //// // = 0x2887C, // + union UINT_FLOAT SQ_PGM_START_ES; //// // = 0x2888C, // SAME 0x28880 + union UINT_FLOAT SQ_PGM_RESOURCES_ES; //// // = 0x28890, // DIFF + union UINT_FLOAT SQ_PGM_RESOURCES_2_ES; //// // = 0x28894, // + union UINT_FLOAT SQ_PGM_START_FS; //// // = 0x288A4, // SAME 0x28894 + union UINT_FLOAT SQ_PGM_RESOURCES_FS; //// // = 0x288A8, // DIFF 0x288A4 + union UINT_FLOAT SQ_PGM_START_HS; // = 0x288B8, // + union UINT_FLOAT SQ_PGM_RESOURCES_HS; // = 0x288BC, // + union UINT_FLOAT SQ_PGM_RESOURCES_2_HS;//// // = 0x288C0, // + union UINT_FLOAT SQ_PGM_START_LS; // = 0x288D0, // + union UINT_FLOAT SQ_PGM_RESOURCES_LS; // = 0x288D4, // + union UINT_FLOAT SQ_PGM_RESOURCES_2_LS; //// // = 0x288D8, // + union UINT_FLOAT SQ_LDS_ALLOC_PS; //// // = 0x288EC, // + union UINT_FLOAT SQ_ESGS_RING_ITEMSIZE; //// // = 0x28900, // SAME 0x288A8 + union UINT_FLOAT SQ_GSVS_RING_ITEMSIZE; //// // = 0x28904, // SAME 0x288AC + union UINT_FLOAT SQ_ESTMP_RING_ITEMSIZE; //// // = 0x28908, // SAME 0x288B0 + union UINT_FLOAT SQ_GSTMP_RING_ITEMSIZE; //// // = 0x2890C, // SAME 0x288B4 + union UINT_FLOAT SQ_VSTMP_RING_ITEMSIZE; //// // = 0x28910, // SAME 0x288B8 + union UINT_FLOAT SQ_PSTMP_RING_ITEMSIZE; //// // = 0x28914, // SAME 0x288BC + union UINT_FLOAT SQ_GS_VERT_ITEMSIZE; //// // = 0x2891C, // SAME 0x288C8 + union UINT_FLOAT SQ_GS_VERT_ITEMSIZE_1; // = 0x28920, // + union UINT_FLOAT SQ_GS_VERT_ITEMSIZE_2; // = 0x28924, // + union UINT_FLOAT SQ_GS_VERT_ITEMSIZE_3; // = 0x28928, // + + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_0; // = 0x289C0, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_1; // = 0x289C4, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_2; // = 0x289C8, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_3; // = 0x289CC, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_4; // = 0x289D0, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_5; // = 0x289D4, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_6; // = 0x289D8, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_7; // = 0x289DC, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_8; // = 0x289E0, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_9; // = 0x289E4, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_10; // = 0x289E8, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_11; // = 0x289EC, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_12; // = 0x289F0, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_13; // = 0x289F4, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_14; // = 0x289F8, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_GS_15; // = 0x289FC, // SAME + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_0; // = 0x28F00, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_1; // = 0x28F04, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_2; // = 0x28F08, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_3; // = 0x28F0C, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_4; // = 0x28F10, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_5; // = 0x28F14, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_6; // = 0x28F18, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_7; // = 0x28F1C, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_8; // = 0x28F20, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_9; // = 0x28F24, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_10; // = 0x28F28, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_11; // = 0x28F2C, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_12; // = 0x28F30, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_13; // = 0x28F34, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_14; // = 0x28F38, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_HS_15; // = 0x28F3C, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_0; // = 0x28F40, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_1; // = 0x28F44, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_2; // = 0x28F48, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_3; // = 0x28F4C, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_4; // = 0x28F50, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_5; // = 0x28F54, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_6; // = 0x28F58, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_7; // = 0x28F5C, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_8; // = 0x28F60, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_9; // = 0x28F64, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_10; // = 0x28F68, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_11; // = 0x28F6C, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_12; // = 0x28F70, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_13; // = 0x28F74, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_14; // = 0x28F78, // + union UINT_FLOAT SQ_ALU_CONST_CACHE_LS_15; // = 0x28F7C, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_0; // = 0x28F80, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_1; // = 0x28F84, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_2; // = 0x28F88, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_3; // = 0x28F8C, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_4; // = 0x28F90, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_5; // = 0x28F94, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_6; // = 0x28F98, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_7; // = 0x28F9C, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_8; // = 0x28FA0, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_9; // = 0x28FA4, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_10; // = 0x28FA8, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_11; // = 0x28FAC, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_12; // = 0x28FB0, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_13; // = 0x28FB4, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_14; // = 0x28FB8, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_HS_15; // = 0x28FBC, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_0; // = 0x28FC0, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_1; // = 0x28FC4, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_2; // = 0x28FC8, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_3; // = 0x28FCC, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_4; // = 0x28FD0, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_5; // = 0x28FD4, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_6; // = 0x28FD8, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_7; // = 0x28FDC, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_8; // = 0x28FE0, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_9; // = 0x28FE4, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_10; // = 0x28FE8, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_11; // = 0x28FEC, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_12; // = 0x28FF0, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_13; // = 0x28FF4, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_14; // = 0x28FF8, // + union UINT_FLOAT SQ_ALU_CONST_BUFFER_SIZE_LS_15; // = 0x28FFC, // + + EVERGREEN_PS_RES ps; + EVERGREEN_VS_RES vs; + +/* Registers from SPI block: */ + union UINT_FLOAT SPI_VS_OUT_ID_0; //// // = 0x2861C, // SAME 0x28614 + union UINT_FLOAT SPI_VS_OUT_ID_1; //// // = 0x28620, // SAME 0x28618 + union UINT_FLOAT SPI_VS_OUT_ID_2; //// // = 0x28624, // SAME 0x2861C + union UINT_FLOAT SPI_VS_OUT_ID_3; //// // = 0x28628, // SAME 0x28620 + union UINT_FLOAT SPI_VS_OUT_ID_4; //// // = 0x2862C, // SAME 0x28624 + union UINT_FLOAT SPI_VS_OUT_ID_5; //// // = 0x28630, // SAME 0x28628 + union UINT_FLOAT SPI_VS_OUT_ID_6; //// // = 0x28634, // SAME 0x2862C + union UINT_FLOAT SPI_VS_OUT_ID_7; //// // = 0x28638, // SAME 0x28630 + union UINT_FLOAT SPI_VS_OUT_ID_8; //// // = 0x2863C, // SAME 0x28634 + union UINT_FLOAT SPI_VS_OUT_ID_9; //// // = 0x28640, // SAME 0x28638 + union UINT_FLOAT SPI_PS_INPUT_CNTL[32]; //// // = 0x28644, // SAME + + union UINT_FLOAT SPI_VS_OUT_CONFIG; //// // = 0x286C4, // SAME + union UINT_FLOAT SPI_THREAD_GROUPING; //// // = 0x286C8, // DIFF + union UINT_FLOAT SPI_PS_IN_CONTROL_0; //// // = 0x286CC, // SAME + union UINT_FLOAT SPI_PS_IN_CONTROL_1; //// // = 0x286D0, // SAME + union UINT_FLOAT SPI_INTERP_CONTROL_0; //// // = 0x286D4, // SAME + union UINT_FLOAT SPI_INPUT_Z; //// // = 0x286D8, // SAME + union UINT_FLOAT SPI_FOG_CNTL; //// // = 0x286DC, // SAME + union UINT_FLOAT SPI_BARYC_CNTL; //// // = 0x286E0, // + union UINT_FLOAT SPI_PS_IN_CONTROL_2; //// // = 0x286E4, // + union UINT_FLOAT SPI_COMPUTE_INPUT_CNTL; // = 0x286E8, // + union UINT_FLOAT SPI_COMPUTE_NUM_THREAD_X; // = 0x286EC, // + union UINT_FLOAT SPI_COMPUTE_NUM_THREAD_Y; // = 0x286F0, // + union UINT_FLOAT SPI_COMPUTE_NUM_THREAD_Z; // = 0x286F4, // + +/* Registers from SX block: */ + union UINT_FLOAT SX_MISC; // = 0x28350, // SAME + union UINT_FLOAT SX_SURFACE_SYNC; // = 0x28354, // DIFF + union UINT_FLOAT SX_ALPHA_TEST_CONTROL; //// // = 0x28410, // SAME + union UINT_FLOAT SX_ALPHA_REF; // = 0x28438, // SAME + +/* Registers from DB block: */ + union UINT_FLOAT DB_RENDER_CONTROL; //// // = 0x28000, // DIFF 0x28D0C + union UINT_FLOAT DB_COUNT_CONTROL; //// // = 0x28004, // + union UINT_FLOAT DB_DEPTH_VIEW; //// // = 0x28008, // DIFF 0x28004 + union UINT_FLOAT DB_RENDER_OVERRIDE; //// // = 0x2800C, // DIFF 0x28D10 + union UINT_FLOAT DB_RENDER_OVERRIDE2; //// // = 0x28010, // + union UINT_FLOAT DB_HTILE_DATA_BASE; //// // = 0x28014, // SAME + union UINT_FLOAT DB_STENCIL_CLEAR; //// // = 0x28028, // SAME + union UINT_FLOAT DB_DEPTH_CLEAR; //// // = 0x2802C, // SAME + union UINT_FLOAT DB_Z_INFO; //// // = 0x28040, // + union UINT_FLOAT DB_STENCIL_INFO; //// // = 0x28044, // + union UINT_FLOAT DB_Z_READ_BASE; //// // = 0x28048, // + union UINT_FLOAT DB_STENCIL_READ_BASE;//// // = 0x2804C, // + union UINT_FLOAT DB_Z_WRITE_BASE; //// // = 0x28050, // + union UINT_FLOAT DB_STENCIL_WRITE_BASE; //// // = 0x28054, // + union UINT_FLOAT DB_DEPTH_SIZE; //// // = 0x28058, // DIFF 0x28000 + union UINT_FLOAT DB_DEPTH_SLICE; //// // = 0x2805C, // + union UINT_FLOAT DB_STENCILREFMASK; // = 0x28430, // SAME + union UINT_FLOAT DB_STENCILREFMASK_BF; // = 0x28434, // SAME + union UINT_FLOAT DB_DEPTH_CONTROL; //// // = 0x28800, // SAME + union UINT_FLOAT DB_SHADER_CONTROL;//// // = 0x2880C, // DIFF + union UINT_FLOAT DB_HTILE_SURFACE; //// // = 0x28ABC, // SAME 0x28D24 + union UINT_FLOAT DB_SRESULTS_COMPARE_STATE0; //// // = 0x28AC0, // SAME 0x28D28 + union UINT_FLOAT DB_SRESULTS_COMPARE_STATE1; //// // = 0x28AC4, // SAME 0x28D2C + union UINT_FLOAT DB_PRELOAD_CONTROL; //// // = 0x28AC8, // SAME 0x28D30 + union UINT_FLOAT DB_ALPHA_TO_MASK; //// // = 0x28B70, // SAME 0x28D44 + +/* Registers from CB block: */ + union UINT_FLOAT CB_TARGET_MASK; //// // = 0x28238, // SAME + union UINT_FLOAT CB_SHADER_MASK; //// // = 0x2823C, // SAME + union UINT_FLOAT CB_BLEND_RED; //// // = 0x28414, // SAME + union UINT_FLOAT CB_BLEND_GREEN; //// // = 0x28418, // SAME + union UINT_FLOAT CB_BLEND_BLUE; //// // = 0x2841C, // SAME + union UINT_FLOAT CB_BLEND_ALPHA; //// // = 0x28420, // SAME + union UINT_FLOAT CB_BLEND0_CONTROL; //// // = 0x28780, // DIFF + union UINT_FLOAT CB_BLEND1_CONTROL; // = 0x28784, // DIFF + union UINT_FLOAT CB_BLEND2_CONTROL; // = 0x28788, // DIFF + union UINT_FLOAT CB_BLEND3_CONTROL; // = 0x2878C, // DIFF + union UINT_FLOAT CB_BLEND4_CONTROL; // = 0x28790, // DIFF + union UINT_FLOAT CB_BLEND5_CONTROL; // = 0x28794, // DIFF + union UINT_FLOAT CB_BLEND6_CONTROL; // = 0x28798, // DIFF + union UINT_FLOAT CB_BLEND7_CONTROL; // = 0x2879C, // DIFF + union UINT_FLOAT CB_COLOR_CONTROL; //// // = 0x28808, // DIFF + union UINT_FLOAT CB_CLRCMP_CONTROL; //// // = 0x28C40, // SAME 0x28C30 + union UINT_FLOAT CB_CLRCMP_SRC; //// // = 0x28C44, // SAME 0x28C34 + union UINT_FLOAT CB_CLRCMP_DST; //// // = 0x28C48, // SAME 0x28C38 + union UINT_FLOAT CB_CLRCMP_MSK; //// // = 0x28C4C, // SAME 0x28C3C + + EVERGREEN_RENDER_TARGET_STATE render_target[EVERGREEN_MAX_RENDER_TARGETS]; + + radeonTexObj* textures[R700_TEXTURE_NUMBERUNITS]; + + EVERGREEN_CONFIG evergreen_config; + + GLboolean bEnablePerspective; + +} EVERGREEN_CHIP_CONTEXT; + +#endif /* _EVERGREEN_CHIP_H_ */
\ No newline at end of file diff --git a/src/mesa/drivers/dri/r600/evergreen_context.c b/src/mesa/drivers/dri/r600/evergreen_context.c new file mode 100644 index 0000000000..65b5898efa --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_context.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#include "main/glheader.h" +#include "main/api_arrayelt.h" +#include "main/context.h" +#include "main/simple_list.h" +#include "main/imports.h" +#include "main/bufferobj.h" +#include "main/texobj.h" + +#include "radeon_common_context.h" +#include "evergreen_context.h" +#include "evergreen_state.h" +#include "r600_blit.h" + +static void evergreen_get_lock(radeonContextPtr rmesa) +{ + drm_radeon_sarea_t *sarea = rmesa->sarea; + + if (sarea->ctx_owner != rmesa->dri.hwContext) { + sarea->ctx_owner = rmesa->dri.hwContext; + if (!rmesa->radeonScreen->kernel_mm) + radeon_bo_legacy_texture_age(rmesa->radeonScreen->bom); + } +} + +static void evergreen_vtbl_emit_cs_header(struct radeon_cs *cs, radeonContextPtr rmesa) +{ + /* please flush pipe do all pending work */ + /* to be enabled */ +} + +static void evergreen_vtbl_pre_emit_atoms(radeonContextPtr radeon) +{ + //TODO apr.01 + //r700Start3D((context_t *)radeon); +} + +static void evergreen_fallback(GLcontext *ctx, GLuint bit, GLboolean mode) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + if (mode) + context->radeon.Fallback |= bit; + else + context->radeon.Fallback &= ~bit; +} + +static void evergreen_emit_query_finish(radeonContextPtr radeon) +{ + //TODO apr.01 + //context_t *context = (context_t*) radeon; + //BATCH_LOCALS(&context->radeon); + + struct radeon_query_object *query = radeon->query.current; + + //BEGIN_BATCH_NO_AUTOSTATE(4 + 2); + //R600_OUT_BATCH(CP_PACKET3(R600_IT_EVENT_WRITE, 2)); + //R600_OUT_BATCH(ZPASS_DONE); + //R600_OUT_BATCH(query->curr_offset + 8); /* hw writes qwords */ + //R600_OUT_BATCH(0x00000000); + //R600_OUT_BATCH_RELOC(VGT_EVENT_INITIATOR, query->bo, 0, 0, RADEON_GEM_DOMAIN_GTT, 0); + //END_BATCH(); + //assert(query->curr_offset < RADEON_QUERY_PAGE_SIZE); + query->emitted_begin = GL_FALSE; +} + +void evergreen_init_vtbl(radeonContextPtr radeon) +{ + radeon->vtbl.get_lock = evergreen_get_lock; + radeon->vtbl.update_viewport_offset = evergreenUpdateViewportOffset; + radeon->vtbl.emit_cs_header = evergreen_vtbl_emit_cs_header; + radeon->vtbl.swtcl_flush = NULL; + radeon->vtbl.pre_emit_atoms = evergreen_vtbl_pre_emit_atoms; + radeon->vtbl.fallback = evergreen_fallback; + radeon->vtbl.emit_query_finish = evergreen_emit_query_finish; + radeon->vtbl.check_blit = r600_check_blit; + radeon->vtbl.blit = r600_blit; + radeon->vtbl.is_format_renderable = radeonIsFormatRenderable; +} + + + diff --git a/src/mesa/slang/slang_link.h b/src/mesa/drivers/dri/r600/evergreen_context.h index 3e9fa2d743..4e50999c98 100644 --- a/src/mesa/slang/slang_link.h +++ b/src/mesa/drivers/dri/r600/evergreen_context.h @@ -1,8 +1,5 @@ /* - * Mesa 3-D graphics library - * Version: 7.2 - * - * Copyright (C) 2008 Brian Paul All Rights Reserved. + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -17,21 +14,25 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef SLANG_LINK_H -#define SLANG_LINK_H 1 +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#ifndef _EVERGREEN_CONTEXT_H_ +#define _EVERGREEN_CONTEXT_H_ + +extern void evergreen_init_vtbl(radeonContextPtr radeon); + +#endif //_EVERGREEN_CONTEXT_H_ -#include "main/mtypes.h" -extern void -_slang_link(GLcontext *ctx, GLhandleARB h, - struct gl_shader_program *shProg); -#endif diff --git a/src/mesa/drivers/dri/r600/evergreen_diff.h b/src/mesa/drivers/dri/r600/evergreen_diff.h new file mode 100644 index 0000000000..c3a5fd0a38 --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_diff.h @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#ifndef _EVERGREEN_DIFF_H_ +#define _EVERGREEN_DIFF_H_ + +enum { + /* CB_BLEND_CONTROL */ + EG_CB_BLENDX_CONTROL_ENABLE_bit = 1 << 30, + /* PA_SC_SCREEN_SCISSOR_TL */ + EG_PA_SC_SCREEN_SCISSOR_TL__TL_X_mask = 0xffff << 0, + EG_PA_SC_SCREEN_SCISSOR_TL__TL_Y_mask = 0xffff << 16, + /* PA_SC_SCREEN_SCISSOR_BR */ + EG_PA_SC_SCREEN_SCISSOR_BR__BR_X_mask = 0xffff << 0, + EG_PA_SC_SCREEN_SCISSOR_BR__BR_Y_mask = 0xffff << 16, + /* PA_SC_WINDOW_SCISSOR_TL */ + EG_PA_SC_WINDOW_SCISSOR_TL__TL_X_mask = 0x7fff << 0, + EG_PA_SC_WINDOW_SCISSOR_TL__TL_Y_mask = 0x7fff << 16, + /* PA_SC_WINDOW_SCISSOR_BR */ + EG_PA_SC_WINDOW_SCISSOR_BR__BR_X_mask = 0x7fff << 0, + EG_PA_SC_WINDOW_SCISSOR_BR__BR_Y_mask = 0x7fff << 16, + /* PA_SC_CLIPRECT_0_TL */ + EG_PA_SC_CLIPRECT_0_TL__TL_X_mask = 0x7fff << 0, + EG_PA_SC_CLIPRECT_0_TL__TL_Y_mask = 0x7fff << 16, + /* PA_SC_CLIPRECT_0_BR */ + EG_PA_SC_CLIPRECT_0_BR__BR_X_mask = 0x7fff << 0, + EG_PA_SC_CLIPRECT_0_BR__BR_Y_mask = 0x7fff << 16, + /* PA_SC_GENERIC_SCISSOR_TL */ + EG_PA_SC_GENERIC_SCISSOR_TL__TL_X_mask = 0x7fff << 0, + EG_PA_SC_GENERIC_SCISSOR_TL__TL_Y_mask = 0x7fff << 16, + /* PA_SC_GENERIC_SCISSOR_BR */ + EG_PA_SC_GENERIC_SCISSOR_BR__BR_X_mask = 0x7fff << 0, + EG_PA_SC_GENERIC_SCISSOR_BR__BR_Y_mask = 0x7fff << 16, + /* PA_SC_VPORT_SCISSOR_0_TL */ + EG_PA_SC_VPORT_SCISSOR_0_TL__TL_X_mask = 0x7fff << 0, + EG_PA_SC_VPORT_SCISSOR_0_TL__TL_Y_mask = 0x7fff << 16, + /* PA_SC_VPORT_SCISSOR_0_BR */ + EG_PA_SC_VPORT_SCISSOR_0_BR__BR_X_mask = 0x7fff << 0, + EG_PA_SC_VPORT_SCISSOR_0_BR__BR_Y_mask = 0x7fff << 16, + /* PA_SC_WINDOW_OFFSET */ + EG_PA_SC_WINDOW_OFFSET__WINDOW_X_OFFSET_shift = 0, + EG_PA_SC_WINDOW_OFFSET__WINDOW_X_OFFSET_mask = 0xffff << 0, + EG_PA_SC_WINDOW_OFFSET__WINDOW_Y_OFFSET_shift = 16, + EG_PA_SC_WINDOW_OFFSET__WINDOW_Y_OFFSET_mask = 0xffff << 16, + /* SPI_BARYC_CNTL */ + EG_SPI_BARYC_CNTL__PERSP_CENTROID_ENA_shift = 4, + EG_SPI_BARYC_CNTL__PERSP_CENTROID_ENA_mask = 0x3 << 4, + EG_SPI_BARYC_CNTL__LINEAR_CENTROID_ENA_shift = 20, + EG_SPI_BARYC_CNTL__LINEAR_CENTROID_ENA_mask = 0x3 << 20, + /* DB_SHADER_CONTROL */ + EG_DB_SHADER_CONTROL__DUAL_EXPORT_ENABLE_bit = 1 << 9, + + /* DB_Z_INFO */ + EG_DB_Z_INFO__FORMAT_shift = 0, //2; + EG_DB_Z_INFO__FORMAT_mask = 0x3, + //2; + EG_DB_Z_INFO__ARRAY_MODE_shift = 4, //4; + EG_DB_Z_INFO__ARRAY_MODE_mask = 0xf << 4, + EG_DB_Z_INFO__TILE_SPLIT_shift = 8, //3; + EG_DB_Z_INFO__TILE_SPLIT_mask = 0x7 << 8, + //1; + EG_DB_Z_INFO__NUM_BANKS_shift = 12, //2; + EG_DB_Z_INFO__NUM_BANKS_mask = 0x3 << 12, + //2; + EG_DB_Z_INFO__BANK_WIDTH_shift = 16, //2; + EG_DB_Z_INFO__BANK_WIDTH_mask = 0x3 << 16, + //2; + EG_DB_Z_INFO__BANK_HEIGHT_shift = 20, //2; + EG_DB_Z_INFO__BANK_HEIGHT_mask = 0x3 << 20, + + EG_Z_INVALID = 0x00000000, + EG_Z_16 = 0x00000001, + EG_Z_24 = 0x00000002, + EG_Z_32_FLOAT = 0x00000003, + EG_ADDR_SURF_TILE_SPLIT_256B = 0x00000002, + EG_ADDR_SURF_8_BANK = 0x00000002, + EG_ADDR_SURF_BANK_WIDTH_1 = 0x00000000, + EG_ADDR_SURF_BANK_HEIGHT_1 = 0x00000000, + /* DB_STENCIL_INFO */ + EG_DB_STENCIL_INFO__FORMAT_bit = 1, //1; + //7; + EG_DB_STENCIL_INFO__TILE_SPLIT_shift = 8, //3; + EG_DB_STENCIL_INFO__TILE_SPLIT_mask = 0x7 << 8, + + /* DB_DEPTH_SIZE */ + EG_DB_DEPTH_SIZE__PITCH_TILE_MAX_shift = 0, // 11; + EG_DB_DEPTH_SIZE__PITCH_TILE_MAX_mask = 0x7ff, + EG_DB_DEPTH_SIZE__HEIGHT_TILE_MAX_shift = 11, // 11; + EG_DB_DEPTH_SIZE__HEIGHT_TILE_MAX_mask = 0x7ff << 11, + + /* DB_COUNT_CONTROL */ + EG_DB_COUNT_CONTROL__ZPASS_INCREMENT_DISABLE_shift = 0, //1 + EG_DB_COUNT_CONTROL__ZPASS_INCREMENT_DISABLE_bit = 1, + EG_DB_COUNT_CONTROL__PERFECT_ZPASS_COUNTS_shift = 1, //1 + EG_DB_COUNT_CONTROL__PERFECT_ZPASS_COUNTS_bit = 1 << 1, + + /* CB_COLOR_CONTROL */ + //3; + EG_CB_COLOR_CONTROL__DEGAMMA_ENABLE_bit = 1 << 3,//1; + EG_CB_COLOR_CONTROL__MODE_shift = 4, //3; + EG_CB_COLOR_CONTROL__MODE_mask = 0x7 << 4, + //9; + EG_CB_COLOR_CONTROL__ROP3_shift = 16, //8; + EG_CB_COLOR_CONTROL__ROP3_mask = 0xff << 16, + EG_CB_NORMAL = 0x00000001, + + /* CB_COLOR0_INFO */ + EG_CB_COLOR0_INFO__ENDIAN_shift = 0, //2; + EG_CB_COLOR0_INFO__ENDIAN_mask = 0x3, + EG_CB_COLOR0_INFO__FORMAT_shift = 2, //6; + EG_CB_COLOR0_INFO__FORMAT_mask = 0x3f << 2, + EG_CB_COLOR0_INFO__ARRAY_MODE_shift = 8, //4; + EG_CB_COLOR0_INFO__ARRAY_MODE_mask = 0xf << 8, + EG_CB_COLOR0_INFO__NUMBER_TYPE_shift = 12, //3; + EG_CB_COLOR0_INFO__NUMBER_TYPE_mask = 0x7 << 12, + EG_CB_COLOR0_INFO__COMP_SWAP_shift = 15, //2; + EG_CB_COLOR0_INFO__COMP_SWAP_mask = 0x3 << 15, + EG_CB_COLOR0_INFO__FAST_CLEAR_bit = 1 << 17,//1; + EG_CB_COLOR0_INFO__COMPRESSION_bit = 1 << 18,//1; + EG_CB_COLOR0_INFO__BLEND_CLAMP_bit = 1 << 19,//1; + EG_CB_COLOR0_INFO__BLEND_BYPASS_bit = 1 << 20,//1; + EG_CB_COLOR0_INFO__SIMPLE_FLOAT_bit = 1 << 21,//1; + EG_CB_COLOR0_INFO__ROUND_MODE_bit = 1 << 22,//1; + EG_CB_COLOR0_INFO__TILE_COMPACT_bit = 1 << 23,//1; + EG_CB_COLOR0_INFO__SOURCE_FORMAT_shift = 24, //2; + EG_CB_COLOR0_INFO__SOURCE_FORMAT_mask = 0x3 << 24, + EG_CB_COLOR0_INFO__RAT_bit = 1 << 26,//1; + EG_CB_COLOR0_INFO__RESOURCE_TYPE_shift = 27, //3; + EG_CB_COLOR0_INFO__RESOURCE_TYPE_mask = 0x7 << 27, + + /* CB_COLOR0_ATTRIB */ + EG_CB_COLOR0_ATTRIB__NON_DISP_TILING_ORDER_shift = 4, + EG_CB_COLOR0_ATTRIB__NON_DISP_TILING_ORDER_bit = 1 << 4, + + /* SPI_CONFIG_CNTL_1 */ + EG_SPI_CONFIG_CNTL_1__VTX_DONE_DELAY_shift = 0, + EG_SPI_CONFIG_CNTL_1__VTX_DONE_DELAY_mask = 0xf, + /* SQ_MS_FIFO_SIZES */ + EG_SQ_MS_FIFO_SIZES__CACHE_FIFO_SIZE_shift = 0, + EG_SQ_MS_FIFO_SIZES__CACHE_FIFO_SIZE_mask = 0xff, + EG_SQ_MS_FIFO_SIZES__FETCH_FIFO_HIWATER_shift = 8, + EG_SQ_MS_FIFO_SIZES__FETCH_FIFO_HIWATER_mask = 0x1f << 8, + EG_SQ_MS_FIFO_SIZES__DONE_FIFO_HIWATER_shift = 16, + EG_SQ_MS_FIFO_SIZES__DONE_FIFO_HIWATER_mask = 0xff << 16, + EG_SQ_MS_FIFO_SIZES__ALU_UPDATE_FIFO_HIWATER_shift = 24, + EG_SQ_MS_FIFO_SIZES__ALU_UPDATE_FIFO_HIWATER_mask = 0x1f << 24, + /* SQ_CONFIG */ + EG_SQ_CONFIG__VC_ENABLE_bit = 1, + EG_SQ_CONFIG__EXPORT_SRC_C_bit = 1 << 1, + EG_SQ_CONFIG__PS_PRIO_shift = 24, + EG_SQ_CONFIG__PS_PRIO_mask = 0x3 << 24, + EG_SQ_CONFIG__VS_PRIO_shift = 26, + EG_SQ_CONFIG__VS_PRIO_mask = 0x3 << 26, + EG_SQ_CONFIG__GS_PRIO_shift = 28, + EG_SQ_CONFIG__GS_PRIO_mask = 0x3 << 28, + EG_SQ_CONFIG__ES_PRIO_shift = 30, + EG_SQ_CONFIG__ES_PRIO_mask = 0x3 << 30, + /* PA_SC_FORCE_EOV_MAX_CNTS */ + EG_PA_SC_FORCE_EOV_MAX_CNTS__FORCE_EOV_MAX_CLK_CNT_shift = 0, + EG_PA_SC_FORCE_EOV_MAX_CNTS__FORCE_EOV_MAX_CLK_CNT_mask = 0x3fff, + EG_PA_SC_FORCE_EOV_MAX_CNTS__FORCE_EOV_MAX_REZ_CNT_shift = 16, + EG_PA_SC_FORCE_EOV_MAX_CNTS__FORCE_EOV_MAX_REZ_CNT_mask = 0x3fff << 16, + /* VGT_CACHE_INVALIDATION */ + EG_VGT_CACHE_INVALIDATION__CACHE_INVALIDATION_shift = 0, + EG_VGT_CACHE_INVALIDATION__CACHE_INVALIDATION_mask = 0x3, + /* CB_COLOR0_PITCH */ + EG_CB_COLOR0_PITCH__TILE_MAX_shift = 0, + EG_CB_COLOR0_PITCH__TILE_MAX_mask = 0x7ff, + /* CB_COLOR0_SLICE */ + EG_CB_COLOR0_SLICE__TILE_MAX_shift = 0, + EG_CB_COLOR0_SLICE__TILE_MAX_mask = 0x3fffff, + /* SQ_VTX_CONSTANT_WORD3_0 */ + EG_SQ_VTX_CONSTANT_WORD3_0__UNCACHED_shift = 2, + EG_SQ_VTX_CONSTANT_WORD3_0__UNCACHED_bit = 1 << 2, + + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_X_shift = 3, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_X_mask = 0x7 << 3, + + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_Y_shift = 6, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_Y_mask = 0x7 << 6, + + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_Z_shift = 9, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_Z_mask = 0x7 << 9, + + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_W_shift = 12, + EG_SQ_VTX_CONSTANT_WORD3_0__DST_SEL_W_mask = 0x7 << 12, + /* SQ_VTX_CONSTANT_WORD4_0 */ + EG_SQ_VTX_CONSTANT_WORD4_0__NUM_ELEMENTS_shift = 0, + EG_SQ_VTX_CONSTANT_WORD4_0__NUM_ELEMENTS_mask = 0xFFFFFFFF, + /* SQ_VTX_CONSTANT_WORD7_0 */ + EG_SQ_VTX_CONSTANT_WORD7_0__TYPE_shift = 30, + EG_SQ_VTX_CONSTANT_WORD7_0__TYPE_mask = 0x3 << 30, + /* SQ_TEX_SAMPLER_WORD0_0 */ + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_shift = 0, // 3; + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_mask = 0x7, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_Y_shift = 3, // 3; + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_Y_mask = 0x7 << 3, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_Z_shift = 6, // 3; + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_Z_mask = 0x7 << 6, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MAG_FILTER_shift = 9, // 2; + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MAG_FILTER_mask = 0x3 << 9, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_shift = 11, // 2; + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_mask = 0x3 << 11, + EG_SQ_TEX_SAMPLER_WORD0_0__Z_FILTER_shift = 13, // 2; + EG_SQ_TEX_SAMPLER_WORD0_0__Z_FILTER_mask = 0x3 << 13, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_shift = 15, // 2; + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_mask = 0x3 << 15, + EG_SQ_TEX_SAMPLER_WORD0_0__MAX_ANISO_RATIO_shift = 17, // 3; + EG_SQ_TEX_SAMPLER_WORD0_0__MAX_ANISO_RATIO_mask = 0x7 << 17, + EG_SQ_TEX_SAMPLER_WORD0_0__BORDER_COLOR_TYPE_shift = 20,//2; + EG_SQ_TEX_SAMPLER_WORD0_0__BORDER_COLOR_TYPE_mask = 0x3 << 20, + EG_SQ_TEX_SAMPLER_WORD0_0__DCF_shift = 22, // 3; + EG_SQ_TEX_SAMPLER_WORD0_0__DCF_mask = 0x7 << 22, + EG_SQ_TEX_SAMPLER_WORD0_0__CHROMA_KEY_shift = 25, // 2; + EG_SQ_TEX_SAMPLER_WORD0_0__CHROMA_KEY_mask = 0x3 << 25, + EG_SQ_TEX_SAMPLER_WORD0_0__ANISO_THRESHOLD_shift = 27, // 3; + EG_SQ_TEX_SAMPLER_WORD0_0__ANISO_THRESHOLD_mask = 0x7 << 27, + EG_SQ_TEX_SAMPLER_WORD0_0__Reserved_shift = 30, // 2 + EG_SQ_TEX_SAMPLER_WORD0_0__Reserved_mask = 0x3 << 30, + /* SQ_TEX_SAMPLER_WORD1_0 */ + EG_SQ_TEX_SAMPLER_WORD1_0__MIN_LOD_shift = 0, // 12; + EG_SQ_TEX_SAMPLER_WORD1_0__MIN_LOD_mask = 0xfff, + EG_SQ_TEX_SAMPLER_WORD1_0__MAX_LOD_shift = 12,// 12; + EG_SQ_TEX_SAMPLER_WORD1_0__MAX_LOD_mask = 0xfff << 12, + /* SQ_TEX_SAMPLER_WORD2_0 */ + EG_SQ_TEX_SAMPLER_WORD2_0__LOD_BIAS_shift = 0, //14; + EG_SQ_TEX_SAMPLER_WORD2_0__LOD_BIAS_mask = 0x3fff, + EG_SQ_TEX_SAMPLER_WORD2_0__LOD_BIAS_SEC_shift = 14,//6; + EG_SQ_TEX_SAMPLER_WORD2_0__LOD_BIAS_SEC_mask = 0x3f << 14, + EG_SQ_TEX_SAMPLER_WORD2_0__MC_COORD_TRUNCATE_shift = 20,//1; + EG_SQ_TEX_SAMPLER_WORD2_0__MC_COORD_TRUNCATE_bit = 1 << 20, + EG_SQ_TEX_SAMPLER_WORD2_0__FORCE_DEGAMMA_shift = 21,//1; + EG_SQ_TEX_SAMPLER_WORD2_0__FORCE_DEGAMMA_bit = 1 << 21, + EG_SQ_TEX_SAMPLER_WORD2_0__ANISO_BIAS_shift = 22,//6; + EG_SQ_TEX_SAMPLER_WORD2_0__ANISO_BIAS_mask = 0x3f << 22, + EG_SQ_TEX_SAMPLER_WORD2_0__TRUNCATE_COORD_shift = 28,//1; + EG_SQ_TEX_SAMPLER_WORD2_0__TRUNCATE_COORD_bit = 1 << 28, + EG_SQ_TEX_SAMPLER_WORD2_0__DISABLE_CUBE_WRAP_shift = 29,//1; + EG_SQ_TEX_SAMPLER_WORD2_0__DISABLE_CUBE_WRAP_bit = 1 << 29, + EG_SQ_TEX_SAMPLER_WORD2_0__Reserved_shift = 30,//1; + EG_SQ_TEX_SAMPLER_WORD2_0__Reserved_bit = 1 << 30, + EG_SQ_TEX_SAMPLER_WORD2_0__TYPE_shift = 31,//1; + EG_SQ_TEX_SAMPLER_WORD2_0__TYPE_bit = 1 << 31, + /* SQ_TEX_RESOURCE_WORD0_0 */ + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_shift = 0, // 3; + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_mask = 0x7, + EG_SQ_TEX_RESOURCE_WORD0_0__ISET_shift = 3, // 1; + EG_SQ_TEX_RESOURCE_WORD0_0__ISET_bit = 1 << 3, + EG_SQ_TEX_RESOURCE_WORD0_0__Reserve_shift = 4, // 1; + EG_SQ_TEX_RESOURCE_WORD0_0__Reserve_bit = 1 << 4, + EG_SQ_TEX_RESOURCE_WORD0_0__NDTO_shift = 5, // 1; + EG_SQ_TEX_RESOURCE_WORD0_0__NDTO_bit = 1 << 5, + EG_SQ_TEX_RESOURCE_WORD0_0__PITCH_shift = 6, // 12; + EG_SQ_TEX_RESOURCE_WORD0_0__PITCH_mask = 0xfff << 6, + EG_SQ_TEX_RESOURCE_WORD0_0__TEX_WIDTH_shift = 18,// 14; + EG_SQ_TEX_RESOURCE_WORD0_0__TEX_WIDTH_mask = 0x3fff << 18, + /* SQ_TEX_RESOURCE_WORD1_0 */ + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_HEIGHT_shift = 0, // 14; + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_HEIGHT_mask = 0x3fff, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_shift = 14,// 13; + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_mask = 0x1fff << 14, + EG_SQ_TEX_RESOURCE_WORD1_0__Reserved_shift = 27,// 1; + EG_SQ_TEX_RESOURCE_WORD1_0__Reserved_bit = 1 << 27, + EG_SQ_TEX_RESOURCE_WORD1_0__ARRAY_MODE_shift = 28,// 4; + EG_SQ_TEX_RESOURCE_WORD1_0__ARRAY_MODE_mask = 0xf << 28, + /* SQ_TEX_RESOURCE_WORD6_0 */ + EG_SQ_TEX_RESOURCE_WORD6_0__MAX_ANISO_RATIO_shift = 0, //: 3; + EG_SQ_TEX_RESOURCE_WORD6_0__MAX_ANISO_RATIO_mask = 0x7, + EG_SQ_TEX_RESOURCE_WORD6_0__INTERLACED_shift = 6, //1; + EG_SQ_TEX_RESOURCE_WORD6_0__INTERLACED_bit = 1 << 6, + EG_SQ_TEX_RESOURCE_WORD6_0__MIN_LOD_shift = 8, //12; + EG_SQ_TEX_RESOURCE_WORD6_0__MIN_LOD_mask = 0xfff << 8, + EG_SQ_TEX_RESOURCE_WORD6_0__TILE_SPLIT_shift = 29,// 3; + EG_SQ_TEX_RESOURCE_WORD6_0__TILE_SPLIT_mask = 0x7 << 29, + /* SQ_TEX_RESOURCE_WORD7_0 */ + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift = 0, // 6; + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask = 0x3f, + EG_SQ_TEX_RESOURCE_WORD7_0__MACRO_TILE_ASPECT_shift = 6, // 2; + EG_SQ_TEX_RESOURCE_WORD7_0__MACRO_TILE_ASPECT_mask = 0x3 << 6, + EG_SQ_TEX_RESOURCE_WORD7_0__BANK_WIDTH_shift = 8, // 2; + EG_SQ_TEX_RESOURCE_WORD7_0__BANK_WIDTH_mask = 0x3 << 8, + EG_SQ_TEX_RESOURCE_WORD7_0__BANK_HEIGHT_shift = 10,// 2; + EG_SQ_TEX_RESOURCE_WORD7_0__BANK_HEIGHT_mask = 0x3 << 10, + EG_SQ_TEX_RESOURCE_WORD7_0__DEPTH_SAMPLE_ORDER_shift = 15,// 1; + EG_SQ_TEX_RESOURCE_WORD7_0__DEPTH_SAMPLE_ORDER_bit = 1 << 15, + EG_SQ_TEX_RESOURCE_WORD7_0__NUM_BANKS_shift = 16,// 2; + EG_SQ_TEX_RESOURCE_WORD7_0__NUM_BANKS_mask = 0x3 << 16, + EG_SQ_TEX_RESOURCE_WORD7_0__TYPE_shift = 30,// 2; + EG_SQ_TEX_RESOURCE_WORD7_0__TYPE_mask = 0x3 << 30, +}; + +/* */ + +#define EG_SQ_FETCH_RESOURCE_COUNT 0x00000400 +#define EG_SQ_TEX_SAMPLER_COUNT 0x0000006c +#define EG_SQ_LOOP_CONST_COUNT 0x000000c0 + +#define EG_SET_RESOURCE_OFFSET 0x30000 +#define EG_SET_RESOURCE_END 0x30400 //r600 := offset + 0x4000 + +#define EG_SET_LOOP_CONST_OFFSET 0x3A200 +#define EG_SET_LOOP_CONST_END 0x3A26C //r600 := offset + 0x180 + + +#define EG_SQ_FETCH_RESOURCE_VS_OFFSET 0x000000b0 +#define EG_FETCH_RESOURCE_STRIDE 8 + +#define EG_SET_BOOL_CONST_OFFSET 0x3A500 +#define EG_SET_BOOL_CONST_END 0x3A506 + + +#endif //_EVERGREEN_DIFF_H_ diff --git a/src/mesa/drivers/dri/r600/evergreen_fragprog.c b/src/mesa/drivers/dri/r600/evergreen_fragprog.c new file mode 100644 index 0000000000..b53ff424a0 --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_fragprog.c @@ -0,0 +1,817 @@ +/* + * Copyright (C) 2008-2009 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + * CooperYuan <cooper.yuan@amd.com>, <cooperyuan@gmail.com> + */ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "main/imports.h" + +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" +#include "program/program.h" + +#include "r600_context.h" +#include "r600_cmdbuf.h" +#include "r600_emit.h" + +#include "evergreen_vertprog.h" +#include "evergreen_fragprog.h" + +void evergreen_insert_wpos_code(GLcontext *ctx, struct gl_fragment_program *fprog) +{ + static const gl_state_index winstate[STATE_LENGTH] + = { STATE_INTERNAL, STATE_FB_SIZE, 0, 0, 0}; + struct prog_instruction *newInst, *inst; + GLint win_size; /* state reference */ + GLuint wpos_temp; /* temp register */ + int i, j; + + /* PARAM win_size = STATE_FB_SIZE */ + win_size = _mesa_add_state_reference(fprog->Base.Parameters, winstate); + + wpos_temp = fprog->Base.NumTemporaries++; + + /* scan program where WPOS is used and replace with wpos_temp */ + inst = fprog->Base.Instructions; + for (i = 0; i < fprog->Base.NumInstructions; i++) { + for (j=0; j < 3; j++) { + if(inst->SrcReg[j].File == PROGRAM_INPUT && + inst->SrcReg[j].Index == FRAG_ATTRIB_WPOS) { + inst->SrcReg[j].File = PROGRAM_TEMPORARY; + inst->SrcReg[j].Index = wpos_temp; + } + } + inst++; + } + + _mesa_insert_instructions(&(fprog->Base), 0, 1); + + newInst = fprog->Base.Instructions; + /* invert wpos.y + * wpos_temp.xyzw = wpos.x-yzw + winsize.0y00 */ + newInst[0].Opcode = OPCODE_ADD; + newInst[0].DstReg.File = PROGRAM_TEMPORARY; + newInst[0].DstReg.Index = wpos_temp; + newInst[0].DstReg.WriteMask = WRITEMASK_XYZW; + + newInst[0].SrcReg[0].File = PROGRAM_INPUT; + newInst[0].SrcReg[0].Index = FRAG_ATTRIB_WPOS; + newInst[0].SrcReg[0].Swizzle = SWIZZLE_XYZW; + newInst[0].SrcReg[0].Negate = NEGATE_Y; + + newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR; + newInst[0].SrcReg[1].Index = win_size; + newInst[0].SrcReg[1].Swizzle = MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_Y, SWIZZLE_ZERO, SWIZZLE_ZERO); + +} + +//TODO : Validate FP input with VP output. +void evergreen_Map_Fragment_Program(r700_AssemblerBase *pAsm, + struct gl_fragment_program *mesa_fp, + GLcontext *ctx) +{ + unsigned int unBit; + unsigned int i; + GLuint ui; + + /* match fp inputs with vp exports. */ + struct evergreen_vertex_program_cont *vpc = + (struct evergreen_vertex_program_cont *)ctx->VertexProgram._Current; + GLbitfield OutputsWritten = vpc->mesa_program.Base.OutputsWritten; + + pAsm->number_used_registers = 0; + +//Input mapping : mesa_fp->Base.InputsRead set the flag, set in + //The flags parsed in parse_attrib_binding. FRAG_ATTRIB_COLx, FRAG_ATTRIB_TEXx, ... + //MUST match order in Map_Vertex_Output + unBit = 1 << FRAG_ATTRIB_WPOS; + if(mesa_fp->Base.InputsRead & unBit) + { + pAsm->uiFP_AttributeMap[FRAG_ATTRIB_WPOS] = pAsm->number_used_registers++; + } + + unBit = 1 << VERT_RESULT_COL0; + if(OutputsWritten & unBit) + { + pAsm->uiFP_AttributeMap[FRAG_ATTRIB_COL0] = pAsm->number_used_registers++; + } + + unBit = 1 << VERT_RESULT_COL1; + if(OutputsWritten & unBit) + { + pAsm->uiFP_AttributeMap[FRAG_ATTRIB_COL1] = pAsm->number_used_registers++; + } + + unBit = 1 << VERT_RESULT_FOGC; + if(OutputsWritten & unBit) + { + pAsm->uiFP_AttributeMap[FRAG_ATTRIB_FOGC] = pAsm->number_used_registers++; + } + + for(i=0; i<8; i++) + { + unBit = 1 << (VERT_RESULT_TEX0 + i); + if(OutputsWritten & unBit) + { + pAsm->uiFP_AttributeMap[FRAG_ATTRIB_TEX0 + i] = pAsm->number_used_registers++; + } + } + +/* order has been taken care of */ +#if 1 + for(i=VERT_RESULT_VAR0; i<VERT_RESULT_MAX; i++) + { + unBit = 1 << i; + if(OutputsWritten & unBit) + { + pAsm->uiFP_AttributeMap[i-VERT_RESULT_VAR0+FRAG_ATTRIB_VAR0] = pAsm->number_used_registers++; + } + } +#else + if( (mesa_fp->Base.InputsRead >> FRAG_ATTRIB_VAR0) > 0 ) + { + struct evergreen_vertex_program_cont *vpc = + (struct evergreen_vertex_program_cont *)ctx->VertexProgram._Current; + struct gl_program_parameter_list * VsVarying = vpc->mesa_program.Base.Varying; + struct gl_program_parameter_list * PsVarying = mesa_fp->Base.Varying; + struct gl_program_parameter * pVsParam; + struct gl_program_parameter * pPsParam; + GLuint j, k; + GLuint unMaxVarying = 0; + + for(i=0; i<VsVarying->NumParameters; i++) + { + pAsm->uiFP_AttributeMap[i + FRAG_ATTRIB_VAR0] = 0; + } + + for(i=FRAG_ATTRIB_VAR0; i<FRAG_ATTRIB_MAX; i++) + { + unBit = 1 << i; + if(mesa_fp->Base.InputsRead & unBit) + { + j = i - FRAG_ATTRIB_VAR0; + pPsParam = PsVarying->Parameters + j; + + for(k=0; k<VsVarying->NumParameters; k++) + { + pVsParam = VsVarying->Parameters + k; + + if( strcmp(pPsParam->Name, pVsParam->Name) == 0) + { + pAsm->uiFP_AttributeMap[i] = pAsm->number_used_registers + k; + if(k > unMaxVarying) + { + unMaxVarying = k; + } + break; + } + } + } + } + + pAsm->number_used_registers += unMaxVarying + 1; + } +#endif + unBit = 1 << FRAG_ATTRIB_FACE; + if(mesa_fp->Base.InputsRead & unBit) + { + pAsm->uiFP_AttributeMap[FRAG_ATTRIB_FACE] = pAsm->number_used_registers++; + } + + unBit = 1 << FRAG_ATTRIB_PNTC; + if(mesa_fp->Base.InputsRead & unBit) + { + pAsm->uiFP_AttributeMap[FRAG_ATTRIB_PNTC] = pAsm->number_used_registers++; + } + + pAsm->uIIns = pAsm->number_used_registers; + +/* Map temporary registers (GPRs) */ + pAsm->starting_temp_register_number = pAsm->number_used_registers; + + if(mesa_fp->Base.NumNativeTemporaries >= mesa_fp->Base.NumTemporaries) + { + pAsm->number_used_registers += mesa_fp->Base.NumNativeTemporaries; + } + else + { + pAsm->number_used_registers += mesa_fp->Base.NumTemporaries; + } + +/* Output mapping */ + pAsm->number_of_exports = 0; + pAsm->number_of_colorandz_exports = 0; /* don't include stencil and mask out. */ + pAsm->starting_export_register_number = pAsm->number_used_registers; + unBit = 1 << FRAG_RESULT_COLOR; + if(mesa_fp->Base.OutputsWritten & unBit) + { + pAsm->uiFP_OutputMap[FRAG_RESULT_COLOR] = pAsm->number_used_registers++; + pAsm->number_of_exports++; + pAsm->number_of_colorandz_exports++; + } + unBit = 1 << FRAG_RESULT_DEPTH; + if(mesa_fp->Base.OutputsWritten & unBit) + { + pAsm->depth_export_register_number = pAsm->number_used_registers; + pAsm->uiFP_OutputMap[FRAG_RESULT_DEPTH] = pAsm->number_used_registers++; + pAsm->number_of_exports++; + pAsm->number_of_colorandz_exports++; + pAsm->pR700Shader->depthIsExported = 1; + } + + pAsm->pucOutMask = (unsigned char*) MALLOC(pAsm->number_of_exports); + for(ui=0; ui<pAsm->number_of_exports; ui++) + { + pAsm->pucOutMask[ui] = 0x0; + } + + pAsm->flag_reg_index = pAsm->number_used_registers++; + + pAsm->uFirstHelpReg = pAsm->number_used_registers; +} + +GLboolean evergreen_Find_Instruction_Dependencies_fp(struct evergreen_fragment_program *fp, + struct gl_fragment_program *mesa_fp) +{ + GLuint i, j; + GLint * puiTEMPwrites; + GLint * puiTEMPreads; + struct prog_instruction * pILInst; + InstDeps *pInstDeps; + struct prog_instruction * texcoord_DepInst; + GLint nDepInstID; + + puiTEMPwrites = (GLint*) MALLOC(sizeof(GLuint)*mesa_fp->Base.NumTemporaries); + puiTEMPreads = (GLint*) MALLOC(sizeof(GLuint)*mesa_fp->Base.NumTemporaries); + + for(i=0; i<mesa_fp->Base.NumTemporaries; i++) + { + puiTEMPwrites[i] = -1; + puiTEMPreads[i] = -1; + } + + pInstDeps = (InstDeps*)MALLOC(sizeof(InstDeps)*mesa_fp->Base.NumInstructions); + + for(i=0; i<mesa_fp->Base.NumInstructions; i++) + { + pInstDeps[i].nDstDep = -1; + pILInst = &(mesa_fp->Base.Instructions[i]); + + //Dst + if(pILInst->DstReg.File == PROGRAM_TEMPORARY) + { + //Set lastwrite for the temp + puiTEMPwrites[pILInst->DstReg.Index] = i; + } + + //Src + for(j=0; j<3; j++) + { + if(pILInst->SrcReg[j].File == PROGRAM_TEMPORARY) + { + //Set dep. + pInstDeps[i].nSrcDeps[j] = puiTEMPwrites[pILInst->SrcReg[j].Index]; + //Set first read + if(puiTEMPreads[pILInst->SrcReg[j].Index] < 0 ) + { + puiTEMPreads[pILInst->SrcReg[j].Index] = i; + } + } + else + { + pInstDeps[i].nSrcDeps[j] = -1; + } + } + } + + fp->r700AsmCode.pInstDeps = pInstDeps; + + //Find dep for tex inst + for(i=0; i<mesa_fp->Base.NumInstructions; i++) + { + pILInst = &(mesa_fp->Base.Instructions[i]); + + if(GL_TRUE == IsTex(pILInst->Opcode)) + { //src0 is the tex coord register, src1 is texunit, src2 is textype + nDepInstID = pInstDeps[i].nSrcDeps[0]; + if(nDepInstID >= 0) + { + texcoord_DepInst = &(mesa_fp->Base.Instructions[nDepInstID]); + if(GL_TRUE == IsAlu(texcoord_DepInst->Opcode) ) + { + pInstDeps[nDepInstID].nDstDep = i; + pInstDeps[i].nDstDep = i; + } + else if(GL_TRUE == IsTex(texcoord_DepInst->Opcode) ) + { + pInstDeps[i].nDstDep = i; + } + else + { //... other deps? + } + } + // make sure that we dont overwrite src used earlier + nDepInstID = puiTEMPreads[pILInst->DstReg.Index]; + if(nDepInstID < i) + { + pInstDeps[i].nDstDep = puiTEMPreads[pILInst->DstReg.Index]; + texcoord_DepInst = &(mesa_fp->Base.Instructions[nDepInstID]); + if(GL_TRUE == IsAlu(texcoord_DepInst->Opcode) ) + { + pInstDeps[nDepInstID].nDstDep = i; + } + + } + + } + } + + FREE(puiTEMPwrites); + FREE(puiTEMPreads); + + return GL_TRUE; +} + +GLboolean evergreenTranslateFragmentShader(struct evergreen_fragment_program *fp, + struct gl_fragment_program *mesa_fp, + GLcontext *ctx) +{ + GLuint number_of_colors_exported; + GLboolean z_enabled = GL_FALSE; + GLuint unBit, shadow_unit; + int i; + struct prog_instruction *inst; + gl_state_index shadow_ambient[STATE_LENGTH] + = { STATE_INTERNAL, STATE_SHADOW_AMBIENT, 0, 0, 0}; + + //Init_Program + Init_r700_AssemblerBase( SPT_FP, &(fp->r700AsmCode), &(fp->r700Shader) ); + + fp->constbo0 = NULL; + fp->r700AsmCode.bUseMemConstant = GL_TRUE; + fp->r700AsmCode.unAsic = 8; + + if(mesa_fp->Base.InputsRead & FRAG_BIT_WPOS) + { + evergreen_insert_wpos_code(ctx, mesa_fp); + } + + /* add/map consts for ARB_shadow_ambient */ + if(mesa_fp->Base.ShadowSamplers) + { + inst = mesa_fp->Base.Instructions; + for (i = 0; i < mesa_fp->Base.NumInstructions; i++) + { + if(inst->TexShadow == 1) + { + shadow_unit = inst->TexSrcUnit; + shadow_ambient[2] = shadow_unit; + fp->r700AsmCode.shadow_regs[shadow_unit] = + _mesa_add_state_reference(mesa_fp->Base.Parameters, shadow_ambient); + } + inst++; + } + } + + evergreen_Map_Fragment_Program(&(fp->r700AsmCode), mesa_fp, ctx); + + if( GL_FALSE == evergreen_Find_Instruction_Dependencies_fp(fp, mesa_fp) ) + { + return GL_FALSE; + } + + InitShaderProgram(&(fp->r700AsmCode)); + + for(i=0; i < MAX_SAMPLERS; i++) + { + fp->r700AsmCode.SamplerUnits[i] = fp->mesa_program.Base.SamplerUnits[i]; + } + + fp->r700AsmCode.unCurNumILInsts = mesa_fp->Base.NumInstructions; + + if( GL_FALSE == AssembleInstr(0, + 0, + mesa_fp->Base.NumInstructions, + &(mesa_fp->Base.Instructions[0]), + &(fp->r700AsmCode)) ) + { + return GL_FALSE; + } + + if(GL_FALSE == Process_Fragment_Exports(&(fp->r700AsmCode), mesa_fp->Base.OutputsWritten) ) + { + return GL_FALSE; + } + + if( GL_FALSE == RelocProgram(&(fp->r700AsmCode), &(mesa_fp->Base)) ) + { + return GL_FALSE; + } + + fp->r700Shader.nRegs = (fp->r700AsmCode.number_used_registers == 0) ? 0 + : (fp->r700AsmCode.number_used_registers - 1); + + fp->r700Shader.nParamExports = fp->r700AsmCode.number_of_exports; + + number_of_colors_exported = fp->r700AsmCode.number_of_colorandz_exports; + + unBit = 1 << FRAG_RESULT_DEPTH; + if(mesa_fp->Base.OutputsWritten & unBit) + { + z_enabled = GL_TRUE; + number_of_colors_exported--; + } + + /* illegal to set this to 0 */ + if(number_of_colors_exported || z_enabled) + { + fp->r700Shader.exportMode = number_of_colors_exported << 1 | z_enabled; + } + else + { + fp->r700Shader.exportMode = (1 << 1); + } + + fp->translated = GL_TRUE; + + return GL_TRUE; +} + +void evergreenSelectFragmentShader(GLcontext *ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + struct evergreen_fragment_program *fp = (struct evergreen_fragment_program *) + (ctx->FragmentProgram._Current); + if (context->radeon.radeonScreen->chip_family < CHIP_FAMILY_RV770) + { + fp->r700AsmCode.bR6xx = 1; + } + + if (GL_FALSE == fp->translated) + evergreenTranslateFragmentShader(fp, &(fp->mesa_program), ctx); +} + +void * evergreenGetActiveFpShaderBo(GLcontext * ctx) +{ + struct evergreen_fragment_program *fp = (struct evergreen_fragment_program *) + (ctx->FragmentProgram._Current); + + return fp->shaderbo; +} + +void * evergreenGetActiveFpShaderConstBo(GLcontext * ctx) +{ + struct evergreen_fragment_program *fp = (struct evergreen_fragment_program *) + (ctx->FragmentProgram._Current); + + return fp->constbo0; +} + +GLboolean evergreenSetupFragmentProgram(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct evergreen_fragment_program *fp = (struct evergreen_fragment_program *) + (ctx->FragmentProgram._Current); + r700_AssemblerBase *pAsm = &(fp->r700AsmCode); + struct gl_fragment_program *mesa_fp = &(fp->mesa_program); + unsigned int ui, i; + unsigned int unNumOfReg; + unsigned int unBit; + GLuint exportCount; + GLboolean point_sprite = GL_FALSE; + + if(GL_FALSE == fp->loaded) + { + if(fp->r700Shader.bNeedsAssembly == GL_TRUE) + { + Assemble( &(fp->r700Shader) ); + } + + r600EmitShader(ctx, + &(fp->shaderbo), + (GLvoid *)(fp->r700Shader.pProgram), + fp->r700Shader.uShaderBinaryDWORDSize, + "FS"); + + fp->loaded = GL_TRUE; + } + + /* TODO : enable this after MemUse fixed *= + (context->chipobj.MemUse)(context, fp->shadercode.buf->id); + */ + + EVERGREEN_STATECHANGE(context, sq); + + evergreen->SQ_PGM_RESOURCES_PS.u32All = 0; + SETbit(evergreen->SQ_PGM_RESOURCES_PS.u32All, PGM_RESOURCES__PRIME_CACHE_ON_DRAW_bit); + + evergreen->ps.SQ_ALU_CONST_CACHE_PS_0.u32All = 0; + evergreen->ps.SQ_PGM_START_PS.u32All = 0; + + EVERGREEN_STATECHANGE(context, spi); + + unNumOfReg = fp->r700Shader.nRegs + 1; + + ui = (evergreen->SPI_PS_IN_CONTROL_0.u32All & NUM_INTERP_mask) / (1 << NUM_INTERP_shift); + + /* PS uses fragment.position */ + if (mesa_fp->Base.InputsRead & (1 << FRAG_ATTRIB_WPOS)) + { + ui += 1; + SETfield(evergreen->SPI_PS_IN_CONTROL_0.u32All, ui, NUM_INTERP_shift, NUM_INTERP_mask); + SETfield(evergreen->SPI_PS_IN_CONTROL_0.u32All, CENTERS_ONLY, BARYC_SAMPLE_CNTL_shift, BARYC_SAMPLE_CNTL_mask); + SETbit(evergreen->SPI_PS_IN_CONTROL_0.u32All, POSITION_ENA_bit); + SETbit(evergreen->SPI_INPUT_Z.u32All, PROVIDE_Z_TO_SPI_bit); + } + else + { + CLEARbit(evergreen->SPI_PS_IN_CONTROL_0.u32All, POSITION_ENA_bit); + CLEARbit(evergreen->SPI_INPUT_Z.u32All, PROVIDE_Z_TO_SPI_bit); + } + + if (mesa_fp->Base.InputsRead & (1 << FRAG_ATTRIB_FACE)) + { + ui += 1; + SETfield(evergreen->SPI_PS_IN_CONTROL_0.u32All, ui, NUM_INTERP_shift, NUM_INTERP_mask); + SETbit(evergreen->SPI_PS_IN_CONTROL_1.u32All, FRONT_FACE_ENA_bit); + SETbit(evergreen->SPI_PS_IN_CONTROL_1.u32All, FRONT_FACE_ALL_BITS_bit); + SETfield(evergreen->SPI_PS_IN_CONTROL_1.u32All, pAsm->uiFP_AttributeMap[FRAG_ATTRIB_FACE], FRONT_FACE_ADDR_shift, FRONT_FACE_ADDR_mask); + } + else + { + CLEARbit(evergreen->SPI_PS_IN_CONTROL_1.u32All, FRONT_FACE_ENA_bit); + } + + /* see if we need any point_sprite replacements */ + for (i = VERT_RESULT_TEX0; i<= VERT_RESULT_TEX7; i++) + { + if(ctx->Point.CoordReplace[i - VERT_RESULT_TEX0] == GL_TRUE) + point_sprite = GL_TRUE; + } + + if ((mesa_fp->Base.InputsRead & (1 << FRAG_ATTRIB_PNTC)) || point_sprite) + { + /* for FRAG_ATTRIB_PNTC we need to increase num_interp */ + if(mesa_fp->Base.InputsRead & (1 << FRAG_ATTRIB_PNTC)) + { + ui++; + SETfield(evergreen->SPI_PS_IN_CONTROL_0.u32All, ui, NUM_INTERP_shift, NUM_INTERP_mask); + } + SETbit(evergreen->SPI_INTERP_CONTROL_0.u32All, PNT_SPRITE_ENA_bit); + SETfield(evergreen->SPI_INTERP_CONTROL_0.u32All, SPI_PNT_SPRITE_SEL_S, PNT_SPRITE_OVRD_X_shift, PNT_SPRITE_OVRD_X_mask); + SETfield(evergreen->SPI_INTERP_CONTROL_0.u32All, SPI_PNT_SPRITE_SEL_T, PNT_SPRITE_OVRD_Y_shift, PNT_SPRITE_OVRD_Y_mask); + SETfield(evergreen->SPI_INTERP_CONTROL_0.u32All, SPI_PNT_SPRITE_SEL_0, PNT_SPRITE_OVRD_Z_shift, PNT_SPRITE_OVRD_Z_mask); + SETfield(evergreen->SPI_INTERP_CONTROL_0.u32All, SPI_PNT_SPRITE_SEL_1, PNT_SPRITE_OVRD_W_shift, PNT_SPRITE_OVRD_W_mask); + if(ctx->Point.SpriteOrigin == GL_LOWER_LEFT) + SETbit(evergreen->SPI_INTERP_CONTROL_0.u32All, PNT_SPRITE_TOP_1_bit); + else + CLEARbit(evergreen->SPI_INTERP_CONTROL_0.u32All, PNT_SPRITE_TOP_1_bit); + } + else + { + CLEARbit(evergreen->SPI_INTERP_CONTROL_0.u32All, PNT_SPRITE_ENA_bit); + } + + + ui = (unNumOfReg < ui) ? ui : unNumOfReg; + + SETfield(evergreen->SQ_PGM_RESOURCES_PS.u32All, ui, NUM_GPRS_shift, NUM_GPRS_mask); + + CLEARbit(evergreen->SQ_PGM_RESOURCES_PS.u32All, UNCACHED_FIRST_INST_bit); + + if(fp->r700Shader.uStackSize) /* we don't use branch for now, it should be zero. */ + { + SETfield(evergreen->SQ_PGM_RESOURCES_PS.u32All, fp->r700Shader.uStackSize, + STACK_SIZE_shift, STACK_SIZE_mask); + } + + SETfield(evergreen->SQ_PGM_EXPORTS_PS.u32All, fp->r700Shader.exportMode, + EXPORT_MODE_shift, EXPORT_MODE_mask); + + // emit ps input map + struct evergreen_vertex_program_cont *vpc = + (struct evergreen_vertex_program_cont *)ctx->VertexProgram._Current; + GLbitfield OutputsWritten = vpc->mesa_program.Base.OutputsWritten; + + for(ui = 0; ui < EVERGREEN_MAX_SHADER_EXPORTS; ui++) + evergreen->SPI_PS_INPUT_CNTL[ui].u32All = 0; + + unBit = 1 << FRAG_ATTRIB_WPOS; + if(mesa_fp->Base.InputsRead & unBit) + { + ui = pAsm->uiFP_AttributeMap[FRAG_ATTRIB_WPOS]; + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, SEL_CENTROID_bit); + SETfield(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, ui, + SEMANTIC_shift, SEMANTIC_mask); + if (evergreen->SPI_INTERP_CONTROL_0.u32All & FLAT_SHADE_ENA_bit) + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + else + CLEARbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + } + + unBit = 1 << VERT_RESULT_COL0; + if(OutputsWritten & unBit) + { + ui = pAsm->uiFP_AttributeMap[FRAG_ATTRIB_COL0]; + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, SEL_CENTROID_bit); + SETfield(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, ui, + SEMANTIC_shift, SEMANTIC_mask); + if (evergreen->SPI_INTERP_CONTROL_0.u32All & FLAT_SHADE_ENA_bit) + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + else + CLEARbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + } + + unBit = 1 << VERT_RESULT_COL1; + if(OutputsWritten & unBit) + { + ui = pAsm->uiFP_AttributeMap[FRAG_ATTRIB_COL1]; + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, SEL_CENTROID_bit); + SETfield(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, ui, + SEMANTIC_shift, SEMANTIC_mask); + if (evergreen->SPI_INTERP_CONTROL_0.u32All & FLAT_SHADE_ENA_bit) + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + else + CLEARbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + } + + unBit = 1 << VERT_RESULT_FOGC; + if(OutputsWritten & unBit) + { + ui = pAsm->uiFP_AttributeMap[FRAG_ATTRIB_FOGC]; + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, SEL_CENTROID_bit); + SETfield(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, ui, + SEMANTIC_shift, SEMANTIC_mask); + if (evergreen->SPI_INTERP_CONTROL_0.u32All & FLAT_SHADE_ENA_bit) + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + else + CLEARbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + } + + for(i=0; i<8; i++) + { + unBit = 1 << (VERT_RESULT_TEX0 + i); + if(OutputsWritten & unBit) + { + ui = pAsm->uiFP_AttributeMap[FRAG_ATTRIB_TEX0 + i]; + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, SEL_CENTROID_bit); + SETfield(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, ui, + SEMANTIC_shift, SEMANTIC_mask); + CLEARbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + /* ARB_point_sprite */ + if(ctx->Point.CoordReplace[i] == GL_TRUE) + { + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, PT_SPRITE_TEX_bit); + } + } + } + + unBit = 1 << FRAG_ATTRIB_FACE; + if(mesa_fp->Base.InputsRead & unBit) + { + ui = pAsm->uiFP_AttributeMap[FRAG_ATTRIB_FACE]; + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, SEL_CENTROID_bit); + SETfield(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, ui, + SEMANTIC_shift, SEMANTIC_mask); + if (evergreen->SPI_INTERP_CONTROL_0.u32All & FLAT_SHADE_ENA_bit) + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + else + CLEARbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + } + unBit = 1 << FRAG_ATTRIB_PNTC; + if(mesa_fp->Base.InputsRead & unBit) + { + ui = pAsm->uiFP_AttributeMap[FRAG_ATTRIB_PNTC]; + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, SEL_CENTROID_bit); + SETfield(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, ui, + SEMANTIC_shift, SEMANTIC_mask); + if (evergreen->SPI_INTERP_CONTROL_0.u32All & FLAT_SHADE_ENA_bit) + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + else + CLEARbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, PT_SPRITE_TEX_bit); + } + + + + + for(i=VERT_RESULT_VAR0; i<VERT_RESULT_MAX; i++) + { + unBit = 1 << i; + if(OutputsWritten & unBit) + { + ui = pAsm->uiFP_AttributeMap[i-VERT_RESULT_VAR0+FRAG_ATTRIB_VAR0]; + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, SEL_CENTROID_bit); + SETfield(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, ui, + SEMANTIC_shift, SEMANTIC_mask); + if (evergreen->SPI_INTERP_CONTROL_0.u32All & FLAT_SHADE_ENA_bit) + SETbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + else + CLEARbit(evergreen->SPI_PS_INPUT_CNTL[ui].u32All, FLAT_SHADE_bit); + } + } + + exportCount = (evergreen->SQ_PGM_EXPORTS_PS.u32All & EXPORT_MODE_mask) / (1 << EXPORT_MODE_shift); + + return GL_TRUE; +} + +GLboolean evergreenSetupFPconstants(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct evergreen_fragment_program *fp = (struct evergreen_fragment_program *) + (ctx->FragmentProgram._Current); + r700_AssemblerBase *pAsm = &(fp->r700AsmCode); + + struct gl_program_parameter_list *paramList; + unsigned int unNumParamData; + unsigned int ui; + + /* sent out shader constants. */ + paramList = fp->mesa_program.Base.Parameters; + + if(NULL != paramList) + { + _mesa_load_state_parameters(ctx, paramList); + + if (paramList->NumParameters > EVERGREEN_MAX_DX9_CONSTS) + return GL_FALSE; + + EVERGREEN_STATECHANGE(context, sq); + + evergreen->ps.num_consts = paramList->NumParameters; + + unNumParamData = paramList->NumParameters; + + for(ui=0; ui<unNumParamData; ui++) { + evergreen->ps.consts[ui][0].f32All = paramList->ParameterValues[ui][0]; + evergreen->ps.consts[ui][1].f32All = paramList->ParameterValues[ui][1]; + evergreen->ps.consts[ui][2].f32All = paramList->ParameterValues[ui][2]; + evergreen->ps.consts[ui][3].f32All = paramList->ParameterValues[ui][3]; + } + + /* Load fp constants to gpu */ + if(unNumParamData > 0) + { + radeonAllocDmaRegion(&context->radeon, + &context->fp_Constbo, + &context->fp_bo_offset, + 256, + 256); + r600EmitShaderConsts(ctx, + context->fp_Constbo, + context->fp_bo_offset, + (GLvoid *)&(evergreen->ps.consts[0][0]), + unNumParamData * 4 * 4); + } + } else + evergreen->ps.num_consts = 0; + + COMPILED_SUB * pCompiledSub; + GLuint uj; + GLuint unConstOffset = evergreen->ps.num_consts; + for(ui=0; ui<pAsm->unNumPresub; ui++) + { + pCompiledSub = pAsm->presubs[ui].pCompiledSub; + + evergreen->ps.num_consts += pCompiledSub->NumParameters; + + for(uj=0; uj<pCompiledSub->NumParameters; uj++) + { + evergreen->ps.consts[uj + unConstOffset][0].f32All = pCompiledSub->ParameterValues[uj][0]; + evergreen->ps.consts[uj + unConstOffset][1].f32All = pCompiledSub->ParameterValues[uj][1]; + evergreen->ps.consts[uj + unConstOffset][2].f32All = pCompiledSub->ParameterValues[uj][2]; + evergreen->ps.consts[uj + unConstOffset][3].f32All = pCompiledSub->ParameterValues[uj][3]; + } + unConstOffset += pCompiledSub->NumParameters; + } +}
\ No newline at end of file diff --git a/src/mesa/drivers/dri/r600/evergreen_fragprog.h b/src/mesa/drivers/dri/r600/evergreen_fragprog.h new file mode 100644 index 0000000000..0e200bf383 --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_fragprog.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008-2009 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#ifndef _EVERGREEN_FRAGPROG_H_ +#define _EVERGREEN_FRAGPROG_H_ + +#include "r600_context.h" +#include "r700_assembler.h" + +struct evergreen_fragment_program +{ + struct gl_fragment_program mesa_program; + + r700_AssemblerBase r700AsmCode; + R700_Shader r700Shader; + + GLboolean translated; + GLboolean loaded; + GLboolean error; + + void * shaderbo; + + GLuint k0used; + void * constbo0; + + GLboolean WritesDepth; + GLuint optimization; +}; + +/* Internal */ +void evergreen_insert_wpos_code(GLcontext *ctx, struct gl_fragment_program *fprog); + +void evergreen_Map_Fragment_Program(r700_AssemblerBase *pAsm, + struct gl_fragment_program *mesa_fp, + GLcontext *ctx); +GLboolean evergreen_Find_Instruction_Dependencies_fp(struct evergreen_fragment_program *fp, + struct gl_fragment_program *mesa_fp); + +GLboolean evergreenTranslateFragmentShader(struct evergreen_fragment_program *fp, + struct gl_fragment_program *mesa_vp, + GLcontext *ctx); + +/* Interface */ +extern void evergreenSelectFragmentShader(GLcontext *ctx); + +extern GLboolean evergreenSetupFragmentProgram(GLcontext * ctx); + +extern GLboolean evergreenSetupFPconstants(GLcontext * ctx); + +extern void * evergreenGetActiveFpShaderBo(GLcontext * ctx); + +extern void * evergreenGetActiveFpShaderConstBo(GLcontext * ctx); + +#endif /*_EVERGREEN_FRAGPROG_H_*/ diff --git a/src/mesa/slang/slang_log.h b/src/mesa/drivers/dri/r600/evergreen_ioctl.c index 544a26654e..5c1270790d 100644 --- a/src/mesa/slang/slang_log.h +++ b/src/mesa/drivers/dri/r600/evergreen_ioctl.c @@ -1,8 +1,5 @@ /* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008-2009 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -17,43 +14,40 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ -#ifndef SLANG_LOG_H -#define SLANG_LOG_H - +#include <sched.h> +#include <errno.h> #include "main/glheader.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/context.h" +#include "main/simple_list.h" -typedef struct slang_info_log_ -{ - char *text; - GLboolean dont_free_text; - GLboolean error_flag; -} slang_info_log; - +#include "radeon_common.h" +#include "r600_context.h" -extern void -slang_info_log_construct(slang_info_log *); +#include "evergreen_ioctl.h" -extern void -slang_info_log_destruct(slang_info_log *); +#include "r700_clear.h" -extern int -slang_info_log_print(slang_info_log *, const char *, ...); +void evergreenClear(GLcontext * ctx, GLbitfield mask) +{ + r700Clear(ctx, mask); +} -extern int -slang_info_log_error(slang_info_log *, const char *, ...); - -extern int -slang_info_log_warning(slang_info_log *, const char *, ...); - -extern void -slang_info_log_memory(slang_info_log *); - - -#endif /* SLANG_LOG_H */ +void evergreenInitIoctlFuncs(struct dd_function_table *functions) +{ + functions->Clear = evergreenClear; + functions->Finish = radeonFinish; + functions->Flush = radeonFlush; +} diff --git a/src/mesa/slang/slang_mem.h b/src/mesa/drivers/dri/r600/evergreen_ioctl.h index b5bfae2479..3c663a7083 100644 --- a/src/mesa/slang/slang_mem.h +++ b/src/mesa/drivers/dri/r600/evergreen_ioctl.h @@ -1,8 +1,5 @@ /* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -17,39 +14,23 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ -#ifndef SLANG_MEM_H -#define SLANG_MEM_H - - -#include "main/imports.h" - - -typedef struct slang_mempool_ slang_mempool; - - -extern slang_mempool * -_slang_new_mempool(GLuint initialSize); - -extern void -_slang_delete_mempool(slang_mempool *pool); - -extern void * -_slang_alloc(GLuint bytes); - -extern void * -_slang_realloc(void *oldBuffer, GLuint oldSize, GLuint newSize); - -extern char * -_slang_strdup(const char *s); +#ifndef _EVERGREEN_IOCTL_H_ +#define _EVERGREEN_IOCTL_H_ -extern void -_slang_free(void *addr); +#include "r600_context.h" +#include "radeon_drm.h" +extern void evergreenClear(GLcontext * ctx, GLbitfield mask); +extern void evergreenInitIoctlFuncs(struct dd_function_table *functions); -#endif +#endif /* _EVERGREEN_IOCTL_H_ */ diff --git a/src/mesa/drivers/dri/r600/evergreen_off.h b/src/mesa/drivers/dri/r600/evergreen_off.h new file mode 100644 index 0000000000..8c250699ec --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_off.h @@ -0,0 +1,881 @@ +/* + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#ifndef _EVERGREEN_OFF_H_ +#define _EVERGREEN_OFF_H_ + +enum +{ +/* Registers from PA block: */ + EG_PA_SC_SCREEN_SCISSOR_TL = 0x28030, // DIFF + EG_PA_SC_SCREEN_SCISSOR_BR = 0x28034, // DIFF + EG_PA_SC_WINDOW_OFFSET = 0x28200, // DIFF + EG_PA_SC_WINDOW_SCISSOR_TL = 0x28204, // DIFF + EG_PA_SC_WINDOW_SCISSOR_BR = 0x28208, // DIFF + EG_PA_SC_CLIPRECT_RULE = 0x2820C, // SAME + EG_PA_SC_CLIPRECT_0_TL = 0x28210, // DIFF + EG_PA_SC_CLIPRECT_0_BR = 0x28214, // DIFF + EG_PA_SC_CLIPRECT_1_TL = 0x28218, // DIFF + EG_PA_SC_CLIPRECT_1_BR = 0x2821C, // DIFF + EG_PA_SC_CLIPRECT_2_TL = 0x28220, // DIFF + EG_PA_SC_CLIPRECT_2_BR = 0x28224, // DIFF + EG_PA_SC_CLIPRECT_3_TL = 0x28228, // DIFF + EG_PA_SC_CLIPRECT_3_BR = 0x2822C, // DIFF + EG_PA_SC_EDGERULE = 0x28230, // SAME + EG_PA_SU_HARDWARE_SCREEN_OFFSET = 0x28234, // + EG_PA_SC_GENERIC_SCISSOR_TL = 0x28240, // DIFF + EG_PA_SC_GENERIC_SCISSOR_BR = 0x28244, // DIFF + EG_PA_SC_VPORT_SCISSOR_0_TL = 0x28250, // DIFF + EG_PA_SC_VPORT_SCISSOR_0_BR = 0x28254, // DIFF + EG_PA_SC_VPORT_SCISSOR_1_TL = 0x28258, // DIFF + EG_PA_SC_VPORT_SCISSOR_1_BR = 0x2825C, // DIFF + EG_PA_SC_VPORT_SCISSOR_2_TL = 0x28260, // DIFF + EG_PA_SC_VPORT_SCISSOR_2_BR = 0x28264, // DIFF + EG_PA_SC_VPORT_SCISSOR_3_TL = 0x28268, // DIFF + EG_PA_SC_VPORT_SCISSOR_3_BR = 0x2826C, // DIFF + EG_PA_SC_VPORT_SCISSOR_4_TL = 0x28270, // DIFF + EG_PA_SC_VPORT_SCISSOR_4_BR = 0x28274, // DIFF + EG_PA_SC_VPORT_SCISSOR_5_TL = 0x28278, // DIFF + EG_PA_SC_VPORT_SCISSOR_5_BR = 0x2827C, // DIFF + EG_PA_SC_VPORT_SCISSOR_6_TL = 0x28280, // DIFF + EG_PA_SC_VPORT_SCISSOR_6_BR = 0x28284, // DIFF + EG_PA_SC_VPORT_SCISSOR_7_TL = 0x28288, // DIFF + EG_PA_SC_VPORT_SCISSOR_7_BR = 0x2828C, // DIFF + EG_PA_SC_VPORT_SCISSOR_8_TL = 0x28290, // DIFF + EG_PA_SC_VPORT_SCISSOR_8_BR = 0x28294, // DIFF + EG_PA_SC_VPORT_SCISSOR_9_TL = 0x28298, // DIFF + EG_PA_SC_VPORT_SCISSOR_9_BR = 0x2829C, // DIFF + EG_PA_SC_VPORT_SCISSOR_10_TL = 0x282A0, // DIFF + EG_PA_SC_VPORT_SCISSOR_10_BR = 0x282A4, // DIFF + EG_PA_SC_VPORT_SCISSOR_11_TL = 0x282A8, // DIFF + EG_PA_SC_VPORT_SCISSOR_11_BR = 0x282AC, // DIFF + EG_PA_SC_VPORT_SCISSOR_12_TL = 0x282B0, // DIFF + EG_PA_SC_VPORT_SCISSOR_12_BR = 0x282B4, // DIFF + EG_PA_SC_VPORT_SCISSOR_13_TL = 0x282B8, // DIFF + EG_PA_SC_VPORT_SCISSOR_13_BR = 0x282BC, // DIFF + EG_PA_SC_VPORT_SCISSOR_14_TL = 0x282C0, // DIFF + EG_PA_SC_VPORT_SCISSOR_14_BR = 0x282C4, // DIFF + EG_PA_SC_VPORT_SCISSOR_15_TL = 0x282C8, // DIFF + EG_PA_SC_VPORT_SCISSOR_15_BR = 0x282CC, // DIFF + EG_PA_SC_VPORT_ZMIN_0 = 0x282D0, // SAME + EG_PA_SC_VPORT_ZMAX_0 = 0x282D4, // SAME + EG_PA_SC_VPORT_ZMIN_1 = 0x282D8, // SAME + EG_PA_SC_VPORT_ZMAX_1 = 0x282DC, // SAME + EG_PA_SC_VPORT_ZMIN_2 = 0x282E0, // SAME + EG_PA_SC_VPORT_ZMAX_2 = 0x282E4, // SAME + EG_PA_SC_VPORT_ZMIN_3 = 0x282E8, // SAME + EG_PA_SC_VPORT_ZMAX_3 = 0x282EC, // SAME + EG_PA_SC_VPORT_ZMIN_4 = 0x282F0, // SAME + EG_PA_SC_VPORT_ZMAX_4 = 0x282F4, // SAME + EG_PA_SC_VPORT_ZMIN_5 = 0x282F8, // SAME + EG_PA_SC_VPORT_ZMAX_5 = 0x282FC, // SAME + EG_PA_SC_VPORT_ZMIN_6 = 0x28300, // SAME + EG_PA_SC_VPORT_ZMAX_6 = 0x28304, // SAME + EG_PA_SC_VPORT_ZMIN_7 = 0x28308, // SAME + EG_PA_SC_VPORT_ZMAX_7 = 0x2830C, // SAME + EG_PA_SC_VPORT_ZMIN_8 = 0x28310, // SAME + EG_PA_SC_VPORT_ZMAX_8 = 0x28314, // SAME + EG_PA_SC_VPORT_ZMIN_9 = 0x28318, // SAME + EG_PA_SC_VPORT_ZMAX_9 = 0x2831C, // SAME + EG_PA_SC_VPORT_ZMIN_10 = 0x28320, // SAME + EG_PA_SC_VPORT_ZMAX_10 = 0x28324, // SAME + EG_PA_SC_VPORT_ZMIN_11 = 0x28328, // SAME + EG_PA_SC_VPORT_ZMAX_11 = 0x2832C, // SAME + EG_PA_SC_VPORT_ZMIN_12 = 0x28330, // SAME + EG_PA_SC_VPORT_ZMAX_12 = 0x28334, // SAME + EG_PA_SC_VPORT_ZMIN_13 = 0x28338, // SAME + EG_PA_SC_VPORT_ZMAX_13 = 0x2833C, // SAME + EG_PA_SC_VPORT_ZMIN_14 = 0x28340, // SAME + EG_PA_SC_VPORT_ZMAX_14 = 0x28344, // SAME + EG_PA_SC_VPORT_ZMIN_15 = 0x28348, // SAME + EG_PA_SC_VPORT_ZMAX_15 = 0x2834C, // SAME + EG_PA_CL_VPORT_XSCALE = 0x2843C, // SAME + EG_PA_CL_VPORT_XOFFSET = 0x28440, // SAME + EG_PA_CL_VPORT_YSCALE = 0x28444, // SAME + EG_PA_CL_VPORT_YOFFSET = 0x28448, // SAME + EG_PA_CL_VPORT_ZSCALE = 0x2844C, // SAME + EG_PA_CL_VPORT_ZOFFSET = 0x28450, // SAME + EG_PA_CL_VPORT_XSCALE_1 = 0x28454, // SAME + EG_PA_CL_VPORT_XOFFSET_1 = 0x28458, // SAME + EG_PA_CL_VPORT_YSCALE_1 = 0x2845C, // SAME + EG_PA_CL_VPORT_YOFFSET_1 = 0x28460, // SAME + EG_PA_CL_VPORT_ZSCALE_1 = 0x28464, // SAME + EG_PA_CL_VPORT_ZOFFSET_1 = 0x28468, // SAME + EG_PA_CL_VPORT_XSCALE_2 = 0x2846C, // SAME + EG_PA_CL_VPORT_XOFFSET_2 = 0x28470, // SAME + EG_PA_CL_VPORT_YSCALE_2 = 0x28474, // SAME + EG_PA_CL_VPORT_YOFFSET_2 = 0x28478, // SAME + EG_PA_CL_VPORT_ZSCALE_2 = 0x2847C, // SAME + EG_PA_CL_VPORT_ZOFFSET_2 = 0x28480, // SAME + EG_PA_CL_VPORT_XSCALE_3 = 0x28484, // SAME + EG_PA_CL_VPORT_XOFFSET_3 = 0x28488, // SAME + EG_PA_CL_VPORT_YSCALE_3 = 0x2848C, // SAME + EG_PA_CL_VPORT_YOFFSET_3 = 0x28490, // SAME + EG_PA_CL_VPORT_ZSCALE_3 = 0x28494, // SAME + EG_PA_CL_VPORT_ZOFFSET_3 = 0x28498, // SAME + EG_PA_CL_VPORT_XSCALE_4 = 0x2849C, // SAME + EG_PA_CL_VPORT_XOFFSET_4 = 0x284A0, // SAME + EG_PA_CL_VPORT_YSCALE_4 = 0x284A4, // SAME + EG_PA_CL_VPORT_YOFFSET_4 = 0x284A8, // SAME + EG_PA_CL_VPORT_ZSCALE_4 = 0x284AC, // SAME + EG_PA_CL_VPORT_ZOFFSET_4 = 0x284B0, // SAME + EG_PA_CL_VPORT_XSCALE_5 = 0x284B4, // SAME + EG_PA_CL_VPORT_XOFFSET_5 = 0x284B8, // SAME + EG_PA_CL_VPORT_YSCALE_5 = 0x284BC, // SAME + EG_PA_CL_VPORT_YOFFSET_5 = 0x284C0, // SAME + EG_PA_CL_VPORT_ZSCALE_5 = 0x284C4, // SAME + EG_PA_CL_VPORT_ZOFFSET_5 = 0x284C8, // SAME + EG_PA_CL_VPORT_XSCALE_6 = 0x284CC, // SAME + EG_PA_CL_VPORT_XOFFSET_6 = 0x284D0, // SAME + EG_PA_CL_VPORT_YSCALE_6 = 0x284D4, // SAME + EG_PA_CL_VPORT_YOFFSET_6 = 0x284D8, // SAME + EG_PA_CL_VPORT_ZSCALE_6 = 0x284DC, // SAME + EG_PA_CL_VPORT_ZOFFSET_6 = 0x284E0, // SAME + EG_PA_CL_VPORT_XSCALE_7 = 0x284E4, // SAME + EG_PA_CL_VPORT_XOFFSET_7 = 0x284E8, // SAME + EG_PA_CL_VPORT_YSCALE_7 = 0x284EC, // SAME + EG_PA_CL_VPORT_YOFFSET_7 = 0x284F0, // SAME + EG_PA_CL_VPORT_ZSCALE_7 = 0x284F4, // SAME + EG_PA_CL_VPORT_ZOFFSET_7 = 0x284F8, // SAME + EG_PA_CL_VPORT_XSCALE_8 = 0x284FC, // SAME + EG_PA_CL_VPORT_XOFFSET_8 = 0x28500, // SAME + EG_PA_CL_VPORT_YSCALE_8 = 0x28504, // SAME + EG_PA_CL_VPORT_YOFFSET_8 = 0x28508, // SAME + EG_PA_CL_VPORT_ZSCALE_8 = 0x2850C, // SAME + EG_PA_CL_VPORT_ZOFFSET_8 = 0x28510, // SAME + EG_PA_CL_VPORT_XSCALE_9 = 0x28514, // SAME + EG_PA_CL_VPORT_XOFFSET_9 = 0x28518, // SAME + EG_PA_CL_VPORT_YSCALE_9 = 0x2851C, // SAME + EG_PA_CL_VPORT_YOFFSET_9 = 0x28520, // SAME + EG_PA_CL_VPORT_ZSCALE_9 = 0x28524, // SAME + EG_PA_CL_VPORT_ZOFFSET_9 = 0x28528, // SAME + EG_PA_CL_VPORT_XSCALE_10 = 0x2852C, // SAME + EG_PA_CL_VPORT_XOFFSET_10 = 0x28530, // SAME + EG_PA_CL_VPORT_YSCALE_10 = 0x28534, // SAME + EG_PA_CL_VPORT_YOFFSET_10 = 0x28538, // SAME + EG_PA_CL_VPORT_ZSCALE_10 = 0x2853C, // SAME + EG_PA_CL_VPORT_ZOFFSET_10 = 0x28540, // SAME + EG_PA_CL_VPORT_XSCALE_11 = 0x28544, // SAME + EG_PA_CL_VPORT_XOFFSET_11 = 0x28548, // SAME + EG_PA_CL_VPORT_YSCALE_11 = 0x2854C, // SAME + EG_PA_CL_VPORT_YOFFSET_11 = 0x28550, // SAME + EG_PA_CL_VPORT_ZSCALE_11 = 0x28554, // SAME + EG_PA_CL_VPORT_ZOFFSET_11 = 0x28558, // SAME + EG_PA_CL_VPORT_XSCALE_12 = 0x2855C, // SAME + EG_PA_CL_VPORT_XOFFSET_12 = 0x28560, // SAME + EG_PA_CL_VPORT_YSCALE_12 = 0x28564, // SAME + EG_PA_CL_VPORT_YOFFSET_12 = 0x28568, // SAME + EG_PA_CL_VPORT_ZSCALE_12 = 0x2856C, // SAME + EG_PA_CL_VPORT_ZOFFSET_12 = 0x28570, // SAME + EG_PA_CL_VPORT_XSCALE_13 = 0x28574, // SAME + EG_PA_CL_VPORT_XOFFSET_13 = 0x28578, // SAME + EG_PA_CL_VPORT_YSCALE_13 = 0x2857C, // SAME + EG_PA_CL_VPORT_YOFFSET_13 = 0x28580, // SAME + EG_PA_CL_VPORT_ZSCALE_13 = 0x28584, // SAME + EG_PA_CL_VPORT_ZOFFSET_13 = 0x28588, // SAME + EG_PA_CL_VPORT_XSCALE_14 = 0x2858C, // SAME + EG_PA_CL_VPORT_XOFFSET_14 = 0x28590, // SAME + EG_PA_CL_VPORT_YSCALE_14 = 0x28594, // SAME + EG_PA_CL_VPORT_YOFFSET_14 = 0x28598, // SAME + EG_PA_CL_VPORT_ZSCALE_14 = 0x2859C, // SAME + EG_PA_CL_VPORT_ZOFFSET_14 = 0x285A0, // SAME + EG_PA_CL_VPORT_XSCALE_15 = 0x285A4, // SAME + EG_PA_CL_VPORT_XOFFSET_15 = 0x285A8, // SAME + EG_PA_CL_VPORT_YSCALE_15 = 0x285AC, // SAME + EG_PA_CL_VPORT_YOFFSET_15 = 0x285B0, // SAME + EG_PA_CL_VPORT_ZSCALE_15 = 0x285B4, // SAME + EG_PA_CL_VPORT_ZOFFSET_15 = 0x285B8, // SAME + EG_PA_CL_UCP_0_X = 0x285BC, // SAME 0x28E20 + EG_PA_CL_UCP_0_Y = 0x285C0, // SAME 0x28E24 + EG_PA_CL_UCP_0_Z = 0x285C4, // SAME 0x28E28 + EG_PA_CL_UCP_0_W = 0x285C8, // SAME 0x28E2C + EG_PA_CL_UCP_1_X = 0x285CC, // SAME 0x28E30 + EG_PA_CL_UCP_1_Y = 0x285D0, // SAME 0x28E34 + EG_PA_CL_UCP_1_Z = 0x285D4, // SAME 0x28E38 + EG_PA_CL_UCP_1_W = 0x285D8, // SAME 0x28E3C + EG_PA_CL_UCP_2_X = 0x285DC, // SAME 0x28E40 + EG_PA_CL_UCP_2_Y = 0x285E0, // SAME 0x28E44 + EG_PA_CL_UCP_2_Z = 0x285E4, // SAME 0x28E48 + EG_PA_CL_UCP_2_W = 0x285E8, // SAME 0x28E4C + EG_PA_CL_UCP_3_X = 0x285EC, // SAME 0x28E50 + EG_PA_CL_UCP_3_Y = 0x285F0, // SAME 0x28E54 + EG_PA_CL_UCP_3_Z = 0x285F4, // SAME 0x28E58 + EG_PA_CL_UCP_3_W = 0x285F8, // SAME 0x28E5C + EG_PA_CL_UCP_4_X = 0x285FC, // SAME 0x28E60 + EG_PA_CL_UCP_4_Y = 0x28600, // SAME 0x28E64 + EG_PA_CL_UCP_4_Z = 0x28604, // SAME 0x28E68 + EG_PA_CL_UCP_4_W = 0x28608, // SAME 0x28E6C + EG_PA_CL_UCP_5_X = 0x2860C, // SAME 0x28E70 + EG_PA_CL_UCP_5_Y = 0x28610, // SAME 0x28E74 + EG_PA_CL_UCP_5_Z = 0x28614, // SAME 0x28E78 + EG_PA_CL_UCP_5_W = 0x28618, // SAME 0x28E7C + EG_PA_CL_POINT_X_RAD = 0x287D4, // SAME 0x28E10 + EG_PA_CL_POINT_Y_RAD = 0x287D8, // SAME 0x28E14 + EG_PA_CL_POINT_SIZE = 0x287DC, // SAME 0x28E18 + EG_PA_CL_POINT_CULL_RAD = 0x287E0, // SAME 0x28E1C + EG_PA_CL_CLIP_CNTL = 0x28810, // SAME + EG_PA_SU_SC_MODE_CNTL = 0x28814, // SAME + EG_PA_CL_VTE_CNTL = 0x28818, // SAME + EG_PA_CL_VS_OUT_CNTL = 0x2881C, // SAME + EG_PA_CL_NANINF_CNTL = 0x28820, // SAME + EG_PA_SU_LINE_STIPPLE_CNTL = 0x28824, // + EG_PA_SU_LINE_STIPPLE_SCALE = 0x28828, // + EG_PA_SU_PRIM_FILTER_CNTL = 0x2882C, // + EG_PA_SU_POINT_SIZE = 0x28A00, // SAME + EG_PA_SU_POINT_MINMAX = 0x28A04, // SAME + EG_PA_SU_LINE_CNTL = 0x28A08, // SAME + EG_PA_SC_LINE_STIPPLE = 0x28A0C, // SAME + EG_PA_SC_MODE_CNTL_0 = 0x28A48, // + EG_PA_SC_MODE_CNTL_1 = 0x28A4C, // + EG_PA_SU_POLY_OFFSET_DB_FMT_CNTL = 0x28B78, // SAME 0x28DF8 + EG_PA_SU_POLY_OFFSET_CLAMP = 0x28B7C, // SAME 0x28DFC + EG_PA_SU_POLY_OFFSET_FRONT_SCALE = 0x28B80, // SAME 0x28E00 + EG_PA_SU_POLY_OFFSET_FRONT_OFFSET = 0x28B84, // SAME 0x28E04 + EG_PA_SU_POLY_OFFSET_BACK_SCALE = 0x28B88, // SAME 0x28E08 + EG_PA_SU_POLY_OFFSET_BACK_OFFSET = 0x28B8C, // SAME 0x28E0C + EG_PA_SC_LINE_CNTL = 0x28C00, // DIFF + EG_PA_SC_AA_CONFIG = 0x28C04, // SAME + EG_PA_SU_VTX_CNTL = 0x28C08, // SAME + EG_PA_CL_GB_VERT_CLIP_ADJ = 0x28C0C, // SAME + EG_PA_CL_GB_VERT_DISC_ADJ = 0x28C10, // SAME + EG_PA_CL_GB_HORZ_CLIP_ADJ = 0x28C14, // SAME + EG_PA_CL_GB_HORZ_DISC_ADJ = 0x28C18, // SAME + EG_PA_SC_AA_SAMPLE_LOCS_0 = 0x28C1C, // + EG_PA_SC_AA_SAMPLE_LOCS_1 = 0x28C20, // + EG_PA_SC_AA_SAMPLE_LOCS_2 = 0x28C24, // + EG_PA_SC_AA_SAMPLE_LOCS_3 = 0x28C28, // + EG_PA_SC_AA_SAMPLE_LOCS_4 = 0x28C2C, // + EG_PA_SC_AA_SAMPLE_LOCS_5 = 0x28C30, // + EG_PA_SC_AA_SAMPLE_LOCS_6 = 0x28C34, // + EG_PA_SC_AA_SAMPLE_LOCS_7 = 0x28C38, // + EG_PA_SC_AA_MASK = 0x28C3C, // SAME 0x28C48 + +/* Registers from VGT block: */ + EG_VGT_INDEX_TYPE = 0x895C, //? config space + EG_VGT_PRIMITIVE_TYPE = 0x8958, //? config space + + EG_VGT_MAX_VTX_INDX = 0x28400, // SAME + EG_VGT_MIN_VTX_INDX = 0x28404, // SAME + EG_VGT_INDX_OFFSET = 0x28408, // SAME + EG_VGT_MULTI_PRIM_IB_RESET_INDX = 0x2840C, // SAME + EG_CS_COPY_STATE = 0x287CC, // + EG_GFX_COPY_STATE = 0x287D0, // SAME + EG_VGT_DMA_BASE_HI = 0x287E4, // SAME + EG_VGT_DMA_BASE = 0x287E8, // SAME + EG_VGT_DRAW_INITIATOR = 0x287F0, // SAME + EG_VGT_IMMED_DATA = 0x287F4, // SAME + EG_VGT_EVENT_ADDRESS_REG = 0x287F8, // SAME + EG_VGT_OUTPUT_PATH_CNTL = 0x28A10, // DIFF + EG_VGT_HOS_CNTL = 0x28A14, // SAME + EG_VGT_HOS_MAX_TESS_LEVEL = 0x28A18, // SAME + EG_VGT_HOS_MIN_TESS_LEVEL = 0x28A1C, // SAME + EG_VGT_HOS_REUSE_DEPTH = 0x28A20, // SAME + EG_VGT_GROUP_PRIM_TYPE = 0x28A24, // SAME + EG_VGT_GROUP_FIRST_DECR = 0x28A28, // SAME + EG_VGT_GROUP_DECR = 0x28A2C, // SAME + EG_VGT_GROUP_VECT_0_CNTL = 0x28A30, // SAME + EG_VGT_GROUP_VECT_1_CNTL = 0x28A34, // SAME + EG_VGT_GROUP_VECT_0_FMT_CNTL = 0x28A38, // SAME + EG_VGT_GROUP_VECT_1_FMT_CNTL = 0x28A3C, // SAME + EG_VGT_GS_MODE = 0x28A40, // DIFF + EG_VGT_ENHANCE = 0x28A50, // DIFF + EG_VGT_GS_PER_ES = 0x28A54, // DIFF 0x88C8 + EG_VGT_ES_PER_GS = 0x28A58, // DIFF 0x88CC + EG_VGT_GS_PER_VS = 0x28A5C, // SAME 0x88E8 + EG_VGT_GS_OUT_PRIM_TYPE = 0x28A6C, // SAME + EG_VGT_DMA_SIZE = 0x28A74, // SAME + EG_VGT_DMA_MAX_SIZE = 0x28A78, // SAME + EG_VGT_DMA_INDEX_TYPE = 0x28A7C, // SAME + EG_VGT_PRIMITIVEID_EN = 0x28A84, // SAME + EG_VGT_DMA_NUM_INSTANCES = 0x28A88, // SAME + EG_VGT_EVENT_INITIATOR = 0x28A90, // SAME + EG_VGT_MULTI_PRIM_IB_RESET_EN = 0x28A94, // SAME + EG_VGT_INSTANCE_STEP_RATE_0 = 0x28AA0, // SAME + EG_VGT_INSTANCE_STEP_RATE_1 = 0x28AA4, // SAME + EG_VGT_REUSE_OFF = 0x28AB4, // SAME + EG_VGT_VTX_CNT_EN = 0x28AB8, // SAME + EG_VGT_STRMOUT_BUFFER_SIZE_0 = 0x28AD0, // SAME + EG_VGT_STRMOUT_VTX_STRIDE_0 = 0x28AD4, // SAME + EG_VGT_STRMOUT_BUFFER_BASE_0 = 0x28AD8, // SAME + EG_VGT_STRMOUT_BUFFER_OFFSET_0 = 0x28ADC, // SAME + EG_VGT_STRMOUT_BUFFER_SIZE_1 = 0x28AE0, // SAME + EG_VGT_STRMOUT_VTX_STRIDE_1 = 0x28AE4, // SAME + EG_VGT_STRMOUT_BUFFER_BASE_1 = 0x28AE8, // SAME + EG_VGT_STRMOUT_BUFFER_OFFSET_1 = 0x28AEC, // SAME + EG_VGT_STRMOUT_BUFFER_SIZE_2 = 0x28AF0, // SAME + EG_VGT_STRMOUT_VTX_STRIDE_2 = 0x28AF4, // SAME + EG_VGT_STRMOUT_BUFFER_BASE_2 = 0x28AF8, // SAME + EG_VGT_STRMOUT_BUFFER_OFFSET_2 = 0x28AFC, // SAME + EG_VGT_STRMOUT_BUFFER_SIZE_3 = 0x28B00, // SAME + EG_VGT_STRMOUT_VTX_STRIDE_3 = 0x28B04, // SAME + EG_VGT_STRMOUT_BUFFER_BASE_3 = 0x28B08, // SAME + EG_VGT_STRMOUT_BUFFER_OFFSET_3 = 0x28B0C, // SAME + EG_VGT_STRMOUT_BASE_OFFSET_0 = 0x28B10, // SAME + EG_VGT_STRMOUT_BASE_OFFSET_1 = 0x28B14, // SAME + EG_VGT_STRMOUT_BASE_OFFSET_2 = 0x28B18, // SAME + EG_VGT_STRMOUT_BASE_OFFSET_3 = 0x28B1C, // SAME + EG_VGT_STRMOUT_DRAW_OPAQUE_OFFSET = 0x28B28, // SAME + EG_VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE = 0x28B2C, // SAME + EG_VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE = 0x28B30, // DIFF + EG_VGT_GS_MAX_VERT_OUT = 0x28B38, // SAME + EG_VGT_STRMOUT_BASE_OFFSET_HI_0 = 0x28B44, // SAME + EG_VGT_STRMOUT_BASE_OFFSET_HI_1 = 0x28B48, // SAME + EG_VGT_STRMOUT_BASE_OFFSET_HI_2 = 0x28B4C, // SAME + EG_VGT_STRMOUT_BASE_OFFSET_HI_3 = 0x28B50, // SAME + EG_VGT_SHADER_STAGES_EN = 0x28B54, // + EG_VGT_LS_HS_CONFIG = 0x28B58, // + EG_VGT_LS_SIZE = 0x28B5C, // + EG_VGT_HS_SIZE = 0x28B60, // + EG_VGT_LS_HS_ALLOC = 0x28B64, // + EG_VGT_HS_PATCH_CONST = 0x28B68, // + EG_VGT_TF_PARAM = 0x28B6C, // + EG_VGT_DISPATCH_INITIATOR = 0x28B74, // + EG_VGT_GS_INSTANCE_CNT = 0x28B90, // + EG_VGT_STRMOUT_CONFIG = 0x28B94, // + EG_VGT_STRMOUT_BUFFER_CONFIG = 0x28B98, // + EG_VGT_VERTEX_REUSE_BLOCK_CNTL = 0x28C58, // SAME + EG_VGT_OUT_DEALLOC_CNTL = 0x28C5C, // SAME + +/* Registers from TP block: */ + EG_GDS_ADDR_BASE = 0x28720, // + EG_GDS_ADDR_SIZE = 0x28724, // + EG_GDS_ORDERED_WAVE_PER_SE = 0x28728, // + EG_GDS_APPEND_CONSUME_UAV0 = 0x2872C, // + EG_GDS_APPEND_CONSUME_UAV1 = 0x28730, // + EG_GDS_APPEND_CONSUME_UAV2 = 0x28734, // + EG_GDS_APPEND_CONSUME_UAV3 = 0x28738, // + EG_GDS_APPEND_CONSUME_UAV4 = 0x2873C, // + EG_GDS_APPEND_CONSUME_UAV5 = 0x28740, // + EG_GDS_APPEND_CONSUME_UAV6 = 0x28744, // + EG_GDS_APPEND_CONSUME_UAV7 = 0x28748, // + EG_GDS_APPEND_CONSUME_UAV8 = 0x2874C, // + EG_GDS_APPEND_CONSUME_UAV9 = 0x28750, // + EG_GDS_APPEND_CONSUME_UAV10 = 0x28754, // + EG_GDS_APPEND_CONSUME_UAV11 = 0x28758, // + +/* Registers from SQ block: */ + EG_SQ_LOOP_CONST_0 = 0x3A200, // 0x3E200 + EG_SQ_ALU_CONST_BUFFER_SIZE_VS_0 = 0x28180, // ? + EG_SQ_VTX_SEMANTIC_0 = 0x28380, // SAME + EG_SQ_VTX_SEMANTIC_1 = 0x28384, // SAME + EG_SQ_VTX_SEMANTIC_2 = 0x28388, // SAME + EG_SQ_VTX_SEMANTIC_3 = 0x2838C, // SAME + EG_SQ_VTX_SEMANTIC_4 = 0x28390, // SAME + EG_SQ_VTX_SEMANTIC_5 = 0x28394, // SAME + EG_SQ_VTX_SEMANTIC_6 = 0x28398, // SAME + EG_SQ_VTX_SEMANTIC_7 = 0x2839C, // SAME + EG_SQ_VTX_SEMANTIC_8 = 0x283A0, // SAME + EG_SQ_VTX_SEMANTIC_9 = 0x283A4, // SAME + EG_SQ_VTX_SEMANTIC_10 = 0x283A8, // SAME + EG_SQ_VTX_SEMANTIC_11 = 0x283AC, // SAME + EG_SQ_VTX_SEMANTIC_12 = 0x283B0, // SAME + EG_SQ_VTX_SEMANTIC_13 = 0x283B4, // SAME + EG_SQ_VTX_SEMANTIC_14 = 0x283B8, // SAME + EG_SQ_VTX_SEMANTIC_15 = 0x283BC, // SAME + EG_SQ_VTX_SEMANTIC_16 = 0x283C0, // SAME + EG_SQ_VTX_SEMANTIC_17 = 0x283C4, // SAME + EG_SQ_VTX_SEMANTIC_18 = 0x283C8, // SAME + EG_SQ_VTX_SEMANTIC_19 = 0x283CC, // SAME + EG_SQ_VTX_SEMANTIC_20 = 0x283D0, // SAME + EG_SQ_VTX_SEMANTIC_21 = 0x283D4, // SAME + EG_SQ_VTX_SEMANTIC_22 = 0x283D8, // SAME + EG_SQ_VTX_SEMANTIC_23 = 0x283DC, // SAME + EG_SQ_VTX_SEMANTIC_24 = 0x283E0, // SAME + EG_SQ_VTX_SEMANTIC_25 = 0x283E4, // SAME + EG_SQ_VTX_SEMANTIC_26 = 0x283E8, // SAME + EG_SQ_VTX_SEMANTIC_27 = 0x283EC, // SAME + EG_SQ_VTX_SEMANTIC_28 = 0x283F0, // SAME + EG_SQ_VTX_SEMANTIC_29 = 0x283F4, // SAME + EG_SQ_VTX_SEMANTIC_30 = 0x283F8, // SAME + EG_SQ_VTX_SEMANTIC_31 = 0x283FC, // SAME + EG_SQ_LSTMP_RING_ITEMSIZE = 0x28830, // + EG_SQ_HSTMP_RING_ITEMSIZE = 0x28834, // + EG_SQ_DYN_GPR_RESOURCE_LIMIT_1 = 0x28838, // + EG_SQ_PGM_START_PS = 0x28840, // SAME + EG_SQ_PGM_RESOURCES_PS = 0x28844, // DIFF 0x28850 + EG_SQ_PGM_RESOURCES_2_PS = 0x28848, // + EG_SQ_PGM_EXPORTS_PS = 0x2884C, // SAME 0x28854 + EG_SQ_PGM_START_VS = 0x2885C, // SAME 0x28858 + EG_SQ_PGM_RESOURCES_VS = 0x28860, // DIFF 0x28868 + EG_SQ_PGM_RESOURCES_2_VS = 0x28864, // + EG_SQ_PGM_START_GS = 0x28874, // SAME 0x2886C + EG_SQ_PGM_RESOURCES_GS = 0x28878, // DIFF 0x2887C + EG_SQ_PGM_RESOURCES_2_GS = 0x2887C, // + EG_SQ_PGM_START_ES = 0x2888C, // SAME 0x28880 + EG_SQ_PGM_RESOURCES_ES = 0x28890, // DIFF + EG_SQ_PGM_RESOURCES_2_ES = 0x28894, // + EG_SQ_PGM_START_FS = 0x288A4, // SAME 0x28894 + EG_SQ_PGM_RESOURCES_FS = 0x288A8, // DIFF 0x288A4 + EG_SQ_PGM_START_HS = 0x288B8, // + EG_SQ_PGM_RESOURCES_HS = 0x288BC, // + EG_SQ_PGM_RESOURCES_2_HS = 0x288C0, // + EG_SQ_PGM_START_LS = 0x288D0, // + EG_SQ_PGM_RESOURCES_LS = 0x288D4, // + EG_SQ_PGM_RESOURCES_2_LS = 0x288D8, // + EG_SQ_THREAD_TRACE_USERDATA = 0x288DC, // + EG_SQ_LDS_ALLOC = 0x288E8, // + EG_SQ_LDS_ALLOC_PS = 0x288EC, // + EG_SQ_VTX_SEMANTIC_CLEAR = 0x288F0, // SAME 0x288E0 + EG_SQ_THREAD_TRACE_CTRL = 0x288F8, // + EG_SQ_ESGS_RING_ITEMSIZE = 0x28900, // SAME 0x288A8 + EG_SQ_GSVS_RING_ITEMSIZE = 0x28904, // SAME 0x288AC + EG_SQ_ESTMP_RING_ITEMSIZE = 0x28908, // SAME 0x288B0 + EG_SQ_GSTMP_RING_ITEMSIZE = 0x2890C, // SAME 0x288B4 + EG_SQ_VSTMP_RING_ITEMSIZE = 0x28910, // SAME 0x288B8 + EG_SQ_PSTMP_RING_ITEMSIZE = 0x28914, // SAME 0x288BC + EG_SQ_GS_VERT_ITEMSIZE = 0x2891C, // SAME 0x288C8 + EG_SQ_GS_VERT_ITEMSIZE_1 = 0x28920, // + EG_SQ_GS_VERT_ITEMSIZE_2 = 0x28924, // + EG_SQ_GS_VERT_ITEMSIZE_3 = 0x28928, // + EG_SQ_GSVS_RING_OFFSET_1 = 0x2892C, // + EG_SQ_GSVS_RING_OFFSET_2 = 0x28930, // + EG_SQ_GSVS_RING_OFFSET_3 = 0x28934, // + EG_SQ_ALU_CONST_CACHE_PS_0 = 0x28940, // SAME + EG_SQ_ALU_CONST_CACHE_PS_1 = 0x28944, // SAME + EG_SQ_ALU_CONST_CACHE_PS_2 = 0x28948, // SAME + EG_SQ_ALU_CONST_CACHE_PS_3 = 0x2894C, // SAME + EG_SQ_ALU_CONST_CACHE_PS_4 = 0x28950, // SAME + EG_SQ_ALU_CONST_CACHE_PS_5 = 0x28954, // SAME + EG_SQ_ALU_CONST_CACHE_PS_6 = 0x28958, // SAME + EG_SQ_ALU_CONST_CACHE_PS_7 = 0x2895C, // SAME + EG_SQ_ALU_CONST_CACHE_PS_8 = 0x28960, // SAME + EG_SQ_ALU_CONST_CACHE_PS_9 = 0x28964, // SAME + EG_SQ_ALU_CONST_CACHE_PS_10 = 0x28968, // SAME + EG_SQ_ALU_CONST_CACHE_PS_11 = 0x2896C, // SAME + EG_SQ_ALU_CONST_CACHE_PS_12 = 0x28970, // SAME + EG_SQ_ALU_CONST_CACHE_PS_13 = 0x28974, // SAME + EG_SQ_ALU_CONST_CACHE_PS_14 = 0x28978, // SAME + EG_SQ_ALU_CONST_CACHE_PS_15 = 0x2897C, // SAME + EG_SQ_ALU_CONST_CACHE_VS_0 = 0x28980, // SAME + EG_SQ_ALU_CONST_CACHE_VS_1 = 0x28984, // SAME + EG_SQ_ALU_CONST_CACHE_VS_2 = 0x28988, // SAME + EG_SQ_ALU_CONST_CACHE_VS_3 = 0x2898C, // SAME + EG_SQ_ALU_CONST_CACHE_VS_4 = 0x28990, // SAME + EG_SQ_ALU_CONST_CACHE_VS_5 = 0x28994, // SAME + EG_SQ_ALU_CONST_CACHE_VS_6 = 0x28998, // SAME + EG_SQ_ALU_CONST_CACHE_VS_7 = 0x2899C, // SAME + EG_SQ_ALU_CONST_CACHE_VS_8 = 0x289A0, // SAME + EG_SQ_ALU_CONST_CACHE_VS_9 = 0x289A4, // SAME + EG_SQ_ALU_CONST_CACHE_VS_10 = 0x289A8, // SAME + EG_SQ_ALU_CONST_CACHE_VS_11 = 0x289AC, // SAME + EG_SQ_ALU_CONST_CACHE_VS_12 = 0x289B0, // SAME + EG_SQ_ALU_CONST_CACHE_VS_13 = 0x289B4, // SAME + EG_SQ_ALU_CONST_CACHE_VS_14 = 0x289B8, // SAME + EG_SQ_ALU_CONST_CACHE_VS_15 = 0x289BC, // SAME + EG_SQ_ALU_CONST_CACHE_GS_0 = 0x289C0, // SAME + EG_SQ_ALU_CONST_CACHE_GS_1 = 0x289C4, // SAME + EG_SQ_ALU_CONST_CACHE_GS_2 = 0x289C8, // SAME + EG_SQ_ALU_CONST_CACHE_GS_3 = 0x289CC, // SAME + EG_SQ_ALU_CONST_CACHE_GS_4 = 0x289D0, // SAME + EG_SQ_ALU_CONST_CACHE_GS_5 = 0x289D4, // SAME + EG_SQ_ALU_CONST_CACHE_GS_6 = 0x289D8, // SAME + EG_SQ_ALU_CONST_CACHE_GS_7 = 0x289DC, // SAME + EG_SQ_ALU_CONST_CACHE_GS_8 = 0x289E0, // SAME + EG_SQ_ALU_CONST_CACHE_GS_9 = 0x289E4, // SAME + EG_SQ_ALU_CONST_CACHE_GS_10 = 0x289E8, // SAME + EG_SQ_ALU_CONST_CACHE_GS_11 = 0x289EC, // SAME + EG_SQ_ALU_CONST_CACHE_GS_12 = 0x289F0, // SAME + EG_SQ_ALU_CONST_CACHE_GS_13 = 0x289F4, // SAME + EG_SQ_ALU_CONST_CACHE_GS_14 = 0x289F8, // SAME + EG_SQ_ALU_CONST_CACHE_GS_15 = 0x289FC, // SAME + EG_SQ_ALU_CONST_CACHE_HS_0 = 0x28F00, // + EG_SQ_ALU_CONST_CACHE_HS_1 = 0x28F04, // + EG_SQ_ALU_CONST_CACHE_HS_2 = 0x28F08, // + EG_SQ_ALU_CONST_CACHE_HS_3 = 0x28F0C, // + EG_SQ_ALU_CONST_CACHE_HS_4 = 0x28F10, // + EG_SQ_ALU_CONST_CACHE_HS_5 = 0x28F14, // + EG_SQ_ALU_CONST_CACHE_HS_6 = 0x28F18, // + EG_SQ_ALU_CONST_CACHE_HS_7 = 0x28F1C, // + EG_SQ_ALU_CONST_CACHE_HS_8 = 0x28F20, // + EG_SQ_ALU_CONST_CACHE_HS_9 = 0x28F24, // + EG_SQ_ALU_CONST_CACHE_HS_10 = 0x28F28, // + EG_SQ_ALU_CONST_CACHE_HS_11 = 0x28F2C, // + EG_SQ_ALU_CONST_CACHE_HS_12 = 0x28F30, // + EG_SQ_ALU_CONST_CACHE_HS_13 = 0x28F34, // + EG_SQ_ALU_CONST_CACHE_HS_14 = 0x28F38, // + EG_SQ_ALU_CONST_CACHE_HS_15 = 0x28F3C, // + EG_SQ_ALU_CONST_CACHE_LS_0 = 0x28F40, // + EG_SQ_ALU_CONST_CACHE_LS_1 = 0x28F44, // + EG_SQ_ALU_CONST_CACHE_LS_2 = 0x28F48, // + EG_SQ_ALU_CONST_CACHE_LS_3 = 0x28F4C, // + EG_SQ_ALU_CONST_CACHE_LS_4 = 0x28F50, // + EG_SQ_ALU_CONST_CACHE_LS_5 = 0x28F54, // + EG_SQ_ALU_CONST_CACHE_LS_6 = 0x28F58, // + EG_SQ_ALU_CONST_CACHE_LS_7 = 0x28F5C, // + EG_SQ_ALU_CONST_CACHE_LS_8 = 0x28F60, // + EG_SQ_ALU_CONST_CACHE_LS_9 = 0x28F64, // + EG_SQ_ALU_CONST_CACHE_LS_10 = 0x28F68, // + EG_SQ_ALU_CONST_CACHE_LS_11 = 0x28F6C, // + EG_SQ_ALU_CONST_CACHE_LS_12 = 0x28F70, // + EG_SQ_ALU_CONST_CACHE_LS_13 = 0x28F74, // + EG_SQ_ALU_CONST_CACHE_LS_14 = 0x28F78, // + EG_SQ_ALU_CONST_CACHE_LS_15 = 0x28F7C, // + EG_SQ_ALU_CONST_BUFFER_SIZE_PS_0 = 0x28140, + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_0 = 0x28F80, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_1 = 0x28F84, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_2 = 0x28F88, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_3 = 0x28F8C, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_4 = 0x28F90, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_5 = 0x28F94, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_6 = 0x28F98, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_7 = 0x28F9C, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_8 = 0x28FA0, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_9 = 0x28FA4, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_10 = 0x28FA8, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_11 = 0x28FAC, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_12 = 0x28FB0, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_13 = 0x28FB4, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_14 = 0x28FB8, // + EG_SQ_ALU_CONST_BUFFER_SIZE_HS_15 = 0x28FBC, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_0 = 0x28FC0, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_1 = 0x28FC4, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_2 = 0x28FC8, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_3 = 0x28FCC, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_4 = 0x28FD0, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_5 = 0x28FD4, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_6 = 0x28FD8, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_7 = 0x28FDC, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_8 = 0x28FE0, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_9 = 0x28FE4, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_10 = 0x28FE8, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_11 = 0x28FEC, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_12 = 0x28FF0, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_13 = 0x28FF4, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_14 = 0x28FF8, // + EG_SQ_ALU_CONST_BUFFER_SIZE_LS_15 = 0x28FFC, // + +/* Registers from SPI block: */ + EG_SPI_VS_OUT_ID_0 = 0x2861C, // SAME 0x28614 + EG_SPI_VS_OUT_ID_1 = 0x28620, // SAME 0x28618 + EG_SPI_VS_OUT_ID_2 = 0x28624, // SAME 0x2861C + EG_SPI_VS_OUT_ID_3 = 0x28628, // SAME 0x28620 + EG_SPI_VS_OUT_ID_4 = 0x2862C, // SAME 0x28624 + EG_SPI_VS_OUT_ID_5 = 0x28630, // SAME 0x28628 + EG_SPI_VS_OUT_ID_6 = 0x28634, // SAME 0x2862C + EG_SPI_VS_OUT_ID_7 = 0x28638, // SAME 0x28630 + EG_SPI_VS_OUT_ID_8 = 0x2863C, // SAME 0x28634 + EG_SPI_VS_OUT_ID_9 = 0x28640, // SAME 0x28638 + EG_SPI_PS_INPUT_CNTL_0 = 0x28644, // SAME + EG_SPI_PS_INPUT_CNTL_1 = 0x28648, // SAME + EG_SPI_PS_INPUT_CNTL_2 = 0x2864C, // SAME + EG_SPI_PS_INPUT_CNTL_3 = 0x28650, // SAME + EG_SPI_PS_INPUT_CNTL_4 = 0x28654, // SAME + EG_SPI_PS_INPUT_CNTL_5 = 0x28658, // SAME + EG_SPI_PS_INPUT_CNTL_6 = 0x2865C, // SAME + EG_SPI_PS_INPUT_CNTL_7 = 0x28660, // SAME + EG_SPI_PS_INPUT_CNTL_8 = 0x28664, // SAME + EG_SPI_PS_INPUT_CNTL_9 = 0x28668, // SAME + EG_SPI_PS_INPUT_CNTL_10 = 0x2866C, // SAME + EG_SPI_PS_INPUT_CNTL_11 = 0x28670, // SAME + EG_SPI_PS_INPUT_CNTL_12 = 0x28674, // SAME + EG_SPI_PS_INPUT_CNTL_13 = 0x28678, // SAME + EG_SPI_PS_INPUT_CNTL_14 = 0x2867C, // SAME + EG_SPI_PS_INPUT_CNTL_15 = 0x28680, // SAME + EG_SPI_PS_INPUT_CNTL_16 = 0x28684, // SAME + EG_SPI_PS_INPUT_CNTL_17 = 0x28688, // SAME + EG_SPI_PS_INPUT_CNTL_18 = 0x2868C, // SAME + EG_SPI_PS_INPUT_CNTL_19 = 0x28690, // SAME + EG_SPI_PS_INPUT_CNTL_20 = 0x28694, // SAME + EG_SPI_PS_INPUT_CNTL_21 = 0x28698, // SAME + EG_SPI_PS_INPUT_CNTL_22 = 0x2869C, // SAME + EG_SPI_PS_INPUT_CNTL_23 = 0x286A0, // SAME + EG_SPI_PS_INPUT_CNTL_24 = 0x286A4, // SAME + EG_SPI_PS_INPUT_CNTL_25 = 0x286A8, // SAME + EG_SPI_PS_INPUT_CNTL_26 = 0x286AC, // SAME + EG_SPI_PS_INPUT_CNTL_27 = 0x286B0, // SAME + EG_SPI_PS_INPUT_CNTL_28 = 0x286B4, // SAME + EG_SPI_PS_INPUT_CNTL_29 = 0x286B8, // SAME + EG_SPI_PS_INPUT_CNTL_30 = 0x286BC, // SAME + EG_SPI_PS_INPUT_CNTL_31 = 0x286C0, // SAME + EG_SPI_VS_OUT_CONFIG = 0x286C4, // SAME + EG_SPI_THREAD_GROUPING = 0x286C8, // DIFF + EG_SPI_PS_IN_CONTROL_0 = 0x286CC, // SAME + EG_SPI_PS_IN_CONTROL_1 = 0x286D0, // SAME + EG_SPI_INTERP_CONTROL_0 = 0x286D4, // SAME + EG_SPI_INPUT_Z = 0x286D8, // SAME + EG_SPI_FOG_CNTL = 0x286DC, // SAME + EG_SPI_BARYC_CNTL = 0x286E0, // + EG_SPI_PS_IN_CONTROL_2 = 0x286E4, // + EG_SPI_COMPUTE_INPUT_CNTL = 0x286E8, // + EG_SPI_COMPUTE_NUM_THREAD_X = 0x286EC, // + EG_SPI_COMPUTE_NUM_THREAD_Y = 0x286F0, // + EG_SPI_COMPUTE_NUM_THREAD_Z = 0x286F4, // + +/* Registers from SX block: */ + EG_SX_MISC = 0x28350, // SAME + EG_SX_SURFACE_SYNC = 0x28354, // DIFF + EG_SX_ALPHA_TEST_CONTROL = 0x28410, // SAME + EG_SX_ALPHA_REF = 0x28438, // SAME + +/* Registers from DB block: */ + EG_DB_RENDER_CONTROL = 0x28000, // DIFF 0x28D0C + EG_DB_COUNT_CONTROL = 0x28004, // + EG_DB_DEPTH_VIEW = 0x28008, // DIFF 0x28004 + EG_DB_RENDER_OVERRIDE = 0x2800C, // DIFF 0x28D10 + EG_DB_RENDER_OVERRIDE2 = 0x28010, // + EG_DB_HTILE_DATA_BASE = 0x28014, // SAME + + EG_DB_STENCIL_CLEAR = 0x28028, // SAME + EG_DB_DEPTH_CLEAR = 0x2802C, // SAME + + EG_DB_Z_INFO = 0x28040, // + EG_DB_STENCIL_INFO = 0x28044, // + EG_DB_Z_READ_BASE = 0x28048, // + EG_DB_STENCIL_READ_BASE = 0x2804C, // + EG_DB_Z_WRITE_BASE = 0x28050, // + EG_DB_STENCIL_WRITE_BASE = 0x28054, // + EG_DB_DEPTH_SIZE = 0x28058, // DIFF 0x28000 + EG_DB_DEPTH_SLICE = 0x2805C, // + + EG_DB_STENCILREFMASK = 0x28430, // SAME + EG_DB_STENCILREFMASK_BF = 0x28434, // SAME + EG_DB_DEPTH_CONTROL = 0x28800, // SAME + EG_DB_SHADER_CONTROL = 0x2880C, // DIFF + EG_DB_HTILE_SURFACE = 0x28ABC, // SAME 0x28D24 + EG_DB_SRESULTS_COMPARE_STATE0 = 0x28AC0, // SAME 0x28D28 + EG_DB_SRESULTS_COMPARE_STATE1 = 0x28AC4, // SAME 0x28D2C + EG_DB_PRELOAD_CONTROL = 0x28AC8, // SAME 0x28D30 + EG_DB_ALPHA_TO_MASK = 0x28B70, // SAME 0x28D44 + +/* Registers from CB block: */ + EG_CB_TARGET_MASK = 0x28238, // SAME + EG_CB_SHADER_MASK = 0x2823C, // SAME + EG_CB_BLEND_RED = 0x28414, // SAME + EG_CB_BLEND_GREEN = 0x28418, // SAME + EG_CB_BLEND_BLUE = 0x2841C, // SAME + EG_CB_BLEND_ALPHA = 0x28420, // SAME + EG_CB_BLEND0_CONTROL = 0x28780, // DIFF + EG_CB_BLEND1_CONTROL = 0x28784, // DIFF + EG_CB_BLEND2_CONTROL = 0x28788, // DIFF + EG_CB_BLEND3_CONTROL = 0x2878C, // DIFF + EG_CB_BLEND4_CONTROL = 0x28790, // DIFF + EG_CB_BLEND5_CONTROL = 0x28794, // DIFF + EG_CB_BLEND6_CONTROL = 0x28798, // DIFF + EG_CB_BLEND7_CONTROL = 0x2879C, // DIFF + EG_CB_COLOR_CONTROL = 0x28808, // DIFF + EG_CB_IMMED0_BASE = 0x28B9C, // + EG_CB_IMMED1_BASE = 0x28BA0, // + EG_CB_IMMED2_BASE = 0x28BA4, // + EG_CB_IMMED3_BASE = 0x28BA8, // + EG_CB_IMMED4_BASE = 0x28BAC, // + EG_CB_IMMED5_BASE = 0x28BB0, // + EG_CB_IMMED6_BASE = 0x28BB4, // + EG_CB_IMMED7_BASE = 0x28BB8, // + EG_CB_IMMED8_BASE = 0x28BBC, // + EG_CB_IMMED9_BASE = 0x28BC0, // + EG_CB_IMMED10_BASE = 0x28BC4, // + EG_CB_IMMED11_BASE = 0x28BC8, // + EG_CB_CLRCMP_CONTROL = 0x28C40, // SAME 0x28C30 + EG_CB_CLRCMP_SRC = 0x28C44, // SAME 0x28C34 + EG_CB_CLRCMP_DST = 0x28C48, // SAME 0x28C38 + EG_CB_CLRCMP_MSK = 0x28C4C, // SAME 0x28C3C + EG_CB_COLOR0_BASE = 0x28C60, // SAME 0x28040 + EG_CB_COLOR0_PITCH = 0x28C64, // + EG_CB_COLOR0_SLICE = 0x28C68, // + EG_CB_COLOR0_VIEW = 0x28C6C, // SAME 0x28080 + EG_CB_COLOR0_INFO = 0x28C70, // DIFF 0x280A0 + EG_CB_COLOR0_ATTRIB = 0x28C74, // + EG_CB_COLOR0_DIM = 0x28C78, // + EG_CB_COLOR0_CMASK = 0x28C7C, // + EG_CB_COLOR0_CMASK_SLICE = 0x28C80, // + EG_CB_COLOR0_FMASK = 0x28C84, // + EG_CB_COLOR0_FMASK_SLICE = 0x28C88, // + EG_CB_COLOR0_CLEAR_WORD0 = 0x28C8C, // + EG_CB_COLOR0_CLEAR_WORD1 = 0x28C90, // + EG_CB_COLOR0_CLEAR_WORD2 = 0x28C94, // + EG_CB_COLOR0_CLEAR_WORD3 = 0x28C98, // + EG_CB_COLOR1_BASE = 0x28C9C, // SAME 0x28044 + EG_CB_COLOR1_PITCH = 0x28CA0, // + EG_CB_COLOR1_SLICE = 0x28CA4, // + EG_CB_COLOR1_VIEW = 0x28CA8, // SAME 0x28084 + EG_CB_COLOR1_INFO = 0x28CAC, // DIFF 0x280A4 + EG_CB_COLOR1_ATTRIB = 0x28CB0, // + EG_CB_COLOR1_DIM = 0x28CB4, // + EG_CB_COLOR1_CMASK = 0x28CB8, // + EG_CB_COLOR1_CMASK_SLICE = 0x28CBC, // + EG_CB_COLOR1_FMASK = 0x28CC0, // + EG_CB_COLOR1_FMASK_SLICE = 0x28CC4, // + EG_CB_COLOR1_CLEAR_WORD0 = 0x28CC8, // + EG_CB_COLOR1_CLEAR_WORD1 = 0x28CCC, // + EG_CB_COLOR1_CLEAR_WORD2 = 0x28CD0, // + EG_CB_COLOR1_CLEAR_WORD3 = 0x28CD4, // + EG_CB_COLOR2_BASE = 0x28CD8, // SAME 0x28048 + EG_CB_COLOR2_PITCH = 0x28CDC, // + EG_CB_COLOR2_SLICE = 0x28CE0, // + EG_CB_COLOR2_VIEW = 0x28CE4, // SAME 0x28088 + EG_CB_COLOR2_INFO = 0x28CE8, // DIFF 0x280A8 + EG_CB_COLOR2_ATTRIB = 0x28CEC, // + EG_CB_COLOR2_DIM = 0x28CF0, // + EG_CB_COLOR2_CMASK = 0x28CF4, // + EG_CB_COLOR2_CMASK_SLICE = 0x28CF8, // + EG_CB_COLOR2_FMASK = 0x28CFC, // + EG_CB_COLOR2_FMASK_SLICE = 0x28D00, // + EG_CB_COLOR2_CLEAR_WORD0 = 0x28D04, // + EG_CB_COLOR2_CLEAR_WORD1 = 0x28D08, // + EG_CB_COLOR2_CLEAR_WORD2 = 0x28D0C, // + EG_CB_COLOR2_CLEAR_WORD3 = 0x28D10, // + EG_CB_COLOR3_BASE = 0x28D14, // SAME 0x2804C + EG_CB_COLOR3_PITCH = 0x28D18, // + EG_CB_COLOR3_SLICE = 0x28D1C, // + EG_CB_COLOR3_VIEW = 0x28D20, // SAME 0x2808C + EG_CB_COLOR3_INFO = 0x28D24, // DIFF 0x280AC + EG_CB_COLOR3_ATTRIB = 0x28D28, // + EG_CB_COLOR3_DIM = 0x28D2C, // + EG_CB_COLOR3_CMASK = 0x28D30, // + EG_CB_COLOR3_CMASK_SLICE = 0x28D34, // + EG_CB_COLOR3_FMASK = 0x28D38, // + EG_CB_COLOR3_FMASK_SLICE = 0x28D3C, // + EG_CB_COLOR3_CLEAR_WORD0 = 0x28D40, // + EG_CB_COLOR3_CLEAR_WORD1 = 0x28D44, // + EG_CB_COLOR3_CLEAR_WORD2 = 0x28D48, // + EG_CB_COLOR3_CLEAR_WORD3 = 0x28D4C, // + EG_CB_COLOR4_BASE = 0x28D50, // SAME 0x28050 + EG_CB_COLOR4_PITCH = 0x28D54, // + EG_CB_COLOR4_SLICE = 0x28D58, // + EG_CB_COLOR4_VIEW = 0x28D5C, // SAME 0x28090 + EG_CB_COLOR4_INFO = 0x28D60, // DIFF 0x280B0 + EG_CB_COLOR4_ATTRIB = 0x28D64, // + EG_CB_COLOR4_DIM = 0x28D68, // + EG_CB_COLOR4_CMASK = 0x28D6C, // + EG_CB_COLOR4_CMASK_SLICE = 0x28D70, // + EG_CB_COLOR4_FMASK = 0x28D74, // + EG_CB_COLOR4_FMASK_SLICE = 0x28D78, // + EG_CB_COLOR4_CLEAR_WORD0 = 0x28D7C, // + EG_CB_COLOR4_CLEAR_WORD1 = 0x28D80, // + EG_CB_COLOR4_CLEAR_WORD2 = 0x28D84, // + EG_CB_COLOR4_CLEAR_WORD3 = 0x28D88, // + EG_CB_COLOR5_BASE = 0x28D8C, // SAME 0x28054 + EG_CB_COLOR5_PITCH = 0x28D90, // + EG_CB_COLOR5_SLICE = 0x28D94, // + EG_CB_COLOR5_VIEW = 0x28D98, // SAME 0x28094 + EG_CB_COLOR5_INFO = 0x28D9C, // DIFF 0x280B4 + EG_CB_COLOR5_ATTRIB = 0x28DA0, // + EG_CB_COLOR5_DIM = 0x28DA4, // + EG_CB_COLOR5_CMASK = 0x28DA8, // + EG_CB_COLOR5_CMASK_SLICE = 0x28DAC, // + EG_CB_COLOR5_FMASK = 0x28DB0, // + EG_CB_COLOR5_FMASK_SLICE = 0x28DB4, // + EG_CB_COLOR5_CLEAR_WORD0 = 0x28DB8, // + EG_CB_COLOR5_CLEAR_WORD1 = 0x28DBC, // + EG_CB_COLOR5_CLEAR_WORD2 = 0x28DC0, // + EG_CB_COLOR5_CLEAR_WORD3 = 0x28DC4, // + EG_CB_COLOR6_BASE = 0x28DC8, // SAME 0x28058 + EG_CB_COLOR6_PITCH = 0x28DCC, // + EG_CB_COLOR6_SLICE = 0x28DD0, // + EG_CB_COLOR6_VIEW = 0x28DD4, // SAME 0x28098 + EG_CB_COLOR6_INFO = 0x28DD8, // DIFF 0x280B8 + EG_CB_COLOR6_ATTRIB = 0x28DDC, // + EG_CB_COLOR6_DIM = 0x28DE0, // + EG_CB_COLOR6_CMASK = 0x28DE4, // + EG_CB_COLOR6_CMASK_SLICE = 0x28DE8, // + EG_CB_COLOR6_FMASK = 0x28DEC, // + EG_CB_COLOR6_FMASK_SLICE = 0x28DF0, // + EG_CB_COLOR6_CLEAR_WORD0 = 0x28DF4, // + EG_CB_COLOR6_CLEAR_WORD1 = 0x28DF8, // + EG_CB_COLOR6_CLEAR_WORD2 = 0x28DFC, // + EG_CB_COLOR6_CLEAR_WORD3 = 0x28E00, // + EG_CB_COLOR7_BASE = 0x28E04, // SAME 0x2805C + EG_CB_COLOR7_PITCH = 0x28E08, // + EG_CB_COLOR7_SLICE = 0x28E0C, // + EG_CB_COLOR7_VIEW = 0x28E10, // SAME 0x2809C + EG_CB_COLOR7_INFO = 0x28E14, // DIFF 0x280BC + EG_CB_COLOR7_ATTRIB = 0x28E18, // + EG_CB_COLOR7_DIM = 0x28E1C, // + EG_CB_COLOR7_CMASK = 0x28E20, // + EG_CB_COLOR7_CMASK_SLICE = 0x28E24, // + EG_CB_COLOR7_FMASK = 0x28E28, // + EG_CB_COLOR7_FMASK_SLICE = 0x28E2C, // + EG_CB_COLOR7_CLEAR_WORD0 = 0x28E30, // + EG_CB_COLOR7_CLEAR_WORD1 = 0x28E34, // + EG_CB_COLOR7_CLEAR_WORD2 = 0x28E38, // + EG_CB_COLOR7_CLEAR_WORD3 = 0x28E3C, // + EG_CB_COLOR8_BASE = 0x28E40, // + EG_CB_COLOR8_PITCH = 0x28E44, // + EG_CB_COLOR8_SLICE = 0x28E48, // + EG_CB_COLOR8_VIEW = 0x28E4C, // + EG_CB_COLOR8_INFO = 0x28E50, // + EG_CB_COLOR8_ATTRIB = 0x28E54, // + EG_CB_COLOR8_DIM = 0x28E58, // + EG_CB_COLOR9_BASE = 0x28E5C, // + EG_CB_COLOR9_PITCH = 0x28E60, // + EG_CB_COLOR9_SLICE = 0x28E64, // + EG_CB_COLOR9_VIEW = 0x28E68, // + EG_CB_COLOR9_INFO = 0x28E6C, // + EG_CB_COLOR9_ATTRIB = 0x28E70, // + EG_CB_COLOR9_DIM = 0x28E74, // + EG_CB_COLOR10_BASE = 0x28E78, // + EG_CB_COLOR10_PITCH = 0x28E7C, // + EG_CB_COLOR10_SLICE = 0x28E80, // + EG_CB_COLOR10_VIEW = 0x28E84, // + EG_CB_COLOR10_INFO = 0x28E88, // + EG_CB_COLOR10_ATTRIB = 0x28E8C, // + EG_CB_COLOR10_DIM = 0x28E90, // + EG_CB_COLOR11_BASE = 0x28E94, // + EG_CB_COLOR11_PITCH = 0x28E98, // + EG_CB_COLOR11_SLICE = 0x28E9C, // + EG_CB_COLOR11_VIEW = 0x28EA0, // + EG_CB_COLOR11_INFO = 0x28EA4, // + EG_CB_COLOR11_ATTRIB = 0x28EA8, // + EG_CB_COLOR11_DIM = 0x28EAC, // + +/* Registers from CP block: */ + EG_COHER_DEST_BASE_0 = 0x28248, // SAME + EG_COHER_DEST_BASE_1 = 0x2824C, // SAME + EG_CP_PERFMON_CNTX_CNTL = 0x28358, // + +/* Config: */ + EG_SPI_CONFIG_CNTL = 0x9100, // DIFF + EG_SPI_CONFIG_CNTL_1 = 0x913C, // DIFF + EG_CP_PERFMON_CNTL = 0x87FC, // SAME + EG_SQ_MS_FIFO_SIZES = 0x8CF0, // SAME + EG_SQ_CONFIG = 0x8C00, // DIFF + EG_SQ_GPR_RESOURCE_MGMT_1 = 0x8C04, // SAME + EG_SQ_GPR_RESOURCE_MGMT_2 = 0x8C08, // SAME + EG_SQ_THREAD_RESOURCE_MGMT = 0x8C18, // SAME 0x8C0C, + EG_SQ_STACK_RESOURCE_MGMT_1 = 0x8C20, // SAME 0x8C10, + EG_SQ_STACK_RESOURCE_MGMT_2 = 0x8C24, // SAME 0x8C14, + EG_SQ_DYN_GPR_CNTL_PS_FLUSH_REQ = 0x8D8C, // DIFF + EG_SQ_LDS_RESOURCE_MGMT = 0x8E2C, // + EG_SQ_GPR_RESOURCE_MGMT_3 = 0x8C0C, // + EG_SQ_STACK_RESOURCE_MGMT_3 = 0x8C28, // + EG_SQ_THREAD_RESOURCE_MGMT_2 = 0x8C1C, // + EG_VGT_CACHE_INVALIDATION = 0x88C4, // DIFF + EG_VGT_GS_VERTEX_REUSE = 0x88D4, // SAME + EG_PA_SC_FORCE_EOV_MAX_CNTS = 0x8B24, // SAME + EG_PA_SC_LINE_STIPPLE_STATE = 0x8B10, // SAME + EG_PA_CL_ENHANCE = 0x8A14, // SAME + +/* Tex border color */ + EG_TD_PS_BORDER_COLOR_RED = 0xA404, + EG_TD_PS_BORDER_COLOR_GREEN = 0xA408, + EG_TD_PS_BORDER_COLOR_BLUE = 0xA40C, + EG_TD_PS_BORDER_COLOR_ALPHA = 0xA410, + +/* const */ + EG_SQ_VTX_CONSTANT_WORD0_0 = 0x30000, // 0x38000 +}; + +#endif /* _EVERGREEN_OFF_H_ */
\ No newline at end of file diff --git a/src/mesa/drivers/dri/r600/evergreen_oglprog.c b/src/mesa/drivers/dri/r600/evergreen_oglprog.c new file mode 100644 index 0000000000..9fe523234c --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_oglprog.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2008-2009 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#include <string.h> + +#include "main/glheader.h" +#include "main/imports.h" +#include "program/program.h" + +#include "tnl/tnl.h" + +#include "r600_context.h" +#include "r600_emit.h" + +#include "evergreen_oglprog.h" +#include "evergreen_fragprog.h" +#include "evergreen_vertprog.h" + + +static void evergreen_freeVertProgCache(GLcontext *ctx, struct r700_vertex_program_cont *cache) +{ + struct evergreen_vertex_program *tmp, *vp = cache->progs; + + while (vp) { + tmp = vp->next; + /* Release DMA region */ + r600DeleteShader(ctx, vp->shaderbo); + + if(NULL != vp->constbo0) + { + r600DeleteShader(ctx, vp->constbo0); + } + + /* Clean up */ + Clean_Up_Assembler(&(vp->r700AsmCode)); + Clean_Up_Shader(&(vp->r700Shader)); + + _mesa_reference_vertprog(ctx, &vp->mesa_program, NULL); + free(vp); + vp = tmp; + } +} + +static struct gl_program *evergreenNewProgram(GLcontext * ctx, + GLenum target, + GLuint id) +{ + struct gl_program *pProgram = NULL; + + struct evergreen_vertex_program_cont *vpc; + struct evergreen_fragment_program *fp; + + radeon_print(RADEON_SHADER, RADEON_VERBOSE, + "%s %u, %u\n", __func__, target, id); + + switch (target) + { + case GL_VERTEX_STATE_PROGRAM_NV: + case GL_VERTEX_PROGRAM_ARB: + vpc = CALLOC_STRUCT(evergreen_vertex_program_cont); + pProgram = _mesa_init_vertex_program(ctx, + &vpc->mesa_program, + target, + id); + + break; + case GL_FRAGMENT_PROGRAM_NV: + case GL_FRAGMENT_PROGRAM_ARB: + fp = CALLOC_STRUCT(evergreen_fragment_program); + pProgram = _mesa_init_fragment_program(ctx, + &fp->mesa_program, + target, + id); + fp->translated = GL_FALSE; + fp->loaded = GL_FALSE; + + fp->shaderbo = NULL; + + fp->constbo0 = NULL; + + break; + default: + _mesa_problem(ctx, "Bad target in evergreenNewProgram"); + } + + return pProgram; +} + +static void evergreenDeleteProgram(GLcontext * ctx, struct gl_program *prog) +{ + struct evergreen_vertex_program_cont *vpc = (struct evergreen_vertex_program_cont *)prog; + struct evergreen_fragment_program * fp; + + radeon_print(RADEON_SHADER, RADEON_VERBOSE, + "%s %p\n", __func__, prog); + + switch (prog->Target) + { + case GL_VERTEX_STATE_PROGRAM_NV: + case GL_VERTEX_PROGRAM_ARB: + evergreen_freeVertProgCache(ctx, vpc); + break; + case GL_FRAGMENT_PROGRAM_NV: + case GL_FRAGMENT_PROGRAM_ARB: + fp = (struct evergreen_fragment_program*)prog; + /* Release DMA region */ + + r600DeleteShader(ctx, fp->shaderbo); + + if(NULL != fp->constbo0) + { + r600DeleteShader(ctx, fp->constbo0); + } + + /* Clean up */ + Clean_Up_Assembler(&(fp->r700AsmCode)); + Clean_Up_Shader(&(fp->r700Shader)); + break; + default: + _mesa_problem(ctx, "Bad target in evergreenNewProgram"); + } + + _mesa_delete_program(ctx, prog); +} + +static GLboolean +evergreenProgramStringNotify(GLcontext * ctx, GLenum target, struct gl_program *prog) +{ + struct evergreen_vertex_program_cont *vpc = (struct evergreen_vertex_program_cont *)prog; + struct evergreen_fragment_program * fp = (struct evergreen_fragment_program*)prog; + + switch (target) { + case GL_VERTEX_PROGRAM_ARB: + evergreen_freeVertProgCache(ctx, vpc); + vpc->progs = NULL; + break; + case GL_FRAGMENT_PROGRAM_ARB: + r600DeleteShader(ctx, fp->shaderbo); + + if(NULL != fp->constbo0) + { + r600DeleteShader(ctx, fp->constbo0); + fp->constbo0 = NULL; + } + + Clean_Up_Assembler(&(fp->r700AsmCode)); + Clean_Up_Shader(&(fp->r700Shader)); + fp->translated = GL_FALSE; + fp->loaded = GL_FALSE; + fp->shaderbo = NULL; + break; + } + + /* XXX check if program is legal, within limits */ + return GL_TRUE; +} + +static GLboolean evergreenIsProgramNative(GLcontext * ctx, GLenum target, struct gl_program *prog) +{ + + return GL_TRUE; +} + +void evergreenInitShaderFuncs(struct dd_function_table *functions) +{ + functions->NewProgram = evergreenNewProgram; + functions->DeleteProgram = evergreenDeleteProgram; + functions->ProgramStringNotify = evergreenProgramStringNotify; + functions->IsProgramNative = evergreenIsProgramNative; +} diff --git a/src/mesa/slang/slang_emit.h b/src/mesa/drivers/dri/r600/evergreen_oglprog.h index f93d6b00d6..1cf3e79d05 100644 --- a/src/mesa/slang/slang_emit.h +++ b/src/mesa/drivers/dri/r600/evergreen_oglprog.h @@ -1,8 +1,5 @@ /* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2008-2009 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -17,33 +14,20 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef SLANG_EMIT_H -#define SLANG_EMIT_H - -#include "main/glheader.h" -#include "slang_ir.h" -#include "slang_vartable.h" - - -extern GLuint -_slang_swizzle_swizzle(GLuint swz1, GLuint swz2); - - -extern GLuint -_slang_var_swizzle(GLint size, GLint comp); - +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ -extern GLboolean -_slang_emit_code(slang_ir_node *n, slang_var_table *vartable, - struct gl_program *prog, - const struct gl_sl_pragmas *pragmas, - GLboolean withEnd, - slang_info_log *log); +#ifndef _EVERGREEN_OGLPROG_H_ +#define _EVERGREEN_OGLPROG_H_ +#include "r600_context.h" +extern void evergreenInitShaderFuncs(struct dd_function_table *functions); -#endif /* SLANG_EMIT_H */ +#endif /*_EVERGREEN_OGLPROG_H_*/ diff --git a/src/mesa/drivers/dri/r600/evergreen_render.c b/src/mesa/drivers/dri/r600/evergreen_render.c new file mode 100644 index 0000000000..85b2f9d6ab --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_render.c @@ -0,0 +1,937 @@ +/* + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#include "main/glheader.h" +#include "main/state.h" +#include "main/imports.h" +#include "main/enums.h" +#include "main/macros.h" +#include "main/context.h" +#include "main/dd.h" +#include "main/simple_list.h" +#include "main/api_arrayelt.h" +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "vbo/vbo.h" + +#include "tnl/tnl.h" +#include "tnl/t_vp_build.h" +#include "tnl/t_context.h" +#include "tnl/t_vertex.h" +#include "vbo/vbo_context.h" + +#include "r600_context.h" +#include "r600_cmdbuf.h" + +#include "evergreen_fragprog.h" +#include "evergreen_vertprog.h" + +#include "evergreen_state.h" +#include "evergreen_tex.h" + +#include "radeon_buffer_objects.h" +#include "radeon_common_context.h" + +static unsigned int evergreenPrimitiveType(int prim) //same +{ + switch (prim & PRIM_MODE_MASK) + { + case GL_POINTS: + return DI_PT_POINTLIST; + break; + case GL_LINES: + return DI_PT_LINELIST; + break; + case GL_LINE_STRIP: + return DI_PT_LINESTRIP; + break; + case GL_LINE_LOOP: + return DI_PT_LINELOOP; + break; + case GL_TRIANGLES: + return DI_PT_TRILIST; + break; + case GL_TRIANGLE_STRIP: + return DI_PT_TRISTRIP; + break; + case GL_TRIANGLE_FAN: + return DI_PT_TRIFAN; + break; + case GL_QUADS: + return DI_PT_QUADLIST; + break; + case GL_QUAD_STRIP: + return DI_PT_QUADSTRIP; + break; + case GL_POLYGON: + return DI_PT_POLYGON; + break; + default: + assert(0); + return -1; + break; + } +} + +static int evergreenNumVerts(int num_verts, int prim) //same +{ + int verts_off = 0; + + switch (prim & PRIM_MODE_MASK) { + case GL_POINTS: + verts_off = 0; + break; + case GL_LINES: + verts_off = num_verts % 2; + break; + case GL_LINE_STRIP: + if (num_verts < 2) + verts_off = num_verts; + break; + case GL_LINE_LOOP: + if (num_verts < 2) + verts_off = num_verts; + break; + case GL_TRIANGLES: + verts_off = num_verts % 3; + break; + case GL_TRIANGLE_STRIP: + if (num_verts < 3) + verts_off = num_verts; + break; + case GL_TRIANGLE_FAN: + if (num_verts < 3) + verts_off = num_verts; + break; + case GL_QUADS: + verts_off = num_verts % 4; + break; + case GL_QUAD_STRIP: + if (num_verts < 4) + verts_off = num_verts; + else + verts_off = num_verts % 2; + break; + case GL_POLYGON: + if (num_verts < 3) + verts_off = num_verts; + break; + default: + assert(0); + return -1; + break; + } + + return num_verts - verts_off; +} + +static void evergreenRunRenderPrimitive(GLcontext * ctx, int start, int end, int prim) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + BATCH_LOCALS(&context->radeon); + int type, total_emit; + int num_indices; + uint32_t vgt_draw_initiator = 0; + uint32_t vgt_index_type = 0; + uint32_t vgt_primitive_type = 0; + uint32_t vgt_num_indices = 0; + + type = evergreenPrimitiveType(prim); + num_indices = evergreenNumVerts(end - start, prim); + + radeon_print(RADEON_RENDER, RADEON_TRACE, + "%s type %x num_indices %d\n", + __func__, type, num_indices); + + if (type < 0 || num_indices <= 0) + return; + + SETfield(vgt_primitive_type, type, + VGT_PRIMITIVE_TYPE__PRIM_TYPE_shift, VGT_PRIMITIVE_TYPE__PRIM_TYPE_mask); + + SETfield(vgt_index_type, DI_INDEX_SIZE_32_BIT, INDEX_TYPE_shift, INDEX_TYPE_mask); + + if(GL_TRUE != context->ind_buf.is_32bit) + { + SETfield(vgt_index_type, DI_INDEX_SIZE_16_BIT, INDEX_TYPE_shift, INDEX_TYPE_mask); + } + + vgt_num_indices = num_indices; + SETfield(vgt_draw_initiator, DI_SRC_SEL_DMA, SOURCE_SELECT_shift, SOURCE_SELECT_mask); + SETfield(vgt_draw_initiator, DI_MAJOR_MODE_0, MAJOR_MODE_shift, MAJOR_MODE_mask); + + total_emit = 3 /* VGT_PRIMITIVE_TYPE */ + + 2 /* VGT_INDEX_TYPE */ + + 2 /* NUM_INSTANCES */ + + 5 + 2; /* DRAW_INDEX */ + + BEGIN_BATCH_NO_AUTOSTATE(total_emit); + // prim + R600_OUT_BATCH_REGSEQ(VGT_PRIMITIVE_TYPE, 1); + R600_OUT_BATCH(vgt_primitive_type); + // index type + R600_OUT_BATCH(CP_PACKET3(R600_IT_INDEX_TYPE, 0)); + R600_OUT_BATCH(vgt_index_type); + // num instances + R600_OUT_BATCH(CP_PACKET3(R600_IT_NUM_INSTANCES, 0)); + R600_OUT_BATCH(1); + // draw packet + R600_OUT_BATCH(CP_PACKET3(R600_IT_DRAW_INDEX, 3)); + R600_OUT_BATCH(context->ind_buf.bo_offset); + R600_OUT_BATCH(0); + R600_OUT_BATCH(vgt_num_indices); + R600_OUT_BATCH(vgt_draw_initiator); + R600_OUT_BATCH_RELOC(context->ind_buf.bo_offset, + context->ind_buf.bo, + context->ind_buf.bo_offset, + RADEON_GEM_DOMAIN_GTT, 0, 0); + END_BATCH(); + COMMIT_BATCH(); +} + +static void evergreenRunRenderPrimitiveImmediate(GLcontext * ctx, int start, int end, int prim) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + BATCH_LOCALS(&context->radeon); + int type, i; + uint32_t num_indices, total_emit = 0; + uint32_t vgt_draw_initiator = 0; + uint32_t vgt_index_type = 0; + uint32_t vgt_primitive_type = 0; + uint32_t vgt_num_indices = 0; + + type = evergreenPrimitiveType(prim); + num_indices = evergreenNumVerts(end - start, prim); + + radeon_print(RADEON_RENDER, RADEON_TRACE, + "%s type %x num_indices %d\n", + __func__, type, num_indices); + + if (type < 0 || num_indices <= 0) + return; + + SETfield(vgt_primitive_type, type, + VGT_PRIMITIVE_TYPE__PRIM_TYPE_shift, VGT_PRIMITIVE_TYPE__PRIM_TYPE_mask); + + if (num_indices > 0xffff) + { + SETfield(vgt_index_type, DI_INDEX_SIZE_32_BIT, INDEX_TYPE_shift, INDEX_TYPE_mask); + } + else + { + SETfield(vgt_index_type, DI_INDEX_SIZE_16_BIT, INDEX_TYPE_shift, INDEX_TYPE_mask); + } + + vgt_num_indices = num_indices; + SETfield(vgt_draw_initiator, DI_MAJOR_MODE_0, MAJOR_MODE_shift, MAJOR_MODE_mask); + + if (start == 0) + { + SETfield(vgt_draw_initiator, DI_SRC_SEL_AUTO_INDEX, SOURCE_SELECT_shift, SOURCE_SELECT_mask); + } + else + { + if (num_indices > 0xffff) + { + total_emit += num_indices; + } + else + { + total_emit += (num_indices + 1) / 2; + } + SETfield(vgt_draw_initiator, DI_SRC_SEL_IMMEDIATE, SOURCE_SELECT_shift, SOURCE_SELECT_mask); + } + + total_emit += 3 /* VGT_PRIMITIVE_TYPE */ + + 2 /* VGT_INDEX_TYPE */ + + 2 /* NUM_INSTANCES */ + + 3; /* DRAW */ + + BEGIN_BATCH_NO_AUTOSTATE(total_emit); + // prim + R600_OUT_BATCH_REGSEQ(VGT_PRIMITIVE_TYPE, 1); + R600_OUT_BATCH(vgt_primitive_type); + // index type + R600_OUT_BATCH(CP_PACKET3(R600_IT_INDEX_TYPE, 0)); + R600_OUT_BATCH(vgt_index_type); + // num instances + R600_OUT_BATCH(CP_PACKET3(R600_IT_NUM_INSTANCES, 0)); + R600_OUT_BATCH(1); + // draw packet + if(start == 0) + { + R600_OUT_BATCH(CP_PACKET3(R600_IT_DRAW_INDEX_AUTO, 1)); + R600_OUT_BATCH(vgt_num_indices); + R600_OUT_BATCH(vgt_draw_initiator); + } + else + { + if (num_indices > 0xffff) + { + R600_OUT_BATCH(CP_PACKET3(R600_IT_DRAW_INDEX_IMMD, (num_indices + 1))); + R600_OUT_BATCH(vgt_num_indices); + R600_OUT_BATCH(vgt_draw_initiator); + for (i = start; i < (start + num_indices); i++) + { + R600_OUT_BATCH(i); + } + } + else + { + R600_OUT_BATCH(CP_PACKET3(R600_IT_DRAW_INDEX_IMMD, (((num_indices + 1) / 2) + 1))); + R600_OUT_BATCH(vgt_num_indices); + R600_OUT_BATCH(vgt_draw_initiator); + for (i = start; i < (start + num_indices); i += 2) + { + if ((i + 1) == (start + num_indices)) + { + R600_OUT_BATCH(i); + } + else + { + R600_OUT_BATCH(((i + 1) << 16) | (i)); + } + } + } + } + + END_BATCH(); + COMMIT_BATCH(); +} + +#define CONVERT( TYPE, MACRO ) do { \ + GLuint i, j, sz; \ + sz = input->Size; \ + if (input->Normalized) { \ + for (i = 0; i < count; i++) { \ + const TYPE *in = (TYPE *)src_ptr; \ + for (j = 0; j < sz; j++) { \ + *dst_ptr++ = MACRO(*in); \ + in++; \ + } \ + src_ptr += stride; \ + } \ + } else { \ + for (i = 0; i < count; i++) { \ + const TYPE *in = (TYPE *)src_ptr; \ + for (j = 0; j < sz; j++) { \ + *dst_ptr++ = (GLfloat)(*in); \ + in++; \ + } \ + src_ptr += stride; \ + } \ + } \ +} while (0) + +/** + * Convert attribute data type to float + * If the attribute uses named buffer object replace the bo with newly allocated bo + */ +static void evergreenConvertAttrib(GLcontext *ctx, int count, + const struct gl_client_array *input, + struct StreamDesc *attr) +{ + context_t *context = R700_CONTEXT(ctx); + const GLvoid *src_ptr; + GLboolean mapped_named_bo = GL_FALSE; + GLfloat *dst_ptr; + GLuint stride; + + stride = (input->StrideB == 0) ? evergreen_getTypeSize(input->Type) * input->Size : input->StrideB; + + /* Convert value for first element only */ + if (input->StrideB == 0) + { + count = 1; + } + + if (input->BufferObj->Name) + { + if (!input->BufferObj->Pointer) + { + ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY_ARB, input->BufferObj); + mapped_named_bo = GL_TRUE; + } + + src_ptr = ADD_POINTERS(input->BufferObj->Pointer, input->Ptr); + } + else + { + src_ptr = input->Ptr; + } + + radeonAllocDmaRegion(&context->radeon, &attr->bo, &attr->bo_offset, + sizeof(GLfloat) * input->Size * count, 32); + + radeon_bo_map(attr->bo, 1); + + dst_ptr = (GLfloat *)ADD_POINTERS(attr->bo->ptr, attr->bo_offset); + + assert(src_ptr != NULL); + + switch (input->Type) + { + case GL_DOUBLE: + CONVERT(GLdouble, (GLfloat)); + break; + case GL_UNSIGNED_INT: + CONVERT(GLuint, UINT_TO_FLOAT); + break; + case GL_INT: + CONVERT(GLint, INT_TO_FLOAT); + break; + case GL_UNSIGNED_SHORT: + CONVERT(GLushort, USHORT_TO_FLOAT); + break; + case GL_SHORT: + CONVERT(GLshort, SHORT_TO_FLOAT); + break; + case GL_UNSIGNED_BYTE: + assert(input->Format != GL_BGRA); + CONVERT(GLubyte, UBYTE_TO_FLOAT); + break; + case GL_BYTE: + CONVERT(GLbyte, BYTE_TO_FLOAT); + break; + default: + assert(0); + break; + } + + radeon_bo_unmap(attr->bo); + + if (mapped_named_bo) + { + ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, input->BufferObj); + } +} + +static void evergreenFixupIndexBuffer(GLcontext *ctx, const struct _mesa_index_buffer *mesa_ind_buf) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + GLvoid *src_ptr; + GLuint *out; + int i; + GLboolean mapped_named_bo = GL_FALSE; + + if (mesa_ind_buf->obj->Name && !mesa_ind_buf->obj->Pointer) + { + ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY_ARB, mesa_ind_buf->obj); + mapped_named_bo = GL_TRUE; + assert(mesa_ind_buf->obj->Pointer != NULL); + } + src_ptr = ADD_POINTERS(mesa_ind_buf->obj->Pointer, mesa_ind_buf->ptr); + + if (mesa_ind_buf->type == GL_UNSIGNED_BYTE) + { + GLuint size = sizeof(GLushort) * ((mesa_ind_buf->count + 1) & ~1); + GLubyte *in = (GLubyte *)src_ptr; + + radeonAllocDmaRegion(&context->radeon, &context->ind_buf.bo, + &context->ind_buf.bo_offset, size, 4); + + radeon_bo_map(context->ind_buf.bo, 1); + assert(context->ind_buf.bo->ptr != NULL); + out = (GLuint *)ADD_POINTERS(context->ind_buf.bo->ptr, context->ind_buf.bo_offset); + + for (i = 0; i + 1 < mesa_ind_buf->count; i += 2) + { + *out++ = in[i] | in[i + 1] << 16; + } + + if (i < mesa_ind_buf->count) + { + *out++ = in[i]; + } + + radeon_bo_unmap(context->ind_buf.bo); +#if MESA_BIG_ENDIAN + } + else + { /* if (mesa_ind_buf->type == GL_UNSIGNED_SHORT) */ + GLushort *in = (GLushort *)src_ptr; + GLuint size = sizeof(GLushort) * ((mesa_ind_buf->count + 1) & ~1); + + radeonAllocDmaRegion(&context->radeon, &context->ind_buf.bo, + &context->ind_buf.bo_offset, size, 4); + + radeon_bo_map(context->ind_buf.bo, 1); + assert(context->ind_buf.bo->ptr != NULL); + out = (GLuint *)ADD_POINTERS(context->ind_buf.bo->ptr, context->ind_buf.bo_offset); + + for (i = 0; i + 1 < mesa_ind_buf->count; i += 2) + { + *out++ = in[i] | in[i + 1] << 16; + } + + if (i < mesa_ind_buf->count) + { + *out++ = in[i]; + } + radeon_bo_unmap(context->ind_buf.bo); +#endif + } + + context->ind_buf.is_32bit = GL_FALSE; + context->ind_buf.count = mesa_ind_buf->count; + + if (mapped_named_bo) + { + ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, mesa_ind_buf->obj); + } +} + +static GLboolean evergreen_check_fallbacks(GLcontext *ctx) //same +{ + if (ctx->RenderMode != GL_RENDER) + return GL_TRUE; + + return GL_FALSE; +} + +/* start 3d, idle, cb/db flush */ +#define PRE_EMIT_STATE_BUFSZ 5 + 5 + 14 + +static GLuint evergreenPredictRenderSize(GLcontext* ctx, + const struct _mesa_prim *prim, + const struct _mesa_index_buffer *ib, + GLuint nr_prims) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + GLboolean flushed; + GLuint dwords, i; + GLuint state_size; + + dwords = PRE_EMIT_STATE_BUFSZ; + if (ib) + dwords += nr_prims * 14; + else { + for (i = 0; i < nr_prims; ++i) + { + if (prim[i].start == 0) + dwords += 10; + else if (prim[i].count > 0xffff) + dwords += prim[i].count + 10; + else + dwords += ((prim[i].count + 1) / 2) + 10; + } + } + + state_size = radeonCountStateEmitSize(&context->radeon); + flushed = rcommonEnsureCmdBufSpace(&context->radeon, + dwords + state_size, + __FUNCTION__); + if (flushed) + dwords += radeonCountStateEmitSize(&context->radeon); + else + dwords += state_size; + + radeon_print(RADEON_RENDER, RADEON_VERBOSE, "%s: total prediction size is %d.\n", __FUNCTION__, dwords); + return dwords; + +} + +static void evergreenSetupIndexBuffer(GLcontext *ctx, const struct _mesa_index_buffer *mesa_ind_buf) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + + if (!mesa_ind_buf) { + context->ind_buf.bo = NULL; + return; + } + +#if MESA_BIG_ENDIAN + if (mesa_ind_buf->type == GL_UNSIGNED_INT) +#else + if (mesa_ind_buf->type != GL_UNSIGNED_BYTE) +#endif + { + const GLvoid *src_ptr; + GLvoid *dst_ptr; + GLboolean mapped_named_bo = GL_FALSE; + + if (mesa_ind_buf->obj->Name && !mesa_ind_buf->obj->Pointer) + { + ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY_ARB, mesa_ind_buf->obj); + assert(mesa_ind_buf->obj->Pointer != NULL); + mapped_named_bo = GL_TRUE; + } + + src_ptr = ADD_POINTERS(mesa_ind_buf->obj->Pointer, mesa_ind_buf->ptr); + + const GLuint size = mesa_ind_buf->count * getTypeSize(mesa_ind_buf->type); + + radeonAllocDmaRegion(&context->radeon, &context->ind_buf.bo, + &context->ind_buf.bo_offset, size, 4); + radeon_bo_map(context->ind_buf.bo, 1); + assert(context->ind_buf.bo->ptr != NULL); + dst_ptr = ADD_POINTERS(context->ind_buf.bo->ptr, context->ind_buf.bo_offset); + + memcpy(dst_ptr, src_ptr, size); + + radeon_bo_unmap(context->ind_buf.bo); + context->ind_buf.is_32bit = (mesa_ind_buf->type == GL_UNSIGNED_INT); + context->ind_buf.count = mesa_ind_buf->count; + + if (mapped_named_bo) + { + ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, mesa_ind_buf->obj); + } + } + else + { + evergreenFixupIndexBuffer(ctx, mesa_ind_buf); + } +} + +static void evergreenAlignDataToDword(GLcontext *ctx, + const struct gl_client_array *input, + int count, + struct StreamDesc *attr) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + const int dst_stride = (input->StrideB + 3) & ~3; + const int size = getTypeSize(input->Type) * input->Size * count; + GLboolean mapped_named_bo = GL_FALSE; + + radeonAllocDmaRegion(&context->radeon, &attr->bo, &attr->bo_offset, size, 32); + + radeon_bo_map(attr->bo, 1); + + if (!input->BufferObj->Pointer) + { + ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY_ARB, input->BufferObj); + mapped_named_bo = GL_TRUE; + } + + { + GLvoid *src_ptr = ADD_POINTERS(input->BufferObj->Pointer, input->Ptr); + GLvoid *dst_ptr = ADD_POINTERS(attr->bo->ptr, attr->bo_offset); + int i; + + for (i = 0; i < count; ++i) + { + memcpy(dst_ptr, src_ptr, input->StrideB); + src_ptr += input->StrideB; + dst_ptr += dst_stride; + } + } + + radeon_bo_unmap(attr->bo); + if (mapped_named_bo) + { + ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, input->BufferObj); + } + + attr->stride = dst_stride; +} + +static void evergreenSetupStreams(GLcontext *ctx, const struct gl_client_array *input[], int count) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + GLuint stride; + int ret; + int i, index; + + EVERGREEN_STATECHANGE(context, vtx); + + for(index = 0; index < context->nNumActiveAos; index++) + { + struct radeon_aos *aos = &context->radeon.tcl.aos[index]; + i = context->stream_desc[index].element; + + stride = (input[i]->StrideB == 0) ? getTypeSize(input[i]->Type) * input[i]->Size : input[i]->StrideB; + + if (input[i]->Type == GL_DOUBLE || input[i]->Type == GL_UNSIGNED_INT || input[i]->Type == GL_INT || +#if MESA_BIG_ENDIAN + getTypeSize(input[i]->Type) != 4 || +#endif + stride < 4) + { + evergreenConvertAttrib(ctx, count, input[i], &context->stream_desc[index]); + } + else + { + if (input[i]->BufferObj->Name) + { + if (stride % 4 != 0) + { + assert(((intptr_t) input[i]->Ptr) % input[i]->StrideB == 0); + evergreenAlignDataToDword(ctx, input[i], count, &context->stream_desc[index]); + context->stream_desc[index].is_named_bo = GL_FALSE; + } + else + { + context->stream_desc[index].stride = input[i]->StrideB; + context->stream_desc[index].bo_offset = (intptr_t) input[i]->Ptr; + context->stream_desc[index].bo = get_radeon_buffer_object(input[i]->BufferObj)->bo; + context->stream_desc[index].is_named_bo = GL_TRUE; + } + } + else + { + int size; + int local_count = count; + uint32_t *dst; + + if (input[i]->StrideB == 0) + { + size = getTypeSize(input[i]->Type) * input[i]->Size; + local_count = 1; + } + else + { + size = getTypeSize(input[i]->Type) * input[i]->Size * local_count; + } + + radeonAllocDmaRegion(&context->radeon, &context->stream_desc[index].bo, + &context->stream_desc[index].bo_offset, size, 32); + + radeon_bo_map(context->stream_desc[index].bo, 1); + assert(context->stream_desc[index].bo->ptr != NULL); + + + dst = (uint32_t *)ADD_POINTERS(context->stream_desc[index].bo->ptr, + context->stream_desc[index].bo_offset); + + switch (context->stream_desc[index].dwords) + { + case 1: + radeonEmitVec4(dst, input[i]->Ptr, input[i]->StrideB, local_count); + break; + case 2: + radeonEmitVec8(dst, input[i]->Ptr, input[i]->StrideB, local_count); + break; + case 3: + radeonEmitVec12(dst, input[i]->Ptr, input[i]->StrideB, local_count); + break; + case 4: + radeonEmitVec16(dst, input[i]->Ptr, input[i]->StrideB, local_count); + break; + default: + assert(0); + break; + } + + radeon_bo_unmap(context->stream_desc[index].bo); + } + } + + aos->count = context->stream_desc[index].stride == 0 ? 1 : count; + aos->stride = context->stream_desc[index].stride / sizeof(float); + aos->components = context->stream_desc[index].dwords; + aos->bo = context->stream_desc[index].bo; + aos->offset = context->stream_desc[index].bo_offset; + + if(context->stream_desc[index].is_named_bo) + { + radeon_cs_space_add_persistent_bo(context->radeon.cmdbuf.cs, + context->stream_desc[index].bo, + RADEON_GEM_DOMAIN_GTT, 0); + } + } + + ret = radeon_cs_space_check_with_bo(context->radeon.cmdbuf.cs, + first_elem(&context->radeon.dma.reserved)->bo, + RADEON_GEM_DOMAIN_GTT, 0); +} + +static void evergreenFreeData(GLcontext *ctx) +{ + /* Need to zero tcl.aos[n].bo and tcl.elt_dma_bo + * to prevent double unref in radeonReleaseArrays + * called during context destroy + */ + context_t *context = EVERGREEN_CONTEXT(ctx); + + int i; + + for (i = 0; i < context->nNumActiveAos; i++) + { + if (!context->stream_desc[i].is_named_bo) + { + radeon_bo_unref(context->stream_desc[i].bo); + } + context->radeon.tcl.aos[i].bo = NULL; + } + + if(context->vp_Constbo != NULL) + { + radeon_bo_unref(context->vp_Constbo); + context->vp_Constbo = NULL; + } + if(context->fp_Constbo != NULL) + { + radeon_bo_unref(context->fp_Constbo); + context->fp_Constbo = NULL; + } + + if (context->ind_buf.bo != NULL) + { + radeon_bo_unref(context->ind_buf.bo); + } +} + +static GLboolean evergreenTryDrawPrims(GLcontext *ctx, + const struct gl_client_array *arrays[], + const struct _mesa_prim *prim, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLuint min_index, + GLuint max_index ) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + radeonContextPtr radeon = &context->radeon; + GLuint i, id = 0; + struct radeon_renderbuffer *rrb; + + if (ctx->NewState) + _mesa_update_state( ctx ); + + if (evergreen_check_fallbacks(ctx)) + return GL_FALSE; + + _tnl_UpdateFixedFunctionProgram(ctx); + evergreenSetVertexFormat(ctx, arrays, max_index + 1); + + + /* shaders need to be updated before buffers are validated */ + evergreenUpdateShaders(ctx); + if (!evergreenValidateBuffers(ctx)) + return GL_FALSE; + + /* always emit CB base to prevent + * lock ups on some chips. + */ + EVERGREEN_STATECHANGE(context, cb); + /* mark vtx as dirty since it changes per-draw */ + EVERGREEN_STATECHANGE(context, vtx); + + evergreenSetScissor(context); + + evergreenSetupVertexProgram(ctx); + evergreenSetupFragmentProgram(ctx); + evergreenUpdateShaderStates(ctx); + + GLuint emit_end = evergreenPredictRenderSize(ctx, prim, ib, nr_prims) + + context->radeon.cmdbuf.cs->cdw; + + /* evergreenPredictRenderSize will call radeonReleaseDmaRegions, so update VP/FP const buf after it. */ + evergreenSetupVPconstants(ctx); + evergreenSetupFPconstants(ctx); + + evergreenSetupIndexBuffer(ctx, ib); + + evergreenSetupStreams(ctx, arrays, max_index + 1); + + radeonEmitState(radeon); + + radeon_debug_add_indent(); + + for (i = 0; i < nr_prims; ++i) + { + if (context->ind_buf.bo) + evergreenRunRenderPrimitive(ctx, + prim[i].start, + prim[i].start + prim[i].count, + prim[i].mode); + else + evergreenRunRenderPrimitiveImmediate(ctx, + prim[i].start, + prim[i].start + prim[i].count, + prim[i].mode); + } + + radeon_debug_remove_indent(); + + /* Flush render op cached for last several quads. */ + /* XXX drm should handle this in fence submit */ + + //evergreeWaitForIdleClean(context); + + rrb = radeon_get_colorbuffer(&context->radeon); + if (rrb && rrb->bo) + r700SyncSurf(context, rrb->bo, 0, RADEON_GEM_DOMAIN_VRAM, + CB_ACTION_ENA_bit | (1 << (id + 6))); + + rrb = radeon_get_depthbuffer(&context->radeon); + if (rrb && rrb->bo) + r700SyncSurf(context, rrb->bo, 0, RADEON_GEM_DOMAIN_VRAM, + DB_ACTION_ENA_bit | DB_DEST_BASE_ENA_bit); + + evergreenFreeData(ctx); + + if (emit_end < context->radeon.cmdbuf.cs->cdw) + { + WARN_ONCE("Rendering was %d commands larger than predicted size." + " We might overflow command buffer.\n", context->radeon.cmdbuf.cs->cdw - emit_end); + } + + return GL_TRUE; +} + +static void evergreenDrawPrims(GLcontext *ctx, + const struct gl_client_array *arrays[], + const struct _mesa_prim *prim, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, + GLuint min_index, + GLuint max_index) +{ + GLboolean retval = GL_FALSE; + + /* This check should get folded into just the places that + * min/max index are really needed. + */ + if (!index_bounds_valid) { + vbo_get_minmax_index(ctx, prim, ib, &min_index, &max_index); + } + + if (min_index) { + vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib, min_index, max_index, evergreenDrawPrims ); + return; + } + + /* Make an attempt at drawing */ + retval = evergreenTryDrawPrims(ctx, arrays, prim, nr_prims, ib, min_index, max_index); + + /* If failed run tnl pipeline - it should take care of fallbacks */ + if (!retval) { + _swsetup_Wakeup(ctx); + _tnl_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index); + } +} + +void evergreenInitDraw(GLcontext *ctx) +{ + struct vbo_context *vbo = vbo_context(ctx); + + /* to be enabled */ + vbo->draw_prims = evergreenDrawPrims; +} + + diff --git a/src/mesa/drivers/dri/r600/evergreen_sq.h b/src/mesa/drivers/dri/r600/evergreen_sq.h new file mode 100644 index 0000000000..b1a536e76f --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_sq.h @@ -0,0 +1,735 @@ +/* + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#ifndef _EVERGREEN_SQ_H_ +#define _EVERGREEN_SQ_H_ + +enum{ +//CF + EG_CF_WORD0__ADDR_shift = 0, + EG_CF_WORD0__ADDR_mask = 0xFFFFFF, + EG_CF_WORD0__JUMPTABLE_SEL_shift = 24, + EG_CF_WORD0__JUMPTABLE_SEL_mask = 0x7 << 24, + + EG_CF_WORD1__POP_COUNT_shift = 0, //3 bits + EG_CF_WORD1__POP_COUNT_mask = 0x7, + EG_CF_WORD1__CF_CONST_shift = 3, //5 bits + EG_CF_WORD1__CF_CONST_mask = 0x1F << 3, + EG_CF_WORD1__COND_shift = 8, //2 bits + EG_CF_WORD1__COND_mask = 0x3 << 8, + EG_CF_WORD1__COUNT_shift = 10,//6 bits + EG_CF_WORD1__COUNT_mask = 0x3F << 10, + EG_CF_WORD1__reserved_shift = 16,//4 bits + EG_CF_WORD1__VPM_shift = 20,//1 bit + EG_CF_WORD1__VPM_bit = 1 << 20, + EG_CF_WORD1__EOP_shift = 21,//1 bit + EG_CF_WORD1__EOP_bit = 1 << 21, + EG_CF_WORD1__CF_INST_shift = 22,//8 bits + EG_CF_WORD1__CF_INST_mask = 0xFF << 22, + EG_CF_WORD1__WQM_shift = 30,//1 bit + EG_CF_WORD1__WQM_bit = 1 << 30, + EG_CF_WORD1__BARRIER_shift = 31,//1 bit + EG_CF_WORD1__BARRIER_bit = 1 << 31, + + EG_CF_INST_NOP = 0, + EG_CF_INST_TC = 1, + EG_CF_INST_VC = 2, + EG_CF_INST_GDS = 3, + EG_CF_INST_LOOP_START = 4, + EG_CF_INST_LOOP_END = 5, + EG_CF_INST_LOOP_START_DX10 = 6, + EG_CF_INST_LOOP_START_NO_AL = 7, + EG_CF_INST_LOOP_CONTINUE = 8, + EG_CF_INST_LOOP_BREAK = 9, + EG_CF_INST_JUMP = 10, + EG_CF_INST_PUSH = 11, + EG_CF_INST_Reserved_12 = 12, + EG_CF_INST_ELSE = 13, + EG_CF_INST_POP = 14, + EG_CF_INST_Reserved_15 = 15, + EG_CF_INST_Reserved_16 = 16, + EG_CF_INST_Reserved_17 = 17, + EG_CF_INST_CALL = 18, + EG_CF_INST_CALL_FS = 19, + EG_CF_INST_RETURN = 20, + EG_CF_INST_EMIT_VERTEX = 21, + EG_CF_INST_EMIT_CUT_VERTEX = 22, + EG_CF_INST_CUT_VERTEX = 23, + EG_CF_INST_KILL = 24, + EG_CF_INST_Reserved_25 = 25, + EG_CF_INST_WAIT_ACK = 26, + EG_CF_INST_TC_ACK = 27, + EG_CF_INST_VC_ACK = 28, + EG_CF_INST_JUMPTABLE = 29, + EG_CF_INST_GLOBAL_WAVE_SYNC = 30, + EG_CF_INST_HALT = 31, + +//TEX + EG_TEX_WORD0__TEX_INST_shift = 0, //5 bits + EG_TEX_WORD0__TEX_INST_mask = 0x1F, + EG_TEX_WORD0__INST_MOD_shift = 5, //2 bits + EG_TEX_WORD0__INST_MOD_mask = 0x3 << 5, + EG_TEX_WORD0__FWQ_shift = 7, //1 bit + EG_TEX_WORD0__FWQ_bit = 1 << 7, + EG_TEX_WORD0__RESOURCE_ID_shift = 8, //8 bits + EG_TEX_WORD0__RESOURCE_ID_mask = 0xFF << 8, + EG_TEX_WORD0__SRC_GPR_shift = 16,//7 bits + EG_TEX_WORD0__SRC_GPR_mask = 0x7F << 16, + EG_TEX_WORD0__SRC_REL_shift = 23,//1 bit + EG_TEX_WORD0__SRC_REL_bit = 1 << 23, + EG_TEX_WORD0__ALT_CONST_shift = 24,//1 bit + EG_TEX_WORD0__ALT_CONST_bit = 1 << 24, + EG_TEX_WORD0__RIM_shift = 25,//2 bits + EG_TEX_WORD0__RIM_mask = 0x3 << 25, + EG_TEX_WORD0__SIM_shift = 27,//2 bits + EG_TEX_WORD0__SIM_mask = 0x3 << 27, + EG_TEX_WORD0__Reserved_shift = 29,//3 bits + EG_TEX_WORD0__Reserved_mask = 0x7 << 29, + + EG_TEX_INST_Reserved_0 = 0, + EG_TEX_INST_Reserved_1 = 1, + EG_TEX_INST_Reserved_2 = 2, + EG_TEX_INST_LD = 3, + EG_TEX_INST_GET_TEXTURE_RESINFO = 4, + EG_TEX_INST_GET_NUMBER_OF_SAMPLES= 5, + EG_TEX_INST_GET_COMP_TEX_LOD = 6, + EG_TEX_INST_GET_GRADIENTS_H = 7, + EG_TEX_INST_GET_GRADIENTS_V = 8, + EG_TEX_INST_SET_TEXTURE_OFFSETS = 9, + EG_TEX_INST_KEEP_GRADIENTS = 10, + EG_TEX_INST_SET_GRADIENTS_H = 11, + EG_TEX_INST_SET_GRADIENTS_V = 12, + EG_TEX_INST_Reserved_13 = 13, + EG_TEX_INST_Reserved_14 = 14, + EG_TEX_INST_Reserved_15 = 15, + EG_TEX_INST_SAMPLE = 16, + EG_TEX_INST_SAMPLE_L = 17, + EG_TEX_INST_SAMPLE_LB = 18, + EG_TEX_INST_SAMPLE_LZ = 19, + EG_TEX_INST_SAMPLE_G = 20, + EG_TEX_INST_GATHER4 = 21, + EG_TEX_INST_SAMPLE_G_LB = 22, + EG_TEX_INST_GATHER4_O = 23, + EG_TEX_INST_SAMPLE_C = 24, + EG_TEX_INST_SAMPLE_C_L = 25, + EG_TEX_INST_SAMPLE_C_LB = 26, + EG_TEX_INST_SAMPLE_C_LZ = 27, + EG_TEX_INST_SAMPLE_C_G = 28, + EG_TEX_INST_GATHER4_C = 29, + EG_TEX_INST_SAMPLE_C_G_LB = 30, + EG_TEX_INST_GATHER4_C_O = 31, + + EG_TEX_WORD1__DST_GPR_shift = 0, //7 bits + EG_TEX_WORD1__DST_GPR_mask = 0x7F, + EG_TEX_WORD1__DST_REL_shift = 7, //1 bit + EG_TEX_WORD1__DST_REL_bit = 1 << 7, + EG_TEX_WORD1__Reserved_shift = 8, //1 bit + EG_TEX_WORD1__Reserved_bit = 1 << 8, + EG_TEX_WORD1__DST_SEL_X_shift = 9, //3 bits + EG_TEX_WORD1__DST_SEL_X_mask = 0x7 << 9, + EG_TEX_WORD1__DST_SEL_Y_shift = 12,//3 bits + EG_TEX_WORD1__DST_SEL_Y_mask = 0x7 << 12, + EG_TEX_WORD1__DST_SEL_Z_shift = 15,//3 bits + EG_TEX_WORD1__DST_SEL_Z_mask = 0x7 << 15, + EG_TEX_WORD1__DST_SEL_W_shift = 18,//3 bits + EG_TEX_WORD1__DST_SEL_W_mask = 0x7 << 18, + EG_TEX_WORD1__LOD_BIAS_shift = 21,//7 bits + EG_TEX_WORD1__LOD_BIAS_mask = 0x7F << 21, + EG_TEX_WORD1__COORD_TYPE_X_shift = 28,//1 bit + EG_TEX_WORD1__COORD_TYPE_X_bit = 1 << 28, + EG_TEX_WORD1__COORD_TYPE_Y_shift = 29,//1 bit + EG_TEX_WORD1__COORD_TYPE_Y_bit = 1 << 29, + EG_TEX_WORD1__COORD_TYPE_Z_shift = 30,//1 bit + EG_TEX_WORD1__COORD_TYPE_Z_bit = 1 << 30, + EG_TEX_WORD1__COORD_TYPE_W_shift = 31,//1 bit + EG_TEX_WORD1__COORD_TYPE_W_bit = 1 << 31, + + EG_TEX_WORD2__OFFSET_X_shift = 0, //5 bits + EG_TEX_WORD2__OFFSET_X_mask = 0x1F, + EG_TEX_WORD2__OFFSET_Y_shift = 5, //5 bits + EG_TEX_WORD2__OFFSET_Y_mask = 0x1F << 5, + EG_TEX_WORD2__OFFSET_Z_shift = 10,//5 bits + EG_TEX_WORD2__OFFSET_Z_mask = 0x1F << 10, + EG_TEX_WORD2__SAMPLER_ID_shift = 15,//5 bits + EG_TEX_WORD2__SAMPLER_ID_mask = 0x1F << 15, + EG_TEX_WORD2__SRC_SEL_X_shift = 20,//3 bits + EG_TEX_WORD2__SRC_SEL_X_mask = 0x7 << 20, + EG_TEX_WORD2__SRC_SEL_Y_shift = 23,//3 bits + EG_TEX_WORD2__SRC_SEL_Y_mask = 0x7 << 23, + EG_TEX_WORD2__SRC_SEL_Z_shift = 26,//3 bits + EG_TEX_WORD2__SRC_SEL_Z_mask = 0x7 << 26, + EG_TEX_WORD2__SRC_SEL_W_shift = 29,//3 bits + EG_TEX_WORD2__SRC_SEL_W_mask = 0x7 << 29, + +//VTX + EG_VTX_WORD0__VC_INST_shift = 0, //5 bits + EG_VTX_WORD0__VC_INST_mask = 0x1F, + EG_VTX_WORD0__FETCH_TYPE_shift = 5, //2 bits + EG_VTX_WORD0__FETCH_TYPE_mask = 0x3 << 5, + EG_VTX_WORD0__FWQ_shift = 7, //1 bit + EG_VTX_WORD0__FWQ_bit = 1 << 7, + EG_VTX_WORD0__BUFFER_ID_shift = 8, //8 bits + EG_VTX_WORD0__BUFFER_ID_mask = 0xFF << 8, + EG_VTX_WORD0__SRC_GPR_shift = 16,//7 bits + EG_VTX_WORD0__SRC_GPR_mask = 0x7F << 16, + EG_VTX_WORD0__SRC_REL_shift = 23,//1 bit + EG_VTX_WORD0__SRC_REL_bit = 1 << 23, + EG_VTX_WORD0__SRC_SEL_X_shift = 24,//2 bits + EG_VTX_WORD0__SRC_SEL_X_mask = 0x3 << 24, + EG_VTX_WORD0__MFC_shift = 26,//6 bits + EG_VTX_WORD0__MFC_mask = 0x3F << 26, + + EG_VC_INST_FETCH = 0, + EG_VC_INST_SEMANTIC = 1, + EG_VC_INST_Reserved_2 = 2, + EG_VC_INST_Reserved_3 = 3, + EG_VC_INST_Reserved_4 = 4, + EG_VC_INST_Reserved_5 = 5, + EG_VC_INST_Reserved_6 = 6, + EG_VC_INST_Reserved_7 = 7, + EG_VC_INST_Reserved_8 = 8, + EG_VC_INST_Reserved_9 = 9, + EG_VC_INST_Reserved_10 = 10, + EG_VC_INST_Reserved_11 = 11, + EG_VC_INST_Reserved_12 = 12, + EG_VC_INST_Reserved_13 = 13, + EG_VC_INST_GET_BUFFER_RESINFO = 14, + + EG_VTX_FETCH_VERTEX_DATA = 0, + EG_VTX_FETCH_INSTANCE_DATA = 1, + EG_VTX_FETCH_NO_INDEX_OFFSET = 2, + + EG_VTX_WORD1_SEM__SEMANTIC_ID_shift = 0, //8 bits + EG_VTX_WORD1_SEM__SEMANTIC_ID_mask = 0xFF, + EG_VTX_WORD1_GPR__DST_GPR_shift = 0, //7 bits + EG_VTX_WORD1_GPR__DST_GPR_mask = 0x7F, + EG_VTX_WORD1_GPR__DST_REL_shift = 7, //1 bit + EG_VTX_WORD1_GPR__DST_REL_bit = 1 << 7, + EG_VTX_WORD1__Reserved_shift = 8, //1 bit + EG_VTX_WORD1__Reserved_bit = 1 << 8, + EG_VTX_WORD1__DST_SEL_X_shift = 9, //3 bits + EG_VTX_WORD1__DST_SEL_X_mask = 0x7 << 9, + EG_VTX_WORD1__DST_SEL_Y_shift = 12,//3 bits + EG_VTX_WORD1__DST_SEL_Y_mask = 0x7 << 12, + EG_VTX_WORD1__DST_SEL_Z_shift = 15,//3 bits + EG_VTX_WORD1__DST_SEL_Z_mask = 0x7 << 15, + EG_VTX_WORD1__DST_SEL_W_shift = 18,//3 bits + EG_VTX_WORD1__DST_SEL_W_mask = 0x7 << 18, + EG_VTX_WORD1__UCF_shift = 21,//1 bit + EG_VTX_WORD1__UCF_bit = 1 << 21, + EG_VTX_WORD1__DATA_FORMAT_shift = 22,//6 bits + EG_VTX_WORD1__DATA_FORMAT_mask = 0x3F << 22, + EG_VTX_WORD1__NFA_shift = 28,//2 bits + EG_VTX_WORD1__NFA_mask = 0x3 << 28, + EG_VTX_WORD1__FCA_shift = 30,//1 bit + EG_VTX_WORD1__FCA_bit = 1 << 30, + EG_VTX_WORD1__SMA_shift = 31,//1 bit + EG_VTX_WORD1__SMA_bit = 1 << 31, + + EG_VTX_WORD2__OFFSET_shift = 0, //16 bits + EG_VTX_WORD2__OFFSET_mask = 0xFFFF, + EG_VTX_WORD2__ENDIAN_SWAP_shift = 16,//2 bits + EG_VTX_WORD2__ENDIAN_SWAP_mask = 0x3 << 16, + EG_VTX_WORD2__CBNS_shift = 18,//1 bit + EG_VTX_WORD2__CBNS_bit = 1 << 18, + EG_VTX_WORD2__MEGA_FETCH_shift = 19,//1 bit + EG_VTX_WORD2__MEGA_FETCH_mask = 1 << 19, + EG_VTX_WORD2__ALT_CONST_shift = 20,//1 bit + EG_VTX_WORD2__ALT_CONST_mask = 1 << 20, + EG_VTX_WORD2__BIM_shift = 21,//2 bits + EG_VTX_WORD2__BIM_mask = 0x3 << 21, + EG_VTX_WORD2__Reserved_shift = 23,//9 bits + EG_VTX_WORD2__Reserved_mask = 0x1FF << 23, + +//CF_ALU + EG_CF_ALU_WORD0__ADDR_shift = 0, //22 bits + EG_CF_ALU_WORD0__ADDR_mask = 0x3FFFFF, + EG_CF_ALU_WORD0__KCACHE_BANK0_shift = 22,//4 bits + EG_CF_ALU_WORD0__KCACHE_BANK0_mask = 0xF << 22, + EG_CF_ALU_WORD0__KCACHE_BANK1_shift = 26,//4 bits + EG_CF_ALU_WORD0__KCACHE_BANK1_mask = 0xF << 26, + EG_CF_ALU_WORD0__KCACHE_MODE0_shift = 30,//2 bits + EG_CF_ALU_WORD0__KCACHE_MODE0_mask = 0x3 << 30, + + EG_CF_ALU_WORD1__KCACHE_MODE1_shift = 0, //2 bits + EG_CF_ALU_WORD1__KCACHE_MODE1_mask = 0x3, + EG_CF_ALU_WORD1__KCACHE_ADDR0_shift = 2, //8 bits + EG_CF_ALU_WORD1__KCACHE_ADDR0_mask = 0xFF << 2, + EG_CF_ALU_WORD1__KCACHE_ADDR1_shift = 10, //8 bits + EG_CF_ALU_WORD1__KCACHE_ADDR1_mask = 0xFF << 10, + EG_CF_ALU_WORD1__COUNT_shift = 18, //7 bits + EG_CF_ALU_WORD1__COUNT_mask = 0x7F << 18, + EG_CF_ALU_WORD1__ALT_CONST_shift = 25, //1 bit + EG_CF_ALU_WORD1__ALT_CONST_bit = 1 << 25, + EG_CF_ALU_WORD1__CF_INST_shift = 26, //4 bits + EG_CF_ALU_WORD1__CF_INST_mask = 0xF << 26, + EG_CF_ALU_WORD1__WQM_shift = 30, //1 bit + EG_CF_ALU_WORD1__WQM_bit = 1 << 30, + EG_CF_ALU_WORD1__BARRIER_shift = 31, //1 bit + EG_CF_ALU_WORD1__BARRIER_bit = 1 << 31, + + EG_CF_INST_ALU = 8, + EG_CF_INST_ALU_PUSH_BEFORE = 9, + EG_CF_INST_ALU_POP_AFTER = 10, + EG_CF_INST_ALU_POP2_AFTER = 11, + EG_CF_INST_ALU_EXTENDED = 12, + EG_CF_INST_ALU_CONTINUE = 13, + EG_CF_INST_ALU_BREAK = 14, + EG_CF_INST_ALU_ELSE_AFTER = 15, + + EG_CF_ALU_WORD0_EXT__Reserved0_shift = 0, //4 bits + EG_CF_ALU_WORD0_EXT__Reserved0_mask = 0xF, + EG_CF_ALU_WORD0_EXT__KBIM0_shift = 4, //2 bits + EG_CF_ALU_WORD0_EXT__KBIM0_mask = 0x3 << 4, + EG_CF_ALU_WORD0_EXT__KBIM1_shift = 6, //2 bits + EG_CF_ALU_WORD0_EXT__KBIM1_mask = 0x3 << 6, + EG_CF_ALU_WORD0_EXT__KBIM2_shift = 8, //2 bits + EG_CF_ALU_WORD0_EXT__KBIM2_mask = 0x3 << 8, + EG_CF_ALU_WORD0_EXT__KBIM3_shift = 10,//2 bits + EG_CF_ALU_WORD0_EXT__KBIM3_mask = 0x3 << 10, + EG_CF_ALU_WORD0_EXT__Reserved12_shift = 12,//10 bits + EG_CF_ALU_WORD0_EXT__Reserved12_mask = 0x3FF << 12, + EG_CF_ALU_WORD0_EXT__KCACHE_BANK2_shift = 22,//4 bits + EG_CF_ALU_WORD0_EXT__KCACHE_BANK2_mask = 0xF << 22, + EG_CF_ALU_WORD0_EXT__KCACHE_BANK3_shift = 26,//4 bits + EG_CF_ALU_WORD0_EXT__KCACHE_BANK3_mask = 0xF << 26, + EG_CF_ALU_WORD0_EXT__KCACHE_MODE2_shift = 30,//2 btis + EG_CF_ALU_WORD0_EXT__KCACHE_MODE2_mask = 0x3 << 30, + + EG_CF_ALU_WORD1_EXT__KCACHE_MODE3_shift = 0, //2 bits + EG_CF_ALU_WORD1_EXT__KCACHE_MODE3_mask = 0x3, + EG_CF_ALU_WORD1_EXT__KCACHE_ADDR2_shift = 2, //8 bits + EG_CF_ALU_WORD1_EXT__KCACHE_ADDR2_mask = 0xFF << 2, + EG_CF_ALU_WORD1_EXT__KCACHE_ADDR3_shift = 10, //8 bits + EG_CF_ALU_WORD1_EXT__KCACHE_ADDR3_mask = 0xFF << 10, + EG_CF_ALU_WORD1_EXT__Reserved18_shift = 18, //8 bits + EG_CF_ALU_WORD1_EXT__Reserved18_mask = 0xFF << 18, + EG_CF_ALU_WORD1_EXT__CF_INST_shift = 26, //4 bits + EG_CF_ALU_WORD1_EXT__CF_INST_mask = 0xF << 26, + EG_CF_ALU_WORD1_EXT__Reserved30_shift = 30, //1 bit + EG_CF_ALU_WORD1_EXT__Reserved30_bit = 1 << 30, + EG_CF_ALU_WORD1_EXT__BARRIER_shift = 31, //1 bit + EG_CF_ALU_WORD1_EXT__BARRIER_bit = 1 << 31, + +//ALU + EG_ALU_WORD0__SRC0_SEL_shift = 0, //9 bits + EG_ALU_WORD0__SRC0_SEL_mask = 0x1FF, + EG_ALU_WORD0__SRC1_SEL_shift = 13,//9 bits + EG_ALU_WORD0__SRC1_SEL_mask = 0x1FF << 13, + EG_ALU_WORD0__SRC0_REL_shift = 9, //1 bit + EG_ALU_WORD0__SRC0_REL_bit = 1 << 9, + EG_ALU_WORD0__SRC1_REL_shift = 22,//1 bit + EG_ALU_WORD0__SRC1_REL_bit = 1 << 22, + EG_ALU_WORD0__SRC0_CHAN_shift = 10,//2 bits + EG_ALU_WORD0__SRC0_CHAN_mask = 0x3 << 10, + EG_ALU_WORD0__SRC1_CHAN_shift = 23,//2 bits + EG_ALU_WORD0__SRC1_CHAN_mask = 0x3 << 23, + EG_ALU_WORD0__SRC0_NEG_shift = 12,//1 bit + EG_ALU_WORD0__SRC0_NEG_bit = 1 << 12, + EG_ALU_WORD0__SRC1_NEG_shift = 25,//1 bit + EG_ALU_WORD0__SRC1_NEG_bit = 1 << 25, + EG_ALU_WORD0__INDEX_MODE_shift = 26,//3 bits + EG_ALU_WORD0__INDEX_MODE_mask = 0x7 << 26, + EG_ALU_WORD0__PRED_SEL_shift = 29,//2 bits + EG_ALU_WORD0__PRED_SEL_mask = 0x3 << 29, + EG_ALU_WORD0__LAST_shift = 31,//1 bit + EG_ALU_WORD0__LAST_bit = 1 << 31, + + EG_ALU_WORD1_OP2__SRC0_ABS_shift = 0, //1 bit + EG_ALU_WORD1_OP2__SRC0_ABS_bit = 1, + EG_ALU_WORD1_OP2__SRC1_ABS_shift = 1, //1 bit + EG_ALU_WORD1_OP2__SRC1_ABS_bit = 1 << 1, + EG_ALU_WORD1_OP2__UEM_shift = 2, //1 bit + EG_ALU_WORD1_OP2__UEM_bit = 1 << 2, + EG_ALU_WORD1_OP2__UPDATE_PRED_shift = 3, //1 bit + EG_ALU_WORD1_OP2__UPDATE_PRED_bit = 1 << 3, + EG_ALU_WORD1_OP2__WRITE_MASK_shift = 4, //1 bit + EG_ALU_WORD1_OP2__WRITE_MASK_bit = 1 << 4, + EG_ALU_WORD1_OP2__OMOD_shift = 5, //2 bits + EG_ALU_WORD1_OP2__OMOD_mask = 0x3 << 5, + EG_ALU_WORD1_OP2__ALU_INST_shift = 7, //11 bits + EG_ALU_WORD1_OP2__ALU_INST_mask = 0x7FF << 7, + + EG_ALU_WORD1__BANK_SWIZZLE_shift = 18,//3 bits + EG_ALU_WORD1__BANK_SWIZZLE_mask = 0x7 << 18, + EG_ALU_WORD1__DST_GPR_shift = 21,//7 bits + EG_ALU_WORD1__DST_GPR_mask = 0x7F << 21, + EG_ALU_WORD1__DST_REL_shift = 28,//1 bit + EG_ALU_WORD1__DST_REL_mask = 1 << 28, + EG_ALU_WORD1__DST_CHAN_shift = 29,//2 bits + EG_ALU_WORD1__DST_CHAN_mask = 0x3 << 29, + EG_ALU_WORD1__CLAMP_shift = 31,//1 bits + EG_ALU_WORD1__CLAMP_mask = 1 << 31, + + EG_ALU_WORD1_OP3__SRC2_SEL_shift = 0, //9 bits + EG_ALU_WORD1_OP3__SRC2_SEL_mask = 0x1FF, + EG_ALU_WORD1_OP3__SRC2_REL_shift = 9, //1 bit + EG_ALU_WORD1_OP3__SRC2_REL_bit = 1 << 9, + EG_ALU_WORD1_OP3__SRC2_CHAN_shift = 10,//2 bits + EG_ALU_WORD1_OP3__SRC2_CHAN_mask = 0x3 << 10, + EG_ALU_WORD1_OP3__SRC2_NEG_shift = 12,//1 bit + EG_ALU_WORD1_OP3__SRC2_NEG_bit = 1 << 12, + EG_ALU_WORD1_OP3__ALU_INST_shift = 13,//5 bits + EG_ALU_WORD1_OP3__ALU_INST_mask = 0x1F << 13, + + EG_OP3_INST_BFE_UINT = 4, + EG_OP3_INST_BFE_INT = 5, + EG_OP3_INST_BFI_INT = 6, + EG_OP3_INST_FMA = 7, + EG_OP3_INST_CNDNE_64 = 9, + EG_OP3_INST_FMA_64 = 10, + EG_OP3_INST_LERP_UINT = 11, + EG_OP3_INST_BIT_ALIGN_INT = 12, + EG_OP3_INST_BYTE_ALIGN_INT = 13, + EG_OP3_INST_SAD_ACCUM_UINT = 14, + EG_OP3_INST_SAD_ACCUM_HI_UINT = 15, + EG_OP3_INST_MULADD_UINT24 = 16, + EG_OP3_INST_LDS_IDX_OP = 17, + EG_OP3_INST_MULADD = 20, + EG_OP3_INST_MULADD_M2 = 21, + EG_OP3_INST_MULADD_M4 = 22, + EG_OP3_INST_MULADD_D2 = 23, + EG_OP3_INST_MULADD_IEEE = 24, + EG_OP3_INST_CNDE = 25, + EG_OP3_INST_CNDGT = 26, + EG_OP3_INST_CNDGE = 27, + EG_OP3_INST_CNDE_INT = 28, + EG_OP3_INST_CMNDGT_INT = 29, + EG_OP3_INST_CMNDGE_INT = 30, + EG_OP3_INST_MUL_LIT = 31, + + EG_OP2_INST_ADD = 0, + EG_OP2_INST_MUL = 1, + EG_OP2_INST_MUL_IEEE = 2, + EG_OP2_INST_MAX = 3, + EG_OP2_INST_MIN = 4, + EG_OP2_INST_MAX_DX10 = 5, + EG_OP2_INST_MIN_DX10 = 6, + EG_OP2_INST_SETE = 8, + EG_OP2_INST_SETGT = 9, + EG_OP2_INST_SETGE = 10, + EG_OP2_INST_SETNE = 11, + EG_OP2_INST_SETE_DX10 = 12, + EG_OP2_INST_SETGT_DX10 = 13, + EG_OP2_INST_SETGE_DX10 = 14, + EG_OP2_INST_SETNE_DX10 = 15, + EG_OP2_INST_FRACT = 16, + EG_OP2_INST_TRUNC = 17, + EG_OP2_INST_CEIL = 18, + EG_OP2_INST_RNDNE = 19, + EG_OP2_INST_FLOOR = 20, + EG_OP2_INST_ASHR_INT = 21, + EG_OP2_INST_LSHR_INT = 22, + EG_OP2_INST_LSHL_INT = 23, + EG_OP2_INST_MOV = 25, + EG_OP2_INST_NOP = 26, + EG_OP2_INST_MUL_64 = 27, + EG_OP2_INST_FLT64_TO_FLT32 = 28, + EG_OP2_INST_FLT32_TO_FLT64 = 29, + EG_OP2_INST_PRED_SETGT_UINT = 30, + EG_OP2_INST_PRED_SETGE_UINT = 31, + EG_OP2_INST_PRED_SETE = 32, + EG_OP2_INST_PRED_SETGT = 33, + EG_OP2_INST_PRED_SETGE = 34, + EG_OP2_INST_PRED_SETNE = 35, + EG_OP2_INST_PRED_SET_INV = 36, + EG_OP2_INST_PRED_SET_POP = 37, + EG_OP2_INST_PRED_SET_CLR = 38, + EG_OP2_INST_PRED_SET_RESTORE = 39, + EG_OP2_INST_PRED_SETE_PUSH = 40, + EG_OP2_INST_PRED_SETGT_PUSH = 41, + EG_OP2_INST_PRED_SETGE_PUSH = 42, + EG_OP2_INST_PRED_SETNE_PUSH = 43, + EG_OP2_INST_KILLE = 44, + EG_OP2_INST_KILLGT = 45, + EG_OP2_INST_KILLGE = 46, + EG_OP2_INST_KILLNE = 47, + EG_OP2_INST_AND_INT = 48, + EG_OP2_INST_OR_INT = 49, + EG_OP2_INST_XOR_INT = 50, + EG_OP2_INST_NOT_INT = 51, + EG_OP2_INST_ADD_INT = 52, + EG_OP2_INST_SUB_INT = 53, + EG_OP2_INST_MAX_INT = 54, + EG_OP2_INST_MIN_INT = 55, + EG_OP2_INST_MAX_UINT = 56, + EG_OP2_INST_MIN_UINT = 57, + EG_OP2_INST_SETE_INT = 58, + EG_OP2_INST_SETGT_INT = 59, + EG_OP2_INST_SETGE_INT = 60, + EG_OP2_INST_SETNE_INT = 61, + EG_OP2_INST_SETGT_UINT = 62, + EG_OP2_INST_SETGE_UINT = 63, + EG_OP2_INST_KILLGT_UINT = 64, + EG_OP2_INST_KILLGE_UINT = 65, + EG_OP2_INST_PREDE_INT = 66, + EG_OP2_INST_PRED_SETGT_INT = 67, + EG_OP2_INST_PRED_SETGE_INT = 68, + EG_OP2_INST_PRED_SETNE_INT = 69, + EG_OP2_INST_KILLE_INT = 70, + EG_OP2_INST_KILLGT_INT = 71, + EG_OP2_INST_KILLGE_INT = 72, + EG_OP2_INST_KILLNE_INT = 73, + EG_OP2_INST_PRED_SETE_PUSH_INT = 74, + EG_OP2_INST_PRED_SETGT_PUSH_INT = 75, + EG_OP2_INST_PRED_SETGE_PUSH_INT = 76, + EG_OP2_INST_PRED_SETNE_PUSH_INT = 77, + EG_OP2_INST_PRED_SETLT_PUSH_INT = 78, + EG_OP2_INST_PRED_SETLE_PUSH_INT = 79, + EG_OP2_INST_FLT_TO_INT = 80, + EG_OP2_INST_BFREV_INT = 81, + EG_OP2_INST_ADDC_UINT = 82, + EG_OP2_INST_SUBB_UINT = 83, + EG_OP2_INST_GROUP_BARRIER = 84, + EG_OP2_INST_GROUP_SEQ_BEGIN = 85, + EG_OP2_INST_GROUP_SEQ_END = 86, + EG_OP2_INST_SET_MODE = 87, + EG_OP2_INST_SET_CF_IDX0 = 88, + EG_OP2_INST_SET_CF_IDX1 = 89, + EG_OP2_INST_SET_LDS_SIZE = 90, + EG_OP2_INST_EXP_IEEE = 129, + EG_OP2_INST_LOG_CLAMPED = 130, + EG_OP2_INST_LOG_IEEE = 131, + EG_OP2_INST_RECIP_CLAMPED = 132, + EG_OP2_INST_RECIP_FF = 133, + EG_OP2_INST_RECIP_IEEE = 134, + EG_OP2_INST_RECIPSQRT_CLAMPED = 135, + EG_OP2_INST_RECIPSQRT_FF = 136, + EG_OP2_INST_RECIPSQRT_IEEE = 137, + EG_OP2_INST_SQRT_IEEE = 138, + EG_OP2_INST_SIN = 141, + EG_OP2_INST_COS = 142, + EG_OP2_INST_MULLO_INT = 143, + EG_OP2_INST_MULHI_INT = 144, + EG_OP2_INST_MULLO_UINT = 145, + EG_OP2_INST_MULHI_UINT = 146, + EG_OP2_INST_RECIP_INT = 147, + EG_OP2_INST_RECIP_UINT = 148, + EG_OP2_INST_RECIP_64 = 149, + EG_OP2_INST_RECIP_CLAMPED_64 = 150, + EG_OP2_INST_RECIPSQRT_64 = 151, + EG_OP2_INST_RECIPSQRT_CLAMPED_64 = 152, + EG_OP2_INST_SQRT_64 = 153, + EG_OP2_INST_FLT_TO_UINT = 154, + EG_OP2_INST_INT_TO_FLT = 155, + EG_OP2_INST_UINT_TO_FLT = 156, + EG_OP2_INST_BFM_INT = 160, + EG_OP2_INST_FLT32_TO_FLT16 = 162, + EG_OP2_INST_FLT16_TO_FLT32 = 163, + EG_OP2_INST_UBYTE0_FLT = 164, + EG_OP2_INST_UBYTE1_FLT = 165, + EG_OP2_INST_UBYTE2_FLT = 166, + EG_OP2_INST_UBYTE3_FLT = 167, + EG_OP2_INST_BCNT_INT = 170, + EG_OP2_INST_FFBH_UINT = 171, + EG_OP2_INST_FFBL_INT = 172, + EG_OP2_INST_FFBH_INT = 173, + EG_OP2_INST_FLT_TO_UINT4 = 174, + EG_OP2_INST_DOT_IEEE = 175, + EG_OP2_INST_FLT_TO_INT_RPI = 176, + EG_OP2_INST_FLT_TO_INT_FLOOR = 177, + EG_OP2_INST_MULHI_UINT24 = 178, + EG_OP2_INST_MBCNT_32HI_INT = 179, + EG_OP2_INST_OFFSET_TO_FLT = 180, + EG_OP2_INST_MUL_UINT24 = 181, + EG_OP2_INST_BCNT_ACCUM_PREV_INT = 182, + EG_OP2_INST_MBCNT_32LO_ACCUM_PREV_INT = 183, + EG_OP2_INST_SETE_64 = 184, + EG_OP2_INST_SETNE_64 = 185, + EG_OP2_INST_SETGT_64 = 186, + EG_OP2_INST_SETGE_64 = 187, + EG_OP2_INST_MIN_64 = 188, + EG_OP2_INST_MAX_64 = 189, + EG_OP2_INST_DOT4 = 190, + EG_OP2_INST_DOT4_IEEE = 191, + EG_OP2_INST_CUBE = 192, + EG_OP2_INST_MAX4 = 193, + EG_OP2_INST_FREXP_64 = 196, + EG_OP2_INST_LDEXP_64 = 197, + EG_OP2_INST_FRACT_64 = 198, + EG_OP2_INST_PRED_SETGT_64 = 199, + EG_OP2_INST_PRED_SETE_64 = 200, + EG_OP2_INST_PRED_SETGE_64 = 201, + EG_OP2_INST_MUL_64_2 = 202, //same as prev? + EG_OP2_INST_ADD_64 = 203, + EG_OP2_INST_MOVA_INT = 204, + EG_OP2_INST_FLT64_TO_FLT32_2 = 205, //same as prev? + EG_OP2_INST_FLT32_TO_FLT64_2 = 206, //same as prev? + EG_OP2_INST_SAD_ACCUM_PREV_UINT = 207, + EG_OP2_INST_DOT = 208, + EG_OP2_INST_MUL_PREV = 209, + EG_OP2_INST_MUL_IEEE_PREV = 210, + EG_OP2_INST_ADD_PREV = 211, + EG_OP2_INST_MULADD_PREV = 212, + EG_OP2_INST_MULADD_IEEE_PREV = 213, + EG_OP2_INST_INTERP_XY = 214, + EG_OP2_INST_INTERP_ZW = 215, + EG_OP2_INST_INTERP_X = 216, + EG_OP2_INST_INTERP_Z = 217, + EG_OP2_INST_STORE_FLAGS = 218, + EG_OP2_INST_LOAD_STORE_FLAGS = 219, + EG_OP2_INST_LDS_1A = 220, + EG_OP2_INST_LDS_1A1D = 221, + EG_OP2_INST_LDS_2A = 223, + EG_OP2_INST_INTERP_LOAD_P0 = 224, + EG_OP2_INST_INTERP_LOAD_P10 = 225, + EG_OP2_INST_INTERP_LOAD_P20 = 226, + + EG_SRC_SEL__GPR_start = 0, + EG_SRC_SEL__GPR_end = 127, + EG_SRC_SEL__KCONST_BANK0_start = 128, + EG_SRC_SEL__KCONST_BANK0_end = 159, + EG_SRC_SEL__KCONST_BANK1_start = 160, + EG_SRC_SEL__KCONST_BANK1_end = 191, + EG_SRC_SEL__INLINE_satrt = 192, + EG_SRC_SEL__INLINE_end = 255, + EG_SRC_SEL__KCONST_BANK2_start = 256, + EG_SRC_SEL__KCONST_BANK2_end = 287, + EG_SRC_SEL__KCONST_BANK3_start = 288, + EG_SRC_SEL__KCONST_BANK3_end = 319, + EG_SRC_SEL__ALU_SRC_LDS_OQ_A = 219, + EG_SRC_SEL__ALU_SRC_LDS_OQ_B = 220, + EG_SRC_SEL__ALU_SRC_LDS_OQ_A_POP = 221, + EG_SRC_SEL__ALU_SRC_LDS_OQ_B_POP = 222, + EG_SRC_SEL__ALU_SRC_LDS_DIRECT_A = 223, + EG_SRC_SEL__ALU_SRC_LDS_DIRECT_B = 224, + EG_SRC_SEL__ALU_SRC_TIME_HI = 227, + EG_SRC_SEL__ALU_SRC_TIME_LO = 228, + EG_SRC_SEL__ALU_SRC_MASK_HI = 229, + EG_SRC_SEL__ALU_SRC_MASK_LO = 230, + EG_SRC_SEL__ALU_SRC_HW_WAVE_ID = 231, + EG_SRC_SEL__ALU_SRC_SIMD_ID = 232, + EG_SRC_SEL__ALU_SRC_SE_ID = 233, + EG_SRC_SEL__ALU_SRC_HW_THREADGRP_ID = 234, + EG_SRC_SEL__ALU_SRC_WAVE_ID_IN_GRP = 235, + EG_SRC_SEL__ALU_SRC_NUM_THREADGRP_WAVES = 236, + EG_SRC_SEL__ALU_SRC_HW_ALU_ODD = 237, + EG_SRC_SEL__ALU_SRC_LOOP_IDX = 238, + EG_SRC_SEL__ALU_SRC_PARAM_BASE_ADDR = 240, + EG_SRC_SEL__ALU_SRC_NEW_PRIM_MASK = 241, + EG_SRC_SEL__ALU_SRC_PRIM_MASK_HI = 242, + EG_SRC_SEL__ALU_SRC_PRIM_MASK_LO = 243, + EG_SRC_SEL__ALU_SRC_1_DBL_L = 244, + EG_SRC_SEL__ALU_SRC_1_DBL_M = 245, + EG_SRC_SEL__ALU_SRC_0_5_DBL_L = 246, + EG_SRC_SEL__ALU_SRC_0_5_DBL_M = 247, + EG_SRC_SEL__ALU_SRC_0 = 248, + EG_SRC_SEL__ALU_SRC_1 = 249, + EG_SRC_SEL__ALU_SRC_1_INT = 250, + EG_SRC_SEL__ALU_SRC_M_1_INT = 251, + EG_SRC_SEL__ALU_SRC_0_5 = 252, + EG_SRC_SEL__ALU_SRC_LITERAL = 253, + EG_SRC_SEL__ALU_SRC_PV = 254, + EG_SRC_SEL__ALU_SRC_PS = 255, + +//ALLOC_EXPORT + EG_CF_ALLOC_EXPORT_WORD0__ARRAY_BASE_shift = 0, //13 bits + EG_CF_ALLOC_EXPORT_WORD0__ARRAY_BASE_mask = 0x1FFF, + EG_CF_ALLOC_EXPORT_WORD0__TYPE_shift = 13,//2 bits + EG_CF_ALLOC_EXPORT_WORD0__TYPE_mask = 0x3 << 13, + EG_CF_ALLOC_EXPORT_WORD0__RW_GPR_shift = 15,//7 bits + EG_CF_ALLOC_EXPORT_WORD0__RW_GPR_mask = 0x7F << 15, + EG_CF_ALLOC_EXPORT_WORD0__RW_REL_shift = 22,//1 bit + EG_CF_ALLOC_EXPORT_WORD0__RW_REL_bit = 1 << 22, + EG_CF_ALLOC_EXPORT_WORD0__INDEX_GPR_shift = 23,//7 bits + EG_CF_ALLOC_EXPORT_WORD0__INDEX_GPR_mask = 0x7F << 23, + EG_CF_ALLOC_EXPORT_WORD0__ELEM_SIZE_shift = 30,//2 bits + EG_CF_ALLOC_EXPORT_WORD0__ELEM_SIZE_mask = 0x3 << 30, + + EG_CF_ALLOC_EXPORT_WORD1_BUF__ARRAY_SIZE_shift = 0, //12 bits + EG_CF_ALLOC_EXPORT_WORD1_BUF__ARRAY_SIZE_mask = 0xFFF, + EG_CF_ALLOC_EXPORT_WORD1_BUF__COMP_MASK_shift = 12, //4 bits + EG_CF_ALLOC_EXPORT_WORD1_BUF__COMP_MASK_mask = 0xF << 12, + + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__SEL_X_shift = 0, //3 bits + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__SEL_X_mask = 0x7, + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__SEL_Y_shift = 3, //3 bits + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__SEL_Y_mask = 0x7 << 3, + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__SEL_Z_shift = 6, //3 bits + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__SEL_Z_mask = 0x7 << 6, + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__SEL_W_shift = 9, //3 bits + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__SEL_W_mask = 0x7 << 9, + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__Resreve_shift = 12,//4 bits + EG_CF_ALLOC_EXPORT_WORD1_SWIZ__Resreve_mask = 0xF << 12, + + EG_CF_ALLOC_EXPORT_WORD1__BURST_COUNT_shift = 16, //4 bits + EG_CF_ALLOC_EXPORT_WORD1__BURST_COUNT_mask = 0xF << 16, + EG_CF_ALLOC_EXPORT_WORD1__VPM_shift = 20, //1 bit + EG_CF_ALLOC_EXPORT_WORD1__VPM_bit = 1 << 20, + EG_CF_ALLOC_EXPORT_WORD1__EOP_shift = 21, //1 bit + EG_CF_ALLOC_EXPORT_WORD1__EOP_bit = 1 << 21, + EG_CF_ALLOC_EXPORT_WORD1__CF_INST_shift = 22, //8 bits + EG_CF_ALLOC_EXPORT_WORD1__CF_INST_mask = 0xFF << 22, + EG_CF_ALLOC_EXPORT_WORD1__MARK_shift = 30, //1 bit + EG_CF_ALLOC_EXPORT_WORD1__MARK_bit = 1 << 30, + EG_CF_ALLOC_EXPORT_WORD1__BARRIER_shift = 31, //1 bit + EG_CF_ALLOC_EXPORT_WORD1__BARRIER_bit = 1 << 31, + + EG_CF_INST_MEM_STREAM0_BUF0 = 64 , + EG_CF_INST_MEM_STREAM0_BUF1 = 65, + EG_CF_INST_MEM_STREAM0_BUF2 = 66, + EG_CF_INST_MEM_STREAM0_BUF3 = 67, + EG_CF_INST_MEM_STREAM1_BUF0 = 68, + EG_CF_INST_MEM_STREAM1_BUF1 = 69, + EG_CF_INST_MEM_STREAM1_BUF2 = 70, + EG_CF_INST_MEM_STREAM1_BUF3 = 71, + EG_CF_INST_MEM_STREAM2_BUF0 = 72, + EG_CF_INST_MEM_STREAM2_BUF1 = 73, + EG_CF_INST_MEM_STREAM2_BUF2 = 74, + EG_CF_INST_MEM_STREAM2_BUF3 = 75, + EG_CF_INST_MEM_STREAM3_BUF0 = 76, + EG_CF_INST_MEM_STREAM3_BUF1 = 77, + EG_CF_INST_MEM_STREAM3_BUF2 = 78, + EG_CF_INST_MEM_STREAM3_BUF3 = 79, + EG_CF_INST_MEM_WR_SCRATCH = 80, + EG_CF_INST_MEM_RING = 82, + EG_CF_INST_EXPORT = 83, + EG_CF_INST_EXPORT_DONE = 84, + EG_CF_INST_MEM_EXPORT = 85, + EG_CF_INST_MEM_RAT = 86, + EG_CF_INST_MEM_RAT_CACHELESS = 87, + EG_CF_INST_MEM_RING1 = 88, + EG_CF_INST_MEM_RING2 = 89, + EG_CF_INST_MEM_RING3 = 90, + EG_CF_INST_MEM_EXPORT_COMBINED = 91, + EG_CF_INST_MEM_RAT_COMBINED_CACHELESS = 92, + + EG_EXPORT_PIXEL = 0, + EG_EXPORT_WRITE = 0, + EG_EXPORT_POS = 1, + EG_EXPORT_WRITE_IND = 1, + EG_EXPORT_PARAM = 2, + EG_EXPORT_WRITE_ACK = 2, + EG_EXPORT_WRITE_IND_ACK = 3, + + /* PS interp param source */ + EG_ALU_SRC_PARAM_BASE = 0x000001c0, + EG_ALU_SRC_PARAM_SIZE = 0x00000021, +}; + +#endif //_EVERGREEN_SQ_H_ + + diff --git a/src/mesa/drivers/dri/r600/evergreen_state.c b/src/mesa/drivers/dri/r600/evergreen_state.c new file mode 100644 index 0000000000..931478caa5 --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_state.c @@ -0,0 +1,1878 @@ +/* + * Copyright (C) 2008-2009 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#include "main/glheader.h" +#include "main/mtypes.h" +#include "main/imports.h" +#include "main/enums.h" +#include "main/macros.h" +#include "main/context.h" +#include "main/dd.h" +#include "main/simple_list.h" + +#include "tnl/tnl.h" +#include "tnl/t_pipeline.h" +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "main/api_arrayelt.h" +#include "main/framebuffer.h" +#include "drivers/common/meta.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" + +#include "vbo/vbo.h" + +#include "r600_context.h" + +#include "evergreen_state.h" +#include "evergreen_diff.h" +#include "evergreen_vertprog.h" +#include "evergreen_fragprog.h" +#include "evergreen_tex.h" + +void evergreenUpdateStateParameters(GLcontext * ctx, GLuint new_state); //same + +void evergreenUpdateShaders(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + + /* should only happenen once, just after context is created */ + /* TODO: shouldn't we fallback to sw here? */ + if (!ctx->FragmentProgram._Current) { + fprintf(stderr, "No ctx->FragmentProgram._Current!!\n"); + return; + } + + evergreenSelectFragmentShader(ctx); + + evergreenSelectVertexShader(ctx); + evergreenUpdateStateParameters(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + context->radeon.NewGLState = 0; +} + +void evergreeUpdateShaders(GLcontext * ctx) +{ + context_t *context = R700_CONTEXT(ctx); + + /* should only happenen once, just after context is created */ + /* TODO: shouldn't we fallback to sw here? */ + if (!ctx->FragmentProgram._Current) { + fprintf(stderr, "No ctx->FragmentProgram._Current!!\n"); + return; + } + + evergreenSelectFragmentShader(ctx); + + evergreenSelectVertexShader(ctx); + evergreenUpdateStateParameters(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + context->radeon.NewGLState = 0; +} + +/* + * To correctly position primitives: + */ +void evergreenUpdateViewportOffset(GLcontext * ctx) //------------------ +{ + context_t *context = R700_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + __DRIdrawable *dPriv = radeon_get_drawable(&context->radeon); + GLfloat xoffset = (GLfloat) dPriv->x; + GLfloat yoffset = (GLfloat) dPriv->y + dPriv->h; + const GLfloat *v = ctx->Viewport._WindowMap.m; + int id = 0; + + GLfloat tx = v[MAT_TX] + xoffset; + GLfloat ty = (-v[MAT_TY]) + yoffset; + + if (evergreen->viewport[id].PA_CL_VPORT_XOFFSET.f32All != tx || + evergreen->viewport[id].PA_CL_VPORT_YOFFSET.f32All != ty) { + /* Note: this should also modify whatever data the context reset + * code uses... + */ + EVERGREEN_STATECHANGE(context, pa); + evergreen->viewport[id].PA_CL_VPORT_XOFFSET.f32All = tx; + evergreen->viewport[id].PA_CL_VPORT_YOFFSET.f32All = ty; + } + + radeonUpdateScissor(ctx); +} + +void evergreenUpdateStateParameters(GLcontext * ctx, GLuint new_state) //same +{ + struct evergreen_fragment_program *fp = + (struct evergreen_fragment_program *)ctx->FragmentProgram._Current; + struct gl_program_parameter_list *paramList; + + if (!(new_state & (_NEW_BUFFERS | _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS))) + return; + + if (!ctx->FragmentProgram._Current || !fp) + return; + + paramList = ctx->FragmentProgram._Current->Base.Parameters; + + if (!paramList) + return; + + _mesa_load_state_parameters(ctx, paramList); + +} + +/** + * Called by Mesa after an internal state update. + */ +static void evergreenInvalidateState(GLcontext * ctx, GLuint new_state) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + _swrast_InvalidateState(ctx, new_state); + _swsetup_InvalidateState(ctx, new_state); + _vbo_InvalidateState(ctx, new_state); + _tnl_InvalidateState(ctx, new_state); + _ae_invalidate_state(ctx, new_state); + + if (new_state & _NEW_BUFFERS) { + _mesa_update_framebuffer(ctx); + /* this updates the DrawBuffer's Width/Height if it's a FBO */ + _mesa_update_draw_buffer_bounds(ctx); + + EVERGREEN_STATECHANGE(context, cb); + EVERGREEN_STATECHANGE(context, db); + } + + if (new_state & (_NEW_LIGHT)) { + EVERGREEN_STATECHANGE(context, pa); + if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION) + SETbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, PROVOKING_VTX_LAST_bit); + else + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, PROVOKING_VTX_LAST_bit); + } + + evergreenUpdateStateParameters(ctx, new_state); + + EVERGREEN_STATECHANGE(context, pa); + EVERGREEN_STATECHANGE(context, spi); + + if(GL_TRUE == evergreen->bEnablePerspective) + { + /* Do scale XY and Z by 1/W0 for perspective correction on pos. For orthogonal case, set both to one. */ + CLEARbit(evergreen->PA_CL_VTE_CNTL.u32All, VTX_XY_FMT_bit); + CLEARbit(evergreen->PA_CL_VTE_CNTL.u32All, VTX_Z_FMT_bit); + + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VTX_W0_FMT_bit); + + SETbit(evergreen->SPI_PS_IN_CONTROL_0.u32All, PERSP_GRADIENT_ENA_bit); + CLEARbit(evergreen->SPI_PS_IN_CONTROL_0.u32All, LINEAR_GRADIENT_ENA_bit); + + SETfield(evergreen->SPI_BARYC_CNTL.u32All, 1, + EG_SPI_BARYC_CNTL__PERSP_CENTROID_ENA_shift, + EG_SPI_BARYC_CNTL__PERSP_CENTROID_ENA_mask); + } + else + { + /* For orthogonal case. */ + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VTX_XY_FMT_bit); + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VTX_Z_FMT_bit); + + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VTX_W0_FMT_bit); + + CLEARbit(evergreen->SPI_PS_IN_CONTROL_0.u32All, PERSP_GRADIENT_ENA_bit); + SETbit(evergreen->SPI_PS_IN_CONTROL_0.u32All, LINEAR_GRADIENT_ENA_bit); + + SETfield(evergreen->SPI_BARYC_CNTL.u32All, 1, + EG_SPI_BARYC_CNTL__LINEAR_CENTROID_ENA_shift, + EG_SPI_BARYC_CNTL__LINEAR_CENTROID_ENA_mask); + } + + context->radeon.NewGLState |= new_state; +} + +static void evergreenSetAlphaState(GLcontext * ctx) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + uint32_t alpha_func = REF_ALWAYS; + GLboolean really_enabled = ctx->Color.AlphaEnabled; + + EVERGREEN_STATECHANGE(context, sx); + + switch (ctx->Color.AlphaFunc) { + case GL_NEVER: + alpha_func = REF_NEVER; + break; + case GL_LESS: + alpha_func = REF_LESS; + break; + case GL_EQUAL: + alpha_func = REF_EQUAL; + break; + case GL_LEQUAL: + alpha_func = REF_LEQUAL; + break; + case GL_GREATER: + alpha_func = REF_GREATER; + break; + case GL_NOTEQUAL: + alpha_func = REF_NOTEQUAL; + break; + case GL_GEQUAL: + alpha_func = REF_GEQUAL; + break; + case GL_ALWAYS: + /*alpha_func = REF_ALWAYS; */ + really_enabled = GL_FALSE; + break; + } + + if (really_enabled) { + SETfield(evergreen->SX_ALPHA_TEST_CONTROL.u32All, alpha_func, + ALPHA_FUNC_shift, ALPHA_FUNC_mask); + SETbit(evergreen->SX_ALPHA_TEST_CONTROL.u32All, ALPHA_TEST_ENABLE_bit); + evergreen->SX_ALPHA_REF.f32All = ctx->Color.AlphaRef; + } else { + CLEARbit(evergreen->SX_ALPHA_TEST_CONTROL.u32All, ALPHA_TEST_ENABLE_bit); + } +} + +static void evergreenAlphaFunc(GLcontext * ctx, GLenum func, GLfloat ref) //same +{ + (void)func; + (void)ref; + evergreenSetAlphaState(ctx); +} + +static void evergreenBlendColor(GLcontext * ctx, const GLfloat cf[4]) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, cb); + + evergreen->CB_BLEND_RED.f32All = cf[0]; + evergreen->CB_BLEND_GREEN.f32All = cf[1]; + evergreen->CB_BLEND_BLUE.f32All = cf[2]; + evergreen->CB_BLEND_ALPHA.f32All = cf[3]; +} + +static int evergreenblend_factor(GLenum factor, GLboolean is_src) //same +{ + switch (factor) { + case GL_ZERO: + return BLEND_ZERO; + break; + case GL_ONE: + return BLEND_ONE; + break; + case GL_DST_COLOR: + return BLEND_DST_COLOR; + break; + case GL_ONE_MINUS_DST_COLOR: + return BLEND_ONE_MINUS_DST_COLOR; + break; + case GL_SRC_COLOR: + return BLEND_SRC_COLOR; + break; + case GL_ONE_MINUS_SRC_COLOR: + return BLEND_ONE_MINUS_SRC_COLOR; + break; + case GL_SRC_ALPHA: + return BLEND_SRC_ALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + return BLEND_ONE_MINUS_SRC_ALPHA; + break; + case GL_DST_ALPHA: + return BLEND_DST_ALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + return BLEND_ONE_MINUS_DST_ALPHA; + break; + case GL_SRC_ALPHA_SATURATE: + return (is_src) ? BLEND_SRC_ALPHA_SATURATE : BLEND_ZERO; + break; + case GL_CONSTANT_COLOR: + return BLEND_CONSTANT_COLOR; + break; + case GL_ONE_MINUS_CONSTANT_COLOR: + return BLEND_ONE_MINUS_CONSTANT_COLOR; + break; + case GL_CONSTANT_ALPHA: + return BLEND_CONSTANT_ALPHA; + break; + case GL_ONE_MINUS_CONSTANT_ALPHA: + return BLEND_ONE_MINUS_CONSTANT_ALPHA; + break; + default: + fprintf(stderr, "unknown blend factor %x\n", factor); + return (is_src) ? BLEND_ONE : BLEND_ZERO; + break; + } +} + +static void evergreenSetBlendState(GLcontext * ctx) //diff : CB_COLOR_CONTROL, CB_BLEND0_CONTROL bits +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + uint32_t blend_reg = 0, eqn, eqnA; + + EVERGREEN_STATECHANGE(context, cb); + + if (RGBA_LOGICOP_ENABLED(ctx) || !ctx->Color.BlendEnabled) { + SETfield(blend_reg, + BLEND_ONE, COLOR_SRCBLEND_shift, COLOR_SRCBLEND_mask); + SETfield(blend_reg, + BLEND_ZERO, COLOR_DESTBLEND_shift, COLOR_DESTBLEND_mask); + SETfield(blend_reg, + COMB_DST_PLUS_SRC, COLOR_COMB_FCN_shift, COLOR_COMB_FCN_mask); + SETfield(blend_reg, + BLEND_ONE, ALPHA_SRCBLEND_shift, ALPHA_SRCBLEND_mask); + SETfield(blend_reg, + BLEND_ZERO, ALPHA_DESTBLEND_shift, ALPHA_DESTBLEND_mask); + SETfield(blend_reg, + COMB_DST_PLUS_SRC, ALPHA_COMB_FCN_shift, ALPHA_COMB_FCN_mask); + //if (context->radeon.radeonScreen->chip_family == CHIP_FAMILY_R600) + // evergreen->CB_BLEND_CONTROL.u32All = blend_reg; + //else + evergreen->CB_BLEND0_CONTROL.u32All = blend_reg; + return; + } + + SETfield(blend_reg, + evergreenblend_factor(ctx->Color.BlendSrcRGB, GL_TRUE), + COLOR_SRCBLEND_shift, COLOR_SRCBLEND_mask); + SETfield(blend_reg, + evergreenblend_factor(ctx->Color.BlendDstRGB, GL_FALSE), + COLOR_DESTBLEND_shift, COLOR_DESTBLEND_mask); + + switch (ctx->Color.BlendEquationRGB) { + case GL_FUNC_ADD: + eqn = COMB_DST_PLUS_SRC; + break; + case GL_FUNC_SUBTRACT: + eqn = COMB_SRC_MINUS_DST; + break; + case GL_FUNC_REVERSE_SUBTRACT: + eqn = COMB_DST_MINUS_SRC; + break; + case GL_MIN: + eqn = COMB_MIN_DST_SRC; + SETfield(blend_reg, + BLEND_ONE, + COLOR_SRCBLEND_shift, COLOR_SRCBLEND_mask); + SETfield(blend_reg, + BLEND_ONE, + COLOR_DESTBLEND_shift, COLOR_DESTBLEND_mask); + break; + case GL_MAX: + eqn = COMB_MAX_DST_SRC; + SETfield(blend_reg, + BLEND_ONE, + COLOR_SRCBLEND_shift, COLOR_SRCBLEND_mask); + SETfield(blend_reg, + BLEND_ONE, + COLOR_DESTBLEND_shift, COLOR_DESTBLEND_mask); + break; + + default: + fprintf(stderr, + "[%s:%u] Invalid RGB blend equation (0x%04x).\n", + __FUNCTION__, __LINE__, ctx->Color.BlendEquationRGB); + return; + } + SETfield(blend_reg, + eqn, COLOR_COMB_FCN_shift, COLOR_COMB_FCN_mask); + + SETfield(blend_reg, + evergreenblend_factor(ctx->Color.BlendSrcA, GL_TRUE), + ALPHA_SRCBLEND_shift, ALPHA_SRCBLEND_mask); + SETfield(blend_reg, + evergreenblend_factor(ctx->Color.BlendDstA, GL_FALSE), + ALPHA_DESTBLEND_shift, ALPHA_DESTBLEND_mask); + + switch (ctx->Color.BlendEquationA) { + case GL_FUNC_ADD: + eqnA = COMB_DST_PLUS_SRC; + break; + case GL_FUNC_SUBTRACT: + eqnA = COMB_SRC_MINUS_DST; + break; + case GL_FUNC_REVERSE_SUBTRACT: + eqnA = COMB_DST_MINUS_SRC; + break; + case GL_MIN: + eqnA = COMB_MIN_DST_SRC; + SETfield(blend_reg, + BLEND_ONE, + ALPHA_SRCBLEND_shift, ALPHA_SRCBLEND_mask); + SETfield(blend_reg, + BLEND_ONE, + ALPHA_DESTBLEND_shift, ALPHA_DESTBLEND_mask); + break; + case GL_MAX: + eqnA = COMB_MAX_DST_SRC; + SETfield(blend_reg, + BLEND_ONE, + ALPHA_SRCBLEND_shift, ALPHA_SRCBLEND_mask); + SETfield(blend_reg, + BLEND_ONE, + ALPHA_DESTBLEND_shift, ALPHA_DESTBLEND_mask); + break; + default: + fprintf(stderr, + "[%s:%u] Invalid A blend equation (0x%04x).\n", + __FUNCTION__, __LINE__, ctx->Color.BlendEquationA); + return; + } + + SETfield(blend_reg, + eqnA, ALPHA_COMB_FCN_shift, ALPHA_COMB_FCN_mask); + + SETbit(blend_reg, SEPARATE_ALPHA_BLEND_bit); + + SETbit(blend_reg, EG_CB_BLENDX_CONTROL_ENABLE_bit); + + evergreen->CB_BLEND0_CONTROL.u32All = blend_reg; +} + +static void evergreenBlendEquationSeparate(GLcontext * ctx, + GLenum modeRGB, GLenum modeA) //same +{ + evergreenSetBlendState(ctx); +} + +static void evergreenBlendFuncSeparate(GLcontext * ctx, + GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA) //same +{ + evergreenSetBlendState(ctx); +} + +static GLuint evergreen_translate_logicop(GLenum logicop) //same +{ + switch (logicop) { + case GL_CLEAR: + return 0x00; + case GL_SET: + return 0xff; + case GL_COPY: + return 0xcc; + case GL_COPY_INVERTED: + return 0x33; + case GL_NOOP: + return 0xaa; + case GL_INVERT: + return 0x55; + case GL_AND: + return 0x88; + case GL_NAND: + return 0x77; + case GL_OR: + return 0xee; + case GL_NOR: + return 0x11; + case GL_XOR: + return 0x66; + case GL_EQUIV: + return 0x99; + case GL_AND_REVERSE: + return 0x44; + case GL_AND_INVERTED: + return 0x22; + case GL_OR_REVERSE: + return 0xdd; + case GL_OR_INVERTED: + return 0xbb; + default: + fprintf(stderr, "unknown blend logic operation %x\n", logicop); + return 0xcc; + } +} + +static void evergreenSetLogicOpState(GLcontext *ctx) //diff : CB_COLOR_CONTROL.ROP3 is actually same bits. +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, cb); + + if (RGBA_LOGICOP_ENABLED(ctx)) + SETfield(evergreen->CB_COLOR_CONTROL.u32All, + evergreen_translate_logicop(ctx->Color.LogicOp), + EG_CB_COLOR_CONTROL__ROP3_shift, + EG_CB_COLOR_CONTROL__ROP3_mask); + else + SETfield(evergreen->CB_COLOR_CONTROL.u32All, 0xCC, + EG_CB_COLOR_CONTROL__ROP3_shift, + EG_CB_COLOR_CONTROL__ROP3_mask); +} + +static void evergreenClipPlane( GLcontext *ctx, GLenum plane, const GLfloat *eq ) //same , but PA_CL_UCP_0_ offset diff +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + GLint p; + GLint *ip; + + p = (GLint) plane - (GLint) GL_CLIP_PLANE0; + ip = (GLint *)ctx->Transform._ClipUserPlane[p]; + + EVERGREEN_STATECHANGE(context, pa); + + evergreen->ucp[p].PA_CL_UCP_0_X.u32All = ip[0]; + evergreen->ucp[p].PA_CL_UCP_0_Y.u32All = ip[1]; + evergreen->ucp[p].PA_CL_UCP_0_Z.u32All = ip[2]; + evergreen->ucp[p].PA_CL_UCP_0_W.u32All = ip[3]; +} + +static void evergreenSetClipPlaneState(GLcontext * ctx, GLenum cap, GLboolean state) //diff in func calls +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + GLuint p; + + p = cap - GL_CLIP_PLANE0; + + EVERGREEN_STATECHANGE(context, pa); + + if (state) { + evergreen->PA_CL_CLIP_CNTL.u32All |= (UCP_ENA_0_bit << p); + evergreen->ucp[p].enabled = GL_TRUE; + evergreenClipPlane(ctx, cap, NULL); + } else { + evergreen->PA_CL_CLIP_CNTL.u32All &= ~(UCP_ENA_0_bit << p); + evergreen->ucp[p].enabled = GL_FALSE; + } +} + +static void evergreenSetDBRenderState(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct evergreen_fragment_program *fp = + (struct evergreen_fragment_program *)(ctx->FragmentProgram._Current); + + EVERGREEN_STATECHANGE(context, db); + + SETbit(evergreen->DB_SHADER_CONTROL.u32All, + DUAL_EXPORT_ENABLE_bit); + SETfield(evergreen->DB_SHADER_CONTROL.u32All, EARLY_Z_THEN_LATE_Z, + Z_ORDER_shift, + Z_ORDER_mask); + /* XXX need to enable htile for hiz/s */ + SETfield(evergreen->DB_RENDER_OVERRIDE.u32All, FORCE_DISABLE, + FORCE_HIZ_ENABLE_shift, + FORCE_HIZ_ENABLE_mask); + SETfield(evergreen->DB_RENDER_OVERRIDE.u32All, FORCE_DISABLE, + FORCE_HIS_ENABLE0_shift, + FORCE_HIS_ENABLE0_mask); + SETfield(evergreen->DB_RENDER_OVERRIDE.u32All, FORCE_DISABLE, + FORCE_HIS_ENABLE1_shift, + FORCE_HIS_ENABLE1_mask); + + if (context->radeon.query.current) + { + SETbit(evergreen->DB_RENDER_OVERRIDE.u32All, NOOP_CULL_DISABLE_bit); + SETbit(evergreen->DB_COUNT_CONTROL.u32All, + EG_DB_COUNT_CONTROL__PERFECT_ZPASS_COUNTS_bit); + } + else + { + CLEARbit(evergreen->DB_RENDER_OVERRIDE.u32All, NOOP_CULL_DISABLE_bit); + CLEARbit(evergreen->DB_COUNT_CONTROL.u32All, + EG_DB_COUNT_CONTROL__PERFECT_ZPASS_COUNTS_bit); + } + + if (fp) + { + if (fp->r700Shader.killIsUsed) + { + SETbit(evergreen->DB_SHADER_CONTROL.u32All, KILL_ENABLE_bit); + } + else + { + CLEARbit(evergreen->DB_SHADER_CONTROL.u32All, KILL_ENABLE_bit); + } + + if (fp->r700Shader.depthIsExported) + { + SETbit(evergreen->DB_SHADER_CONTROL.u32All, Z_EXPORT_ENABLE_bit); + } + else + { + CLEARbit(evergreen->DB_SHADER_CONTROL.u32All, Z_EXPORT_ENABLE_bit); + } + } +} + +void evergreenUpdateShaderStates(GLcontext * ctx) +{ + evergreenSetDBRenderState(ctx); + evergreenUpdateTextureState(ctx); +} + +static void evergreenSetDepthState(GLcontext * ctx) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, db); + + if (ctx->Depth.Test) + { + SETbit(evergreen->DB_DEPTH_CONTROL.u32All, Z_ENABLE_bit); + if (ctx->Depth.Mask) + { + SETbit(evergreen->DB_DEPTH_CONTROL.u32All, Z_WRITE_ENABLE_bit); + } + else + { + CLEARbit(evergreen->DB_DEPTH_CONTROL.u32All, Z_WRITE_ENABLE_bit); + } + + switch (ctx->Depth.Func) + { + case GL_NEVER: + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_NEVER, + ZFUNC_shift, ZFUNC_mask); + break; + case GL_LESS: + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_LESS, + ZFUNC_shift, ZFUNC_mask); + break; + case GL_EQUAL: + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_EQUAL, + ZFUNC_shift, ZFUNC_mask); + break; + case GL_LEQUAL: + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_LEQUAL, + ZFUNC_shift, ZFUNC_mask); + break; + case GL_GREATER: + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_GREATER, + ZFUNC_shift, ZFUNC_mask); + break; + case GL_NOTEQUAL: + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_NOTEQUAL, + ZFUNC_shift, ZFUNC_mask); + break; + case GL_GEQUAL: + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_GEQUAL, + ZFUNC_shift, ZFUNC_mask); + break; + case GL_ALWAYS: + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_ALWAYS, + ZFUNC_shift, ZFUNC_mask); + break; + default: + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_ALWAYS, + ZFUNC_shift, ZFUNC_mask); + break; + } + } + else + { + CLEARbit(evergreen->DB_DEPTH_CONTROL.u32All, Z_ENABLE_bit); + CLEARbit(evergreen->DB_DEPTH_CONTROL.u32All, Z_WRITE_ENABLE_bit); + } +} + +static void evergreenSetStencilState(GLcontext * ctx, GLboolean state) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + GLboolean hw_stencil = GL_FALSE; + + if (ctx->DrawBuffer) { + struct radeon_renderbuffer *rrbStencil + = radeon_get_renderbuffer(ctx->DrawBuffer, BUFFER_STENCIL); + hw_stencil = (rrbStencil && rrbStencil->bo); + } + + if (hw_stencil) { + EVERGREEN_STATECHANGE(context, db); + if (state) { + SETbit(evergreen->DB_DEPTH_CONTROL.u32All, STENCIL_ENABLE_bit); + SETbit(evergreen->DB_DEPTH_CONTROL.u32All, BACKFACE_ENABLE_bit); + } else + CLEARbit(evergreen->DB_DEPTH_CONTROL.u32All, STENCIL_ENABLE_bit); + } +} + +static void evergreenUpdateCulling(GLcontext * ctx) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, pa); + + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, FACE_bit); + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_FRONT_bit); + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_BACK_bit); + + if (ctx->Polygon.CullFlag) + { + switch (ctx->Polygon.CullFaceMode) + { + case GL_FRONT: + SETbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_FRONT_bit); + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_BACK_bit); + break; + case GL_BACK: + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_FRONT_bit); + SETbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_BACK_bit); + break; + case GL_FRONT_AND_BACK: + SETbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_FRONT_bit); + SETbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_BACK_bit); + break; + default: + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_FRONT_bit); + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, CULL_BACK_bit); + break; + } + } + + switch (ctx->Polygon.FrontFace) + { + case GL_CW: + SETbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, FACE_bit); + break; + case GL_CCW: + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, FACE_bit); + break; + default: + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, FACE_bit); /* default: ccw */ + break; + } + + /* Winding is inverted when rendering to FBO */ + if (ctx->DrawBuffer && ctx->DrawBuffer->Name) + evergreen->PA_SU_SC_MODE_CNTL.u32All ^= FACE_bit; +} + +static void evergreenSetPolygonOffsetState(GLcontext * ctx, GLboolean state) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, pa); + + if (state) { + SETbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, POLY_OFFSET_FRONT_ENABLE_bit); + SETbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, POLY_OFFSET_BACK_ENABLE_bit); + SETbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, POLY_OFFSET_PARA_ENABLE_bit); + } else { + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, POLY_OFFSET_FRONT_ENABLE_bit); + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, POLY_OFFSET_BACK_ENABLE_bit); + CLEARbit(evergreen->PA_SU_SC_MODE_CNTL.u32All, POLY_OFFSET_PARA_ENABLE_bit); + } +} + +static void evergreenUpdateLineStipple(GLcontext * ctx) //diff +{ + /* TODO */ +} + +void evergreenSetScissor(context_t *context) //diff +{ + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + unsigned x1, y1, x2, y2; + int id = 0; + struct radeon_renderbuffer *rrb; + + rrb = radeon_get_colorbuffer(&context->radeon); + if (!rrb || !rrb->bo) { + return; + } + if (context->radeon.state.scissor.enabled) { + x1 = context->radeon.state.scissor.rect.x1; + y1 = context->radeon.state.scissor.rect.y1; + x2 = context->radeon.state.scissor.rect.x2; + y2 = context->radeon.state.scissor.rect.y2; + /* r600 has exclusive BR scissors */ + if (context->radeon.radeonScreen->kernel_mm) { + x2++; + y2++; + } + } else { + if (context->radeon.radeonScreen->driScreen->dri2.enabled) { + x1 = 0; + y1 = 0; + x2 = rrb->base.Width; + y2 = rrb->base.Height; + } else { + x1 = rrb->dPriv->x; + y1 = rrb->dPriv->y; + x2 = rrb->dPriv->x + rrb->dPriv->w; + y2 = rrb->dPriv->y + rrb->dPriv->h; + } + } + + EVERGREEN_STATECHANGE(context, pa); + + /* screen */ + /* TODO : check WINDOW_OFFSET_DISABLE */ + //SETbit(evergreen->PA_SC_SCREEN_SCISSOR_TL.u32All, WINDOW_OFFSET_DISABLE_bit); + SETfield(evergreen->PA_SC_SCREEN_SCISSOR_TL.u32All, x1, + PA_SC_SCREEN_SCISSOR_TL__TL_X_shift, EG_PA_SC_SCREEN_SCISSOR_TL__TL_X_mask); + SETfield(evergreen->PA_SC_SCREEN_SCISSOR_TL.u32All, y1, + PA_SC_SCREEN_SCISSOR_TL__TL_Y_shift, EG_PA_SC_SCREEN_SCISSOR_TL__TL_Y_mask); + + SETfield(evergreen->PA_SC_SCREEN_SCISSOR_BR.u32All, x2, + PA_SC_SCREEN_SCISSOR_BR__BR_X_shift, EG_PA_SC_SCREEN_SCISSOR_BR__BR_X_mask); + SETfield(evergreen->PA_SC_SCREEN_SCISSOR_BR.u32All, y2, + PA_SC_SCREEN_SCISSOR_BR__BR_Y_shift, EG_PA_SC_SCREEN_SCISSOR_BR__BR_Y_mask); + + /* window */ + SETbit(evergreen->PA_SC_WINDOW_SCISSOR_TL.u32All, WINDOW_OFFSET_DISABLE_bit); + SETfield(evergreen->PA_SC_WINDOW_SCISSOR_TL.u32All, x1, + PA_SC_WINDOW_SCISSOR_TL__TL_X_shift, EG_PA_SC_WINDOW_SCISSOR_TL__TL_X_mask); + SETfield(evergreen->PA_SC_WINDOW_SCISSOR_TL.u32All, y1, + PA_SC_WINDOW_SCISSOR_TL__TL_Y_shift, EG_PA_SC_WINDOW_SCISSOR_TL__TL_Y_mask); + + SETfield(evergreen->PA_SC_WINDOW_SCISSOR_BR.u32All, x2, + PA_SC_WINDOW_SCISSOR_BR__BR_X_shift, EG_PA_SC_WINDOW_SCISSOR_BR__BR_X_mask); + SETfield(evergreen->PA_SC_WINDOW_SCISSOR_BR.u32All, y2, + PA_SC_WINDOW_SCISSOR_BR__BR_Y_shift, EG_PA_SC_WINDOW_SCISSOR_BR__BR_Y_mask); + + + SETfield(evergreen->PA_SC_CLIPRECT_0_TL.u32All, x1, + PA_SC_CLIPRECT_0_TL__TL_X_shift, EG_PA_SC_CLIPRECT_0_TL__TL_X_mask); + SETfield(evergreen->PA_SC_CLIPRECT_0_TL.u32All, y1, + PA_SC_CLIPRECT_0_TL__TL_Y_shift, EG_PA_SC_CLIPRECT_0_TL__TL_Y_mask); + SETfield(evergreen->PA_SC_CLIPRECT_0_BR.u32All, x2, + PA_SC_CLIPRECT_0_BR__BR_X_shift, EG_PA_SC_CLIPRECT_0_BR__BR_X_mask); + SETfield(evergreen->PA_SC_CLIPRECT_0_BR.u32All, y2, + PA_SC_CLIPRECT_0_BR__BR_Y_shift, EG_PA_SC_CLIPRECT_0_BR__BR_Y_mask); + + evergreen->PA_SC_CLIPRECT_1_TL.u32All = evergreen->PA_SC_CLIPRECT_0_TL.u32All; + evergreen->PA_SC_CLIPRECT_1_BR.u32All = evergreen->PA_SC_CLIPRECT_0_BR.u32All; + evergreen->PA_SC_CLIPRECT_2_TL.u32All = evergreen->PA_SC_CLIPRECT_0_TL.u32All; + evergreen->PA_SC_CLIPRECT_2_BR.u32All = evergreen->PA_SC_CLIPRECT_0_BR.u32All; + evergreen->PA_SC_CLIPRECT_3_TL.u32All = evergreen->PA_SC_CLIPRECT_0_TL.u32All; + evergreen->PA_SC_CLIPRECT_3_BR.u32All = evergreen->PA_SC_CLIPRECT_0_BR.u32All; + + /* more....2d clip */ + SETbit(evergreen->PA_SC_GENERIC_SCISSOR_TL.u32All, WINDOW_OFFSET_DISABLE_bit); + SETfield(evergreen->PA_SC_GENERIC_SCISSOR_TL.u32All, x1, + PA_SC_GENERIC_SCISSOR_TL__TL_X_shift, EG_PA_SC_GENERIC_SCISSOR_TL__TL_X_mask); + SETfield(evergreen->PA_SC_GENERIC_SCISSOR_TL.u32All, y1, + PA_SC_GENERIC_SCISSOR_TL__TL_Y_shift, EG_PA_SC_GENERIC_SCISSOR_TL__TL_Y_mask); + SETfield(evergreen->PA_SC_GENERIC_SCISSOR_BR.u32All, x2, + PA_SC_GENERIC_SCISSOR_BR__BR_X_shift, EG_PA_SC_GENERIC_SCISSOR_BR__BR_X_mask); + SETfield(evergreen->PA_SC_GENERIC_SCISSOR_BR.u32All, y2, + PA_SC_GENERIC_SCISSOR_BR__BR_Y_shift, EG_PA_SC_GENERIC_SCISSOR_BR__BR_Y_mask); + + SETbit(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_TL.u32All, WINDOW_OFFSET_DISABLE_bit); + SETfield(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_TL.u32All, x1, + PA_SC_VPORT_SCISSOR_0_TL__TL_X_shift, EG_PA_SC_VPORT_SCISSOR_0_TL__TL_X_mask); + SETfield(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_TL.u32All, y1, + PA_SC_VPORT_SCISSOR_0_TL__TL_Y_shift, EG_PA_SC_VPORT_SCISSOR_0_TL__TL_Y_mask); + SETfield(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_BR.u32All, x2, + PA_SC_VPORT_SCISSOR_0_BR__BR_X_shift, EG_PA_SC_VPORT_SCISSOR_0_BR__BR_X_mask); + SETfield(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_BR.u32All, y2, + PA_SC_VPORT_SCISSOR_0_BR__BR_Y_shift, EG_PA_SC_VPORT_SCISSOR_0_BR__BR_Y_mask); + + id = 1; + SETbit(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_TL.u32All, WINDOW_OFFSET_DISABLE_bit); + SETfield(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_TL.u32All, x1, + PA_SC_VPORT_SCISSOR_0_TL__TL_X_shift, EG_PA_SC_VPORT_SCISSOR_0_TL__TL_X_mask); + SETfield(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_TL.u32All, y1, + PA_SC_VPORT_SCISSOR_0_TL__TL_Y_shift, EG_PA_SC_VPORT_SCISSOR_0_TL__TL_Y_mask); + SETfield(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_BR.u32All, x2, + PA_SC_VPORT_SCISSOR_0_BR__BR_X_shift, EG_PA_SC_VPORT_SCISSOR_0_BR__BR_X_mask); + SETfield(evergreen->viewport[id].PA_SC_VPORT_SCISSOR_0_BR.u32All, y2, + PA_SC_VPORT_SCISSOR_0_BR__BR_Y_shift, EG_PA_SC_VPORT_SCISSOR_0_BR__BR_Y_mask); + + evergreen->viewport[id].enabled = GL_TRUE; +} + +static void evergreenUpdateWindow(GLcontext * ctx, int id) //diff in calling evergreenSetScissor +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + __DRIdrawable *dPriv = radeon_get_drawable(&context->radeon); + GLfloat xoffset = dPriv ? (GLfloat) dPriv->x : 0; + GLfloat yoffset = dPriv ? (GLfloat) dPriv->y + dPriv->h : 0; + const GLfloat *v = ctx->Viewport._WindowMap.m; + const GLfloat depthScale = 1.0F / ctx->DrawBuffer->_DepthMaxF; + const GLboolean render_to_fbo = (ctx->DrawBuffer->Name != 0); + GLfloat y_scale, y_bias; + + if (render_to_fbo) { + y_scale = 1.0; + y_bias = 0; + } else { + y_scale = -1.0; + y_bias = yoffset; + } + + GLfloat sx = v[MAT_SX]; + GLfloat tx = v[MAT_TX] + xoffset; + GLfloat sy = v[MAT_SY] * y_scale; + GLfloat ty = (v[MAT_TY] * y_scale) + y_bias; + GLfloat sz = v[MAT_SZ] * depthScale; + GLfloat tz = v[MAT_TZ] * depthScale; + + EVERGREEN_STATECHANGE(context, pa); + + + evergreen->viewport[id].PA_CL_VPORT_XSCALE.f32All = sx; + evergreen->viewport[id].PA_CL_VPORT_XOFFSET.f32All = tx; + + evergreen->viewport[id].PA_CL_VPORT_YSCALE.f32All = sy; + evergreen->viewport[id].PA_CL_VPORT_YOFFSET.f32All = ty; + + evergreen->viewport[id].PA_CL_VPORT_ZSCALE.f32All = sz; + evergreen->viewport[id].PA_CL_VPORT_ZOFFSET.f32All = tz; + + if (ctx->Transform.DepthClamp) { + evergreen->viewport[id].PA_SC_VPORT_ZMIN_0.f32All = MIN2(ctx->Viewport.Near, ctx->Viewport.Far); + evergreen->viewport[id].PA_SC_VPORT_ZMAX_0.f32All = MAX2(ctx->Viewport.Near, ctx->Viewport.Far); + SETbit(evergreen->PA_CL_CLIP_CNTL.u32All, ZCLIP_NEAR_DISABLE_bit); + SETbit(evergreen->PA_CL_CLIP_CNTL.u32All, ZCLIP_FAR_DISABLE_bit); + } else { + evergreen->viewport[id].PA_SC_VPORT_ZMIN_0.f32All = 0.0; + evergreen->viewport[id].PA_SC_VPORT_ZMAX_0.f32All = 1.0; + CLEARbit(evergreen->PA_CL_CLIP_CNTL.u32All, ZCLIP_NEAR_DISABLE_bit); + CLEARbit(evergreen->PA_CL_CLIP_CNTL.u32All, ZCLIP_FAR_DISABLE_bit); + } + + evergreen->viewport[id].enabled = GL_TRUE; + + evergreenSetScissor(context); +} + +static void evergreenEnable(GLcontext * ctx, GLenum cap, GLboolean state) //diff in func calls +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + + switch (cap) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + /* empty */ + break; + case GL_FOG: + /* empty */ + break; + case GL_ALPHA_TEST: + evergreenSetAlphaState(ctx); + break; + case GL_COLOR_LOGIC_OP: + evergreenSetLogicOpState(ctx); + /* fall-through, because logic op overrides blending */ + case GL_BLEND: + evergreenSetBlendState(ctx); + break; + case GL_CLIP_PLANE0: + case GL_CLIP_PLANE1: + case GL_CLIP_PLANE2: + case GL_CLIP_PLANE3: + case GL_CLIP_PLANE4: + case GL_CLIP_PLANE5: + evergreenSetClipPlaneState(ctx, cap, state); + break; + case GL_DEPTH_TEST: + evergreenSetDepthState(ctx); + break; + case GL_STENCIL_TEST: + evergreenSetStencilState(ctx, state); + break; + case GL_CULL_FACE: + evergreenUpdateCulling(ctx); + break; + case GL_POLYGON_OFFSET_POINT: + case GL_POLYGON_OFFSET_LINE: + case GL_POLYGON_OFFSET_FILL: + evergreenSetPolygonOffsetState(ctx, state); + break; + case GL_SCISSOR_TEST: + radeon_firevertices(&context->radeon); + context->radeon.state.scissor.enabled = state; + radeonUpdateScissor(ctx); + break; + case GL_LINE_STIPPLE: + evergreenUpdateLineStipple(ctx); + break; + case GL_DEPTH_CLAMP: + evergreenUpdateWindow(ctx, 0); + break; + default: + break; + } + +} + +static void evergreenColorMask(GLcontext * ctx, + GLboolean r, GLboolean g, GLboolean b, GLboolean a) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + unsigned int mask = ((r ? 1 : 0) | + (g ? 2 : 0) | + (b ? 4 : 0) | + (a ? 8 : 0)); + + if (mask != evergreen->CB_TARGET_MASK.u32All) { + EVERGREEN_STATECHANGE(context, cb); + SETfield(evergreen->CB_TARGET_MASK.u32All, mask, TARGET0_ENABLE_shift, TARGET0_ENABLE_mask); + } +} + +static void evergreenDepthFunc(GLcontext * ctx, GLenum func) //same +{ + evergreenSetDepthState(ctx); +} + +static void evergreenDepthMask(GLcontext * ctx, GLboolean mask) //same +{ + evergreenSetDepthState(ctx); +} + +static void evergreenCullFace(GLcontext * ctx, GLenum mode) //same +{ + evergreenUpdateCulling(ctx); +} + +static void evergreenFogfv(GLcontext * ctx, GLenum pname, const GLfloat * param) //same +{ +} + +static void evergreenUpdatePolygonMode(GLcontext * ctx) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, pa); + + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, X_DISABLE_POLY_MODE, POLY_MODE_shift, POLY_MODE_mask); + + /* Only do something if a polygon mode is wanted, default is GL_FILL */ + if (ctx->Polygon.FrontMode != GL_FILL || + ctx->Polygon.BackMode != GL_FILL) { + GLenum f, b; + + /* Handle GL_CW (clock wise and GL_CCW (counter clock wise) + * correctly by selecting the correct front and back face + */ + f = ctx->Polygon.FrontMode; + b = ctx->Polygon.BackMode; + + /* Enable polygon mode */ + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, X_DUAL_MODE, POLY_MODE_shift, POLY_MODE_mask); + + switch (f) { + case GL_LINE: + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, X_DRAW_LINES, + POLYMODE_FRONT_PTYPE_shift, POLYMODE_FRONT_PTYPE_mask); + break; + case GL_POINT: + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, X_DRAW_POINTS, + POLYMODE_FRONT_PTYPE_shift, POLYMODE_FRONT_PTYPE_mask); + break; + case GL_FILL: + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, X_DRAW_TRIANGLES, + POLYMODE_FRONT_PTYPE_shift, POLYMODE_FRONT_PTYPE_mask); + break; + } + + switch (b) { + case GL_LINE: + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, X_DRAW_LINES, + POLYMODE_BACK_PTYPE_shift, POLYMODE_BACK_PTYPE_mask); + break; + case GL_POINT: + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, X_DRAW_POINTS, + POLYMODE_BACK_PTYPE_shift, POLYMODE_BACK_PTYPE_mask); + break; + case GL_FILL: + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, X_DRAW_TRIANGLES, + POLYMODE_BACK_PTYPE_shift, POLYMODE_BACK_PTYPE_mask); + break; + } + } +} + +static void evergreenFrontFace(GLcontext * ctx, GLenum mode) //same +{ + evergreenUpdateCulling(ctx); + evergreenUpdatePolygonMode(ctx); +} + +static void evergreenShadeModel(GLcontext * ctx, GLenum mode) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, spi); + + /* also need to set/clear FLAT_SHADE bit per param in SPI_PS_INPUT_CNTL_[0-31] */ + switch (mode) { + case GL_FLAT: + SETbit(evergreen->SPI_INTERP_CONTROL_0.u32All, FLAT_SHADE_ENA_bit); + break; + case GL_SMOOTH: + CLEARbit(evergreen->SPI_INTERP_CONTROL_0.u32All, FLAT_SHADE_ENA_bit); + break; + default: + return; + } +} + +static void evergreenLogicOpcode(GLcontext *ctx, GLenum logicop) //diff +{ + if (RGBA_LOGICOP_ENABLED(ctx)) + evergreenSetLogicOpState(ctx); +} + +static void evergreenPointSize(GLcontext * ctx, GLfloat size) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, pa); + + /* We need to clamp to user defined range here, because + * the HW clamping happens only for per vertex point size. */ + size = CLAMP(size, ctx->Point.MinSize, ctx->Point.MaxSize); + + /* same size limits for AA, non-AA points */ + size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize); + + /* format is 12.4 fixed point */ + SETfield(evergreen->PA_SU_POINT_SIZE.u32All, (int)(size * 8.0), + PA_SU_POINT_SIZE__HEIGHT_shift, PA_SU_POINT_SIZE__HEIGHT_mask); + SETfield(evergreen->PA_SU_POINT_SIZE.u32All, (int)(size * 8.0), + PA_SU_POINT_SIZE__WIDTH_shift, PA_SU_POINT_SIZE__WIDTH_mask); + +} + +static void evergreenPointParameter(GLcontext * ctx, GLenum pname, const GLfloat * param) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, pa); + + /* format is 12.4 fixed point */ + switch (pname) { + case GL_POINT_SIZE_MIN: + SETfield(evergreen->PA_SU_POINT_MINMAX.u32All, (int)(ctx->Point.MinSize * 8.0), + MIN_SIZE_shift, MIN_SIZE_mask); + evergreenPointSize(ctx, ctx->Point.Size); + break; + case GL_POINT_SIZE_MAX: + SETfield(evergreen->PA_SU_POINT_MINMAX.u32All, (int)(ctx->Point.MaxSize * 8.0), + MAX_SIZE_shift, MAX_SIZE_mask); + evergreenPointSize(ctx, ctx->Point.Size); + break; + case GL_POINT_DISTANCE_ATTENUATION: + break; + case GL_POINT_FADE_THRESHOLD_SIZE: + break; + default: + break; + } +} + +static int evergreen_translate_stencil_func(int func) //same +{ + switch (func) { + case GL_NEVER: + return REF_NEVER; + case GL_LESS: + return REF_LESS; + case GL_EQUAL: + return REF_EQUAL; + case GL_LEQUAL: + return REF_LEQUAL; + case GL_GREATER: + return REF_GREATER; + case GL_NOTEQUAL: + return REF_NOTEQUAL; + case GL_GEQUAL: + return REF_GEQUAL; + case GL_ALWAYS: + return REF_ALWAYS; + } + return 0; +} + +static void evergreenStencilFuncSeparate(GLcontext * ctx, GLenum face, + GLenum func, GLint ref, GLuint mask) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + const unsigned back = ctx->Stencil._BackFace; + + + EVERGREEN_STATECHANGE(context, db); + + //front + SETfield(evergreen->DB_STENCILREFMASK.u32All, ctx->Stencil.Ref[0], + STENCILREF_shift, STENCILREF_mask); + SETfield(evergreen->DB_STENCILREFMASK.u32All, ctx->Stencil.ValueMask[0], + STENCILMASK_shift, STENCILMASK_mask); + + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, evergreen_translate_stencil_func(ctx->Stencil.Function[0]), + STENCILFUNC_shift, STENCILFUNC_mask); + + //back + SETfield(evergreen->DB_STENCILREFMASK_BF.u32All, ctx->Stencil.Ref[back], + STENCILREF_BF_shift, STENCILREF_BF_mask); + SETfield(evergreen->DB_STENCILREFMASK_BF.u32All, ctx->Stencil.ValueMask[back], + STENCILMASK_BF_shift, STENCILMASK_BF_mask); + + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, evergreen_translate_stencil_func(ctx->Stencil.Function[back]), + STENCILFUNC_BF_shift, STENCILFUNC_BF_mask); +} + +static void evergreenStencilMaskSeparate(GLcontext * ctx, GLenum face, GLuint mask) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + const unsigned back = ctx->Stencil._BackFace; + + EVERGREEN_STATECHANGE(context, db); + + // front + SETfield(evergreen->DB_STENCILREFMASK.u32All, ctx->Stencil.WriteMask[0], + STENCILWRITEMASK_shift, STENCILWRITEMASK_mask); + + // back + SETfield(evergreen->DB_STENCILREFMASK_BF.u32All, ctx->Stencil.WriteMask[back], + STENCILWRITEMASK_BF_shift, STENCILWRITEMASK_BF_mask); + +} + +static int evergreen_translate_stencil_op(int op) //same +{ + switch (op) { + case GL_KEEP: + return STENCIL_KEEP; + case GL_ZERO: + return STENCIL_ZERO; + case GL_REPLACE: + return STENCIL_REPLACE; + case GL_INCR: + return STENCIL_INCR_CLAMP; + case GL_DECR: + return STENCIL_DECR_CLAMP; + case GL_INCR_WRAP_EXT: + return STENCIL_INCR_WRAP; + case GL_DECR_WRAP_EXT: + return STENCIL_DECR_WRAP; + case GL_INVERT: + return STENCIL_INVERT; + default: + WARN_ONCE("Do not know how to translate stencil op"); + return STENCIL_KEEP; + } + return 0; +} + +static void evergreenStencilOpSeparate(GLcontext * ctx, GLenum face, + GLenum fail, GLenum zfail, GLenum zpass) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + const unsigned back = ctx->Stencil._BackFace; + + EVERGREEN_STATECHANGE(context, db); + + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, evergreen_translate_stencil_op(ctx->Stencil.FailFunc[0]), + STENCILFAIL_shift, STENCILFAIL_mask); + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, evergreen_translate_stencil_op(ctx->Stencil.ZFailFunc[0]), + STENCILZFAIL_shift, STENCILZFAIL_mask); + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, evergreen_translate_stencil_op(ctx->Stencil.ZPassFunc[0]), + STENCILZPASS_shift, STENCILZPASS_mask); + + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, evergreen_translate_stencil_op(ctx->Stencil.FailFunc[back]), + STENCILFAIL_BF_shift, STENCILFAIL_BF_mask); + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, evergreen_translate_stencil_op(ctx->Stencil.ZFailFunc[back]), + STENCILZFAIL_BF_shift, STENCILZFAIL_BF_mask); + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, evergreen_translate_stencil_op(ctx->Stencil.ZPassFunc[back]), + STENCILZPASS_BF_shift, STENCILZPASS_BF_mask); +} + +static void evergreenViewport(GLcontext * ctx, + GLint x, + GLint y, + GLsizei width, + GLsizei height) //diff in evergreenUpdateWindow +{ + evergreenUpdateWindow(ctx, 0); + + radeon_viewport(ctx, x, y, width, height); +} + +static void evergreenDepthRange(GLcontext * ctx, GLclampd nearval, GLclampd farval) //diff in evergreenUpdateWindow +{ + evergreenUpdateWindow(ctx, 0); +} + +static void evergreenLineWidth(GLcontext * ctx, GLfloat widthf) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + uint32_t lineWidth = (uint32_t)((widthf * 0.5) * (1 << 4)); + + EVERGREEN_STATECHANGE(context, pa); + + if (lineWidth > 0xFFFF) + lineWidth = 0xFFFF; + SETfield(evergreen->PA_SU_LINE_CNTL.u32All,(uint16_t)lineWidth, + PA_SU_LINE_CNTL__WIDTH_shift, PA_SU_LINE_CNTL__WIDTH_mask); +} + +static void evergreenLineStipple(GLcontext *ctx, GLint factor, GLushort pattern) //same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + EVERGREEN_STATECHANGE(context, pa); + + SETfield(evergreen->PA_SC_LINE_STIPPLE.u32All, pattern, LINE_PATTERN_shift, LINE_PATTERN_mask); + SETfield(evergreen->PA_SC_LINE_STIPPLE.u32All, (factor-1), REPEAT_COUNT_shift, REPEAT_COUNT_mask); + SETfield(evergreen->PA_SC_LINE_STIPPLE.u32All, 1, AUTO_RESET_CNTL_shift, AUTO_RESET_CNTL_mask); +} + +static void evergreenPolygonOffset(GLcontext * ctx, GLfloat factor, GLfloat units) //diff : + //all register here offset diff, bits same +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + GLfloat constant = units; + GLchar depth = 0; + + EVERGREEN_STATECHANGE(context, pa); + + switch (ctx->Visual.depthBits) { + case 16: + constant *= 4.0; + depth = -16; + break; + case 24: + constant *= 2.0; + depth = -24; + break; + } + + factor *= 12.0; + SETfield(evergreen->PA_SU_POLY_OFFSET_DB_FMT_CNTL.u32All, depth, + POLY_OFFSET_NEG_NUM_DB_BITS_shift, POLY_OFFSET_NEG_NUM_DB_BITS_mask); + //evergreen->PA_SU_POLY_OFFSET_CLAMP.f32All = constant; //??? + evergreen->PA_SU_POLY_OFFSET_FRONT_SCALE.f32All = factor; + evergreen->PA_SU_POLY_OFFSET_FRONT_OFFSET.f32All = constant; + evergreen->PA_SU_POLY_OFFSET_BACK_SCALE.f32All = factor; + evergreen->PA_SU_POLY_OFFSET_BACK_OFFSET.f32All = constant; +} + +static void evergreenPolygonMode(GLcontext * ctx, GLenum face, GLenum mode) //same +{ + (void)face; + (void)mode; + + evergreenUpdatePolygonMode(ctx); +} + +static void evergreenRenderMode(GLcontext * ctx, GLenum mode) //same +{ +} + +//TODO : move to kernel. +static void evergreenInitSQConfig(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + uint32_t uSqNumCfInsts, uMaxGPRs, uMaxThreads, uMaxStackEntries, uPSThreadCount, uOtherThreadCount; + uint32_t NUM_PS_GPRS, NUM_VS_GPRS, NUM_GS_GPRS, NUM_ES_GPRS, NUM_HS_GPRS, NUM_LS_GPRS, NUM_CLAUSE_TEMP_GPRS; + GLboolean bVC_ENABLE = GL_TRUE; + + R600_STATECHANGE(context, sq); + + switch (context->radeon.radeonScreen->chip_family) + { + case CHIP_FAMILY_CEDAR: + uSqNumCfInsts = 1; + bVC_ENABLE = GL_FALSE; + uMaxGPRs = 256; + uPSThreadCount = 96; + uMaxThreads = 192; + uMaxStackEntries = 256; + break; + case CHIP_FAMILY_REDWOOD: + uSqNumCfInsts = 2; + bVC_ENABLE = GL_TRUE; + uMaxGPRs = 256; + uPSThreadCount = 128; + uMaxThreads = 248; + uMaxStackEntries = 256; + break; + case CHIP_FAMILY_JUNIPER: + uSqNumCfInsts = 2; + bVC_ENABLE = GL_TRUE; + uMaxGPRs = 256; + uPSThreadCount = 128; + uMaxThreads = 248; + uMaxStackEntries = 512; + break; + case CHIP_FAMILY_CYPRESS: + uSqNumCfInsts = 2; + bVC_ENABLE = GL_TRUE; + uMaxGPRs = 256; + uPSThreadCount = 128; + uMaxThreads = 248; + uMaxStackEntries = 512; + break; + case CHIP_FAMILY_HEMLOCK: + uSqNumCfInsts = 2;//? + bVC_ENABLE = GL_TRUE; + uMaxGPRs = 256; + uPSThreadCount = 128; + uMaxThreads = 248; + uMaxStackEntries = 512; + break; + default: + uSqNumCfInsts = 2; + bVC_ENABLE = GL_TRUE; + uMaxGPRs = 256; + uPSThreadCount = 128; + uMaxThreads = 248; + uMaxStackEntries = 512; + break; + } + + evergreen->evergreen_config.SQ_DYN_GPR_CNTL_PS_FLUSH_REQ.u32All = 0; + + evergreen->evergreen_config.SPI_CONFIG_CNTL.u32All = 0; + evergreen->evergreen_config.SPI_CONFIG_CNTL_1.u32All = 0; + SETfield(evergreen->evergreen_config.SPI_CONFIG_CNTL_1.u32All, 4, + EG_SPI_CONFIG_CNTL_1__VTX_DONE_DELAY_shift, + EG_SPI_CONFIG_CNTL_1__VTX_DONE_DELAY_mask); + + evergreen->evergreen_config.CP_PERFMON_CNTL.u32All = 0; + + evergreen->evergreen_config.SQ_MS_FIFO_SIZES.u32All = 0; + SETfield(evergreen->evergreen_config.SQ_MS_FIFO_SIZES.u32All, 16 * uSqNumCfInsts, + EG_SQ_MS_FIFO_SIZES__CACHE_FIFO_SIZE_shift, + EG_SQ_MS_FIFO_SIZES__CACHE_FIFO_SIZE_mask); + SETfield(evergreen->evergreen_config.SQ_MS_FIFO_SIZES.u32All, 0x4, + EG_SQ_MS_FIFO_SIZES__FETCH_FIFO_HIWATER_shift, + EG_SQ_MS_FIFO_SIZES__FETCH_FIFO_HIWATER_mask); + SETfield(evergreen->evergreen_config.SQ_MS_FIFO_SIZES.u32All, 0xE0, + EG_SQ_MS_FIFO_SIZES__DONE_FIFO_HIWATER_shift, + EG_SQ_MS_FIFO_SIZES__DONE_FIFO_HIWATER_mask); + SETfield(evergreen->evergreen_config.SQ_MS_FIFO_SIZES.u32All, 0x8, + EG_SQ_MS_FIFO_SIZES__ALU_UPDATE_FIFO_HIWATER_shift, + EG_SQ_MS_FIFO_SIZES__ALU_UPDATE_FIFO_HIWATER_mask); + + if(bVC_ENABLE == GL_TRUE) + { + SETbit(evergreen->evergreen_config.SQ_CONFIG.u32All, + EG_SQ_CONFIG__VC_ENABLE_bit); + } + else + { + CLEARbit(evergreen->evergreen_config.SQ_CONFIG.u32All, + EG_SQ_CONFIG__VC_ENABLE_bit); + } + SETbit(evergreen->evergreen_config.SQ_CONFIG.u32All, + EG_SQ_CONFIG__EXPORT_SRC_C_bit); + SETfield(evergreen->evergreen_config.SQ_CONFIG.u32All, 0, + EG_SQ_CONFIG__PS_PRIO_shift, + EG_SQ_CONFIG__PS_PRIO_mask); + SETfield(evergreen->evergreen_config.SQ_CONFIG.u32All, 1, + EG_SQ_CONFIG__VS_PRIO_shift, + EG_SQ_CONFIG__VS_PRIO_mask); + SETfield(evergreen->evergreen_config.SQ_CONFIG.u32All, 2, + EG_SQ_CONFIG__GS_PRIO_shift, + EG_SQ_CONFIG__GS_PRIO_mask); + SETfield(evergreen->evergreen_config.SQ_CONFIG.u32All, 3, + EG_SQ_CONFIG__ES_PRIO_shift, + EG_SQ_CONFIG__ES_PRIO_mask); + + NUM_CLAUSE_TEMP_GPRS = 4; + NUM_PS_GPRS = ((uMaxGPRs-(4*2))*12/32); // 93 + NUM_VS_GPRS = ((uMaxGPRs-(4*2))*6/32); // 46 + NUM_GS_GPRS = ((uMaxGPRs-(4*2))*4/32); // 31 + NUM_ES_GPRS = ((uMaxGPRs-(4*2))*4/32); // 31 + NUM_HS_GPRS = ((uMaxGPRs-(4*2))*3/32); // 23 + NUM_LS_GPRS = ((uMaxGPRs-(4*2))*3/32); // 23 + + evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_1.u32All = 0; + evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_2.u32All = 0; + evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_3.u32All = 0; + + SETfield(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_1.u32All, NUM_PS_GPRS, + NUM_PS_GPRS_shift, NUM_PS_GPRS_mask); + SETfield(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_1.u32All, NUM_VS_GPRS, + NUM_VS_GPRS_shift, NUM_VS_GPRS_mask); + SETfield(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_1.u32All, NUM_CLAUSE_TEMP_GPRS, + NUM_CLAUSE_TEMP_GPRS_shift, NUM_CLAUSE_TEMP_GPRS_mask); + SETfield(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_2.u32All, NUM_GS_GPRS, + NUM_GS_GPRS_shift, NUM_GS_GPRS_mask); + SETfield(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_2.u32All, NUM_ES_GPRS, + NUM_ES_GPRS_shift, NUM_ES_GPRS_mask); + SETfield(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_3.u32All, NUM_HS_GPRS, + NUM_PS_GPRS_shift, NUM_PS_GPRS_mask); + SETfield(evergreen->evergreen_config.SQ_GPR_RESOURCE_MGMT_3.u32All, NUM_LS_GPRS, + NUM_VS_GPRS_shift, NUM_VS_GPRS_mask); + + uOtherThreadCount = (((uMaxThreads-uPSThreadCount)/6)/8)*8; + evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT.u32All = 0; + evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT_2.u32All = 0; + SETfield(evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT.u32All, uPSThreadCount, + NUM_PS_THREADS_shift, NUM_PS_THREADS_mask); + SETfield(evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT.u32All, uOtherThreadCount, + NUM_VS_THREADS_shift, NUM_VS_THREADS_mask); + SETfield(evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT.u32All, uOtherThreadCount, + NUM_GS_THREADS_shift, NUM_GS_THREADS_mask); + SETfield(evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT.u32All, uOtherThreadCount, + NUM_ES_THREADS_shift, NUM_ES_THREADS_mask); + SETfield(evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT_2.u32All, uOtherThreadCount, + NUM_PS_THREADS_shift, NUM_PS_THREADS_mask); + SETfield(evergreen->evergreen_config.SQ_THREAD_RESOURCE_MGMT_2.u32All, uOtherThreadCount, + NUM_VS_THREADS_shift, NUM_VS_THREADS_mask); + + uMaxStackEntries = ((uMaxStackEntries*1)/6); + evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_1.u32All = 0; + evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_2.u32All = 0; + evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_3.u32All = 0; + SETfield(evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_1.u32All, uMaxStackEntries, + NUM_PS_STACK_ENTRIES_shift, NUM_PS_STACK_ENTRIES_mask); + SETfield(evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_1.u32All, uMaxStackEntries, + NUM_VS_STACK_ENTRIES_shift, NUM_VS_STACK_ENTRIES_mask); + SETfield(evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_2.u32All, uMaxStackEntries, + NUM_GS_STACK_ENTRIES_shift, NUM_GS_STACK_ENTRIES_mask); + SETfield(evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_2.u32All, uMaxStackEntries, + NUM_ES_STACK_ENTRIES_shift, NUM_ES_STACK_ENTRIES_mask); + SETfield(evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_3.u32All, uMaxStackEntries, + NUM_PS_STACK_ENTRIES_shift, NUM_PS_STACK_ENTRIES_mask); + SETfield(evergreen->evergreen_config.SQ_STACK_RESOURCE_MGMT_3.u32All, uMaxStackEntries, + NUM_VS_STACK_ENTRIES_shift, NUM_VS_STACK_ENTRIES_mask); + + evergreen->evergreen_config.PA_SC_FORCE_EOV_MAX_CNTS.u32All = 0; + SETfield(evergreen->evergreen_config.PA_SC_FORCE_EOV_MAX_CNTS.u32All, 4095, + EG_PA_SC_FORCE_EOV_MAX_CNTS__FORCE_EOV_MAX_CLK_CNT_shift, + EG_PA_SC_FORCE_EOV_MAX_CNTS__FORCE_EOV_MAX_CLK_CNT_mask); + SETfield(evergreen->evergreen_config.PA_SC_FORCE_EOV_MAX_CNTS.u32All, 255, + EG_PA_SC_FORCE_EOV_MAX_CNTS__FORCE_EOV_MAX_REZ_CNT_shift, + EG_PA_SC_FORCE_EOV_MAX_CNTS__FORCE_EOV_MAX_REZ_CNT_mask); + + evergreen->evergreen_config.VGT_CACHE_INVALIDATION.u32All = 0; + SETfield(evergreen->evergreen_config.VGT_CACHE_INVALIDATION.u32All, 2, + EG_VGT_CACHE_INVALIDATION__CACHE_INVALIDATION_shift, + EG_VGT_CACHE_INVALIDATION__CACHE_INVALIDATION_mask); + + evergreen->evergreen_config.VGT_GS_VERTEX_REUSE.u32All = 0; + SETfield(evergreen->evergreen_config.VGT_GS_VERTEX_REUSE.u32All, 16, + VERT_REUSE_shift, + VERT_REUSE_mask); + + evergreen->evergreen_config.PA_SC_LINE_STIPPLE_STATE.u32All = 0; + + evergreen->evergreen_config.PA_CL_ENHANCE.u32All = 0; + SETbit(evergreen->evergreen_config.PA_CL_ENHANCE.u32All, + CLIP_VTX_REORDER_ENA_bit); + SETfield(evergreen->evergreen_config.PA_CL_ENHANCE.u32All, 3, + NUM_CLIP_SEQ_shift, + NUM_CLIP_SEQ_mask); +} + +void evergreenInitState(GLcontext * ctx) //diff +{ + context_t *context = R700_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + + int id = 0; + + //calloc should have done this + memset(evergreen, 0, sizeof(EVERGREEN_CHIP_CONTEXT)); + + // Disable window clipping and offset: + SETfield(evergreen->PA_SC_WINDOW_OFFSET.u32All, 0, + EG_PA_SC_WINDOW_OFFSET__WINDOW_X_OFFSET_shift, EG_PA_SC_WINDOW_OFFSET__WINDOW_X_OFFSET_mask); + SETfield(evergreen->PA_SC_WINDOW_OFFSET.u32All, 0, + EG_PA_SC_WINDOW_OFFSET__WINDOW_Y_OFFSET_shift, EG_PA_SC_WINDOW_OFFSET__WINDOW_Y_OFFSET_mask); + + SETbit(evergreen->PA_SC_WINDOW_SCISSOR_TL.u32All, WINDOW_OFFSET_DISABLE_bit); + + evergreen->PA_SC_CLIPRECT_RULE.u32All = 0x0000FFFF; + + evergreen->PA_SC_EDGERULE.u32All = 0xAAAAAAAA; + + // Set up Z min/max: + evergreen->viewport[id].PA_SC_VPORT_ZMIN_0.f32All = 0.0; + evergreen->viewport[id].PA_SC_VPORT_ZMAX_0.f32All = 1.0; + + SETfield(evergreen->CB_TARGET_MASK.u32All, 0xF, TARGET0_ENABLE_shift, TARGET0_ENABLE_mask); + SETfield(evergreen->CB_SHADER_MASK.u32All, 0xF, OUTPUT0_ENABLE_shift, OUTPUT0_ENABLE_mask); + + SETfield(evergreen->SPI_BARYC_CNTL.u32All, 1, + EG_SPI_BARYC_CNTL__PERSP_CENTROID_ENA_shift, + EG_SPI_BARYC_CNTL__PERSP_CENTROID_ENA_mask); + SETfield(evergreen->SPI_BARYC_CNTL.u32All, 1, + EG_SPI_BARYC_CNTL__LINEAR_CENTROID_ENA_shift, + EG_SPI_BARYC_CNTL__LINEAR_CENTROID_ENA_mask); + + // Turn off vgt reuse: + evergreen->VGT_REUSE_OFF.u32All = 0; + SETbit(evergreen->VGT_REUSE_OFF.u32All, REUSE_OFF_bit); + + // Specify offsetting and clamp values for vertices: + evergreen->VGT_MAX_VTX_INDX.u32All = 0xFFFFFF; + evergreen->VGT_MIN_VTX_INDX.u32All = 0; + evergreen->VGT_INDX_OFFSET.u32All = 0; + + evergreen->VGT_DMA_NUM_INSTANCES.u32All = 1; + + // Do not alpha blend: + SETfield(evergreen->SX_ALPHA_TEST_CONTROL.u32All, REF_NEVER, + ALPHA_FUNC_shift, ALPHA_FUNC_mask); + CLEARbit(evergreen->SX_ALPHA_TEST_CONTROL.u32All, ALPHA_TEST_ENABLE_bit); + + evergreen->SPI_VS_OUT_ID_0.u32All = 0x03020100; + evergreen->SPI_VS_OUT_ID_1.u32All = 0x07060504; + + evergreen->SPI_PS_INPUT_CNTL[0].u32All = 0x00000800; + evergreen->SPI_PS_INPUT_CNTL[1].u32All = 0x00000801; + evergreen->SPI_PS_INPUT_CNTL[2].u32All = 0x00000802; + + + // Depth buffer currently disabled: + evergreen->DB_DEPTH_CONTROL.u32All = 0; + SETbit(evergreen->DB_DEPTH_CONTROL.u32All, Z_WRITE_ENABLE_bit); + SETfield(evergreen->DB_DEPTH_CONTROL.u32All, FRAG_ALWAYS, + ZFUNC_shift, ZFUNC_mask); + + evergreen->DB_Z_READ_BASE.u32All = 0; + evergreen->DB_Z_WRITE_BASE.u32All = 0; + + evergreen->DB_DEPTH_CLEAR.f32All = 1.0; + + evergreen->DB_DEPTH_VIEW.u32All = 0; + + evergreen->DB_SHADER_CONTROL.u32All = 0; + SETbit(evergreen->DB_SHADER_CONTROL.u32All, EG_DB_SHADER_CONTROL__DUAL_EXPORT_ENABLE_bit); + + evergreen->DB_Z_INFO.u32All = 0; + SETfield(evergreen->DB_Z_INFO.u32All , ARRAY_1D_TILED_THIN1, + EG_DB_Z_INFO__ARRAY_MODE_shift, EG_DB_Z_INFO__ARRAY_MODE_mask); + SETfield(evergreen->DB_Z_INFO.u32All , EG_Z_24, + EG_DB_Z_INFO__FORMAT_shift, EG_DB_Z_INFO__FORMAT_mask); + SETfield(evergreen->DB_Z_INFO.u32All , EG_ADDR_SURF_TILE_SPLIT_256B, + EG_DB_Z_INFO__TILE_SPLIT_shift, EG_DB_Z_INFO__TILE_SPLIT_mask); + SETfield(evergreen->DB_Z_INFO.u32All , EG_ADDR_SURF_8_BANK, + EG_DB_Z_INFO__NUM_BANKS_shift, EG_DB_Z_INFO__NUM_BANKS_mask); + SETfield(evergreen->DB_Z_INFO.u32All , EG_ADDR_SURF_BANK_WIDTH_1, + EG_DB_Z_INFO__BANK_WIDTH_shift, EG_DB_Z_INFO__BANK_WIDTH_mask); + SETfield(evergreen->DB_Z_INFO.u32All , EG_ADDR_SURF_BANK_HEIGHT_1, + EG_DB_Z_INFO__BANK_HEIGHT_shift, EG_DB_Z_INFO__BANK_HEIGHT_mask); + + evergreen->DB_STENCIL_INFO.u32All = 0; + CLEARbit(evergreen->DB_STENCIL_INFO.u32All, EG_DB_STENCIL_INFO__FORMAT_bit); + SETfield(evergreen->DB_STENCIL_INFO.u32All, EG_ADDR_SURF_TILE_SPLIT_256B, + EG_DB_STENCIL_INFO__TILE_SPLIT_shift, EG_DB_STENCIL_INFO__TILE_SPLIT_mask); + + evergreen->DB_RENDER_CONTROL.u32All = 0; + + evergreen->DB_RENDER_OVERRIDE.u32All = 0; + SETfield(evergreen->DB_RENDER_OVERRIDE.u32All, FORCE_DISABLE, FORCE_HIZ_ENABLE_shift, FORCE_HIZ_ENABLE_mask); + SETfield(evergreen->DB_RENDER_OVERRIDE.u32All, FORCE_DISABLE, FORCE_HIS_ENABLE0_shift, FORCE_HIS_ENABLE0_mask); + SETfield(evergreen->DB_RENDER_OVERRIDE.u32All, FORCE_DISABLE, FORCE_HIS_ENABLE1_shift, FORCE_HIS_ENABLE1_mask); + + // Disable ROP3 modes by setting src to dst copy: + SETfield(evergreen->CB_COLOR_CONTROL.u32All, 0xCC, + EG_CB_COLOR_CONTROL__ROP3_shift, + EG_CB_COLOR_CONTROL__ROP3_mask); + SETfield(evergreen->CB_COLOR_CONTROL.u32All, EG_CB_NORMAL, + EG_CB_COLOR_CONTROL__MODE_shift, + EG_CB_COLOR_CONTROL__MODE_mask); + + SETfield(evergreen->CB_BLEND0_CONTROL.u32All, + BLEND_ONE, COLOR_SRCBLEND_shift, COLOR_SRCBLEND_mask); + + SETfield(evergreen->CB_BLEND0_CONTROL.u32All, + BLEND_ONE, ALPHA_SRCBLEND_shift, ALPHA_SRCBLEND_mask); + + //evergreen->PA_CL_CLIP_CNTL.CLIP_DISABLE = 1; + + SETbit(evergreen->PA_CL_CLIP_CNTL.u32All, DX_LINEAR_ATTR_CLIP_ENA_bit); + + // Set up the culling control register: + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, 2, + POLYMODE_FRONT_PTYPE_shift, POLYMODE_FRONT_PTYPE_mask); // draw using triangles + SETfield(evergreen->PA_SU_SC_MODE_CNTL.u32All, 2, + POLYMODE_BACK_PTYPE_shift, POLYMODE_BACK_PTYPE_mask); // draw using triangles + + // Do scale XY or X by 1/W0. eg: + evergreen->bEnablePerspective = GL_TRUE; + + CLEARbit(evergreen->PA_CL_VTE_CNTL.u32All, VTX_XY_FMT_bit); + CLEARbit(evergreen->PA_CL_VTE_CNTL.u32All, VTX_Z_FMT_bit); + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VTX_W0_FMT_bit); + + // Enable viewport scaling for all three axis: + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VPORT_X_SCALE_ENA_bit); + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VPORT_X_OFFSET_ENA_bit); + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VPORT_Y_SCALE_ENA_bit); + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VPORT_Y_OFFSET_ENA_bit); + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VPORT_Z_SCALE_ENA_bit); + SETbit(evergreen->PA_CL_VTE_CNTL.u32All, VPORT_Z_OFFSET_ENA_bit); + + // Set up point sizes and min/max values: + SETfield(evergreen->PA_SU_POINT_SIZE.u32All, 0x8, + PA_SU_POINT_SIZE__HEIGHT_shift, PA_SU_POINT_SIZE__HEIGHT_mask); + SETfield(evergreen->PA_SU_POINT_SIZE.u32All, 0x8, + PA_SU_POINT_SIZE__WIDTH_shift, PA_SU_POINT_SIZE__WIDTH_mask); + CLEARfield(evergreen->PA_SU_POINT_MINMAX.u32All, MIN_SIZE_mask); + SETfield(evergreen->PA_SU_POINT_MINMAX.u32All, 0x8000, MAX_SIZE_shift, MAX_SIZE_mask); + SETfield(evergreen->PA_SU_LINE_CNTL.u32All,0x8, + PA_SU_LINE_CNTL__WIDTH_shift, PA_SU_LINE_CNTL__WIDTH_mask); + + // Set up line control: + evergreen->PA_SC_LINE_CNTL.u32All = 0; + CLEARbit(evergreen->PA_SC_LINE_CNTL.u32All, EXPAND_LINE_WIDTH_bit); + SETbit(evergreen->PA_SC_LINE_CNTL.u32All, LAST_PIXEL_bit); + + // Set up vertex control: + evergreen->PA_SU_VTX_CNTL.u32All = 0; + CLEARfield(evergreen->PA_SU_VTX_CNTL.u32All, QUANT_MODE_mask); + SETbit(evergreen->PA_SU_VTX_CNTL.u32All, PIX_CENTER_bit); + SETfield(evergreen->PA_SU_VTX_CNTL.u32All, X_ROUND_TO_EVEN, + PA_SU_VTX_CNTL__ROUND_MODE_shift, PA_SU_VTX_CNTL__ROUND_MODE_mask); + + // to 1.0 = no guard band: + evergreen->PA_CL_GB_VERT_CLIP_ADJ.u32All = 0x3F800000; // 1.0 + evergreen->PA_CL_GB_VERT_DISC_ADJ.u32All = 0x3F800000; // 1.0 + evergreen->PA_CL_GB_HORZ_CLIP_ADJ.u32All = 0x3F800000; // 1.0 + evergreen->PA_CL_GB_HORZ_DISC_ADJ.u32All = 0x3F800000; // 1.0 + + // Diable color compares: + SETfield(evergreen->CB_CLRCMP_CONTROL.u32All, CLRCMP_DRAW_ALWAYS, + CLRCMP_FCN_SRC_shift, CLRCMP_FCN_SRC_mask); + SETfield(evergreen->CB_CLRCMP_CONTROL.u32All, CLRCMP_DRAW_ALWAYS, + CLRCMP_FCN_DST_shift, CLRCMP_FCN_DST_mask); + SETfield(evergreen->CB_CLRCMP_CONTROL.u32All, CLRCMP_SEL_SRC, + CLRCMP_FCN_SEL_shift, CLRCMP_FCN_SEL_mask); + + // Zero out source: + evergreen->CB_CLRCMP_SRC.u32All = 0x00000000; + + // Put a compare color in for error checking: + evergreen->CB_CLRCMP_DST.u32All = 0x000000FF; + + // Set up color compare mask: + evergreen->CB_CLRCMP_MSK.u32All = 0xFFFFFFFF; + + // Enable all samples for multi-sample anti-aliasing: + evergreen->PA_SC_AA_MASK.u32All = 0xFFFFFFFF; + // Turn off AA: + evergreen->PA_SC_AA_CONFIG.u32All = 0; + + SETfield(evergreen->VGT_OUT_DEALLOC_CNTL.u32All, 16, + DEALLOC_DIST_shift, DEALLOC_DIST_mask); + SETfield(evergreen->VGT_VERTEX_REUSE_BLOCK_CNTL.u32All, 14, + VTX_REUSE_DEPTH_shift, VTX_REUSE_DEPTH_mask); + + evergreen->SX_MISC.u32All = 0; + + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, 1, + EG_CB_COLOR0_INFO__SOURCE_FORMAT_shift, EG_CB_COLOR0_INFO__SOURCE_FORMAT_mask); + SETbit(evergreen->render_target[id].CB_COLOR0_INFO.u32All, EG_CB_COLOR0_INFO__BLEND_CLAMP_bit); + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, 0, + EG_CB_COLOR0_INFO__NUMBER_TYPE_shift, EG_CB_COLOR0_INFO__NUMBER_TYPE_mask); + + SETfield(evergreen->render_target[id].CB_COLOR0_INFO.u32All, SWAP_STD, + EG_CB_COLOR0_INFO__COMP_SWAP_shift, EG_CB_COLOR0_INFO__COMP_SWAP_mask); + + evergreen->render_target[id].CB_COLOR0_VIEW.u32All = 0; + evergreen->render_target[id].CB_COLOR0_CMASK.u32All = 0; + evergreen->render_target[id].CB_COLOR0_FMASK.u32All = 0; + evergreen->render_target[id].CB_COLOR0_FMASK_SLICE.u32All = 0; + + evergreenInitSQConfig(ctx); + + context->radeon.hw.all_dirty = GL_TRUE; +} + +void evergreenInitStateFuncs(radeonContextPtr radeon, struct dd_function_table *functions) +{ + functions->UpdateState = evergreenInvalidateState; + functions->AlphaFunc = evergreenAlphaFunc; + functions->BlendColor = evergreenBlendColor; + functions->BlendEquationSeparate = evergreenBlendEquationSeparate; + functions->BlendFuncSeparate = evergreenBlendFuncSeparate; + functions->Enable = evergreenEnable; + functions->ColorMask = evergreenColorMask; + functions->DepthFunc = evergreenDepthFunc; + functions->DepthMask = evergreenDepthMask; + functions->CullFace = evergreenCullFace; + functions->Fogfv = evergreenFogfv; + functions->FrontFace = evergreenFrontFace; + functions->ShadeModel = evergreenShadeModel; + functions->LogicOpcode = evergreenLogicOpcode; + + /* ARB_point_parameters */ + functions->PointParameterfv = evergreenPointParameter; + + /* Stencil related */ + functions->StencilFuncSeparate = evergreenStencilFuncSeparate; + functions->StencilMaskSeparate = evergreenStencilMaskSeparate; + functions->StencilOpSeparate = evergreenStencilOpSeparate; + + /* Viewport related */ + functions->Viewport = evergreenViewport; + functions->DepthRange = evergreenDepthRange; + functions->PointSize = evergreenPointSize; + functions->LineWidth = evergreenLineWidth; + functions->LineStipple = evergreenLineStipple; + + functions->PolygonOffset = evergreenPolygonOffset; + functions->PolygonMode = evergreenPolygonMode; + + functions->RenderMode = evergreenRenderMode; + + functions->ClipPlane = evergreenClipPlane; + + functions->Scissor = radeonScissor; + + functions->DrawBuffer = radeonDrawBuffer; + functions->ReadBuffer = radeonReadBuffer; + + if (radeon->radeonScreen->kernel_mm) { + functions->CopyPixels = _mesa_meta_CopyPixels; + functions->DrawPixels = _mesa_meta_DrawPixels; + functions->ReadPixels = radeonReadPixels; + } +} + + diff --git a/src/mesa/drivers/dri/r600/evergreen_state.h b/src/mesa/drivers/dri/r600/evergreen_state.h new file mode 100644 index 0000000000..ffdb56b38a --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_state.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008-2009 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#ifndef _EVERGREEN_STATE_H_ +#define _EVERGREEN_STATE_H_ + +#include "main/mtypes.h" + +#include "r600_context.h" + +extern void evergreenUpdateStateParameters(GLcontext * ctx, GLuint new_state); +extern void evergreenUpdateShaders(GLcontext * ctx); +extern void evergreenUpdateShaderStates(GLcontext * ctx); + +extern void evergreeUpdateShaders(GLcontext * ctx); + +extern void evergreenUpdateViewportOffset(GLcontext * ctx); + +extern void evergreenInitState(GLcontext * ctx); +extern void evergreenInitStateFuncs (radeonContextPtr radeon, struct dd_function_table *functions); + +extern void evergreenSetScissor(context_t *context); + +#endif /* _EVERGREEN_STATE_H_ */ diff --git a/src/mesa/drivers/dri/r600/evergreen_tex.c b/src/mesa/drivers/dri/r600/evergreen_tex.c new file mode 100644 index 0000000000..8b42045ebb --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_tex.c @@ -0,0 +1,1551 @@ +/* + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#include "main/glheader.h" +#include "main/imports.h" +#include "main/colormac.h" +#include "main/context.h" +#include "main/enums.h" +#include "main/image.h" +#include "main/teximage.h" +#include "main/mipmap.h" +#include "main/simple_list.h" +#include "main/texstore.h" +#include "main/texobj.h" + +#include "texmem.h" + +#include "r600_context.h" +#include "radeon_mipmap_tree.h" +#include "evergreen_diff.h" +#include "evergreen_tex.h" +#include "evergreen_fragprog.h" +#include "evergreen_vertprog.h" + +#include "r600_tex.h" + +static unsigned int evergreen_translate_wrap_mode(GLenum wrapmode) +{ + switch(wrapmode) { + case GL_REPEAT: return SQ_TEX_WRAP; + case GL_CLAMP: return SQ_TEX_CLAMP_HALF_BORDER; + case GL_CLAMP_TO_EDGE: return SQ_TEX_CLAMP_LAST_TEXEL; + case GL_CLAMP_TO_BORDER: return SQ_TEX_CLAMP_BORDER; + case GL_MIRRORED_REPEAT: return SQ_TEX_MIRROR; + case GL_MIRROR_CLAMP_EXT: return SQ_TEX_MIRROR_ONCE_HALF_BORDER; + case GL_MIRROR_CLAMP_TO_EDGE_EXT: return SQ_TEX_MIRROR_ONCE_LAST_TEXEL; + case GL_MIRROR_CLAMP_TO_BORDER_EXT: return SQ_TEX_MIRROR_ONCE_BORDER; + default: + radeon_error("bad wrap mode in %s", __FUNCTION__); + return 0; + } +} + +static GLboolean evergreenGetTexFormat(struct gl_texture_object *tObj, gl_format mesa_format) +{ + radeonTexObj *t = radeon_tex_obj(tObj); + + CLEARfield(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + CLEARfield(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + CLEARfield(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + CLEARfield(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + CLEARbit(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__FORCE_DEGAMMA_bit); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_X_shift, + FORMAT_COMP_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_Y_shift, + FORMAT_COMP_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_Z_shift, + FORMAT_COMP_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_W_shift, + FORMAT_COMP_W_mask); + + SETfield(t->SQ_TEX_RESOURCE1, ARRAY_LINEAR_GENERAL, + EG_SQ_TEX_RESOURCE_WORD1_0__ARRAY_MODE_shift, + EG_SQ_TEX_RESOURCE_WORD1_0__ARRAY_MODE_mask); + + switch (mesa_format) /* This is mesa format. */ + { + case MESA_FORMAT_RGBA8888: + case MESA_FORMAT_SIGNED_RGBA8888: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + if (mesa_format == MESA_FORMAT_SIGNED_RGBA8888) { + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_SIGNED, + FORMAT_COMP_X_shift, FORMAT_COMP_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_SIGNED, + FORMAT_COMP_Y_shift, FORMAT_COMP_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_SIGNED, + FORMAT_COMP_Z_shift, FORMAT_COMP_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_SIGNED, + FORMAT_COMP_W_shift, FORMAT_COMP_W_mask); + } + break; + case MESA_FORMAT_RGBA8888_REV: + case MESA_FORMAT_SIGNED_RGBA8888_REV: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + if (mesa_format == MESA_FORMAT_SIGNED_RGBA8888_REV) { + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_SIGNED, + FORMAT_COMP_X_shift, FORMAT_COMP_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_SIGNED, + FORMAT_COMP_Y_shift, FORMAT_COMP_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_SIGNED, + FORMAT_COMP_Z_shift, FORMAT_COMP_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_SIGNED, + FORMAT_COMP_W_shift, FORMAT_COMP_W_mask); + } + break; + case MESA_FORMAT_ARGB8888: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_XRGB8888: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_XRGB8888_REV: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_ARGB8888_REV: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_RGB888: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_RGB565: + SETfield(t->SQ_TEX_RESOURCE7, FMT_5_6_5, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_RGB565_REV: + SETfield(t->SQ_TEX_RESOURCE7, FMT_5_6_5, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_ARGB4444: + SETfield(t->SQ_TEX_RESOURCE7, FMT_4_4_4_4, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_ARGB4444_REV: + SETfield(t->SQ_TEX_RESOURCE7, FMT_4_4_4_4, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_ARGB1555: + SETfield(t->SQ_TEX_RESOURCE7, FMT_1_5_5_5, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_ARGB1555_REV: + SETfield(t->SQ_TEX_RESOURCE7, FMT_1_5_5_5, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_AL88: + case MESA_FORMAT_AL88_REV: /* TODO : Check this. */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_RGB332: + SETfield(t->SQ_TEX_RESOURCE7, FMT_3_3_2, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_A8: /* ZERO, ZERO, ZERO, X */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_L8: /* X, X, X, ONE */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_I8: /* X, X, X, X */ + case MESA_FORMAT_CI8: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_RGB_DXT1: /* not supported yet */ + case MESA_FORMAT_RGBA_DXT1: /* not supported yet */ + case MESA_FORMAT_RGBA_DXT3: /* not supported yet */ + case MESA_FORMAT_RGBA_DXT5: /* not supported yet */ + return GL_FALSE; + + case MESA_FORMAT_RGBA_FLOAT32: + SETfield(t->SQ_TEX_RESOURCE7, FMT_32_32_32_32_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_RGBA_FLOAT16: + SETfield(t->SQ_TEX_RESOURCE7, FMT_16_16_16_16_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_RGB_FLOAT32: /* X, Y, Z, ONE */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_32_32_32_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_RGB_FLOAT16: + SETfield(t->SQ_TEX_RESOURCE7, FMT_16_16_16_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_ALPHA_FLOAT32: /* ZERO, ZERO, ZERO, X */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_32_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_ALPHA_FLOAT16: /* ZERO, ZERO, ZERO, X */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_16_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_LUMINANCE_FLOAT32: /* X, X, X, ONE */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_32_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_LUMINANCE_FLOAT16: /* X, X, X, ONE */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_16_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32: + SETfield(t->SQ_TEX_RESOURCE7, FMT_32_32_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16: + SETfield(t->SQ_TEX_RESOURCE7, FMT_16_16_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_INTENSITY_FLOAT32: /* X, X, X, X */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_32_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_INTENSITY_FLOAT16: /* X, X, X, X */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_16_FLOAT, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case MESA_FORMAT_Z16: + case MESA_FORMAT_X8_Z24: + case MESA_FORMAT_S8_Z24: + case MESA_FORMAT_Z24_S8: + case MESA_FORMAT_Z32: + case MESA_FORMAT_S8: + CLEARbit(t->SQ_TEX_RESOURCE0, EG_SQ_TEX_RESOURCE_WORD0_0__NDTO_bit); + SETfield(t->SQ_TEX_RESOURCE1, ARRAY_1D_TILED_THIN1, + EG_SQ_TEX_RESOURCE_WORD1_0__ARRAY_MODE_shift, + EG_SQ_TEX_RESOURCE_WORD1_0__ARRAY_MODE_mask); + switch (mesa_format) { + case MESA_FORMAT_Z16: + SETfield(t->SQ_TEX_RESOURCE7, FMT_16, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + break; + case MESA_FORMAT_X8_Z24: + case MESA_FORMAT_S8_Z24: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_24, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + break; + case MESA_FORMAT_Z24_S8: + SETfield(t->SQ_TEX_RESOURCE7, FMT_24_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + break; + case MESA_FORMAT_Z32: + SETfield(t->SQ_TEX_RESOURCE7, FMT_32, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + break; + case MESA_FORMAT_S8: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + break; + default: + break; + }; + switch (tObj->DepthMode) { + case GL_LUMINANCE: /* X, X, X, ONE */ + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case GL_INTENSITY: /* X, X, X, X */ + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + case GL_ALPHA: /* ZERO, ZERO, ZERO, X */ + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_0, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + break; + default: + return GL_FALSE; + } + break; + /* EXT_texture_sRGB */ + case MESA_FORMAT_SRGBA8: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + SETbit(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__FORCE_DEGAMMA_bit); + break; + case MESA_FORMAT_SLA8: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + SETbit(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__FORCE_DEGAMMA_bit); + break; + case MESA_FORMAT_SL8: /* X, X, X, ONE */ + SETfield(t->SQ_TEX_RESOURCE7, FMT_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + SETbit(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__FORCE_DEGAMMA_bit); + break; + default: + /* Not supported format */ + return GL_FALSE; + }; + + return GL_TRUE; +} + +static GLuint evergreen_translate_shadow_func(GLenum func) +{ + switch (func) { + case GL_NEVER: + return SQ_TEX_DEPTH_COMPARE_NEVER; + case GL_LESS: + return SQ_TEX_DEPTH_COMPARE_LESS; + case GL_LEQUAL: + return SQ_TEX_DEPTH_COMPARE_LESSEQUAL; + case GL_GREATER: + return SQ_TEX_DEPTH_COMPARE_GREATER; + case GL_GEQUAL: + return SQ_TEX_DEPTH_COMPARE_GREATEREQUAL; + case GL_NOTEQUAL: + return SQ_TEX_DEPTH_COMPARE_NOTEQUAL; + case GL_EQUAL: + return SQ_TEX_DEPTH_COMPARE_EQUAL; + case GL_ALWAYS: + return SQ_TEX_DEPTH_COMPARE_ALWAYS; + default: + WARN_ONCE("Unknown shadow compare function! %d", func); + return 0; + } +} + +static void evergreenUpdateTexWrap(radeonTexObjPtr t) +{ + struct gl_texture_object *tObj = &t->base; + + SETfield(t->SQ_TEX_SAMPLER0, evergreen_translate_wrap_mode(tObj->WrapS), + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_mask); + + if (tObj->Target != GL_TEXTURE_1D) + { + SETfield(t->SQ_TEX_SAMPLER0, evergreen_translate_wrap_mode(tObj->WrapT), + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_Y_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_Y_mask); + + if (tObj->Target == GL_TEXTURE_3D) + SETfield(t->SQ_TEX_SAMPLER0, evergreen_translate_wrap_mode(tObj->WrapR), + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_Z_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_Z_mask); + } +} + +static void evergreenSetTexDefaultState(radeonTexObjPtr t) +{ + /* Init text object to default states. */ + t->SQ_TEX_RESOURCE0 = 0; + t->SQ_TEX_RESOURCE1 = 0; + t->SQ_TEX_RESOURCE2 = 0; + t->SQ_TEX_RESOURCE3 = 0; + t->SQ_TEX_RESOURCE4 = 0; + t->SQ_TEX_RESOURCE5 = 0; + t->SQ_TEX_RESOURCE6 = 0; + t->SQ_TEX_RESOURCE7 = 0; + + SETfield(t->SQ_TEX_RESOURCE0, SQ_TEX_DIM_2D, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_mask); + + CLEARbit(t->SQ_TEX_RESOURCE0, EG_SQ_TEX_RESOURCE_WORD0_0__NDTO_bit); + + SETfield(t->SQ_TEX_RESOURCE1, ARRAY_LINEAR_GENERAL, + EG_SQ_TEX_RESOURCE_WORD1_0__ARRAY_MODE_shift, + EG_SQ_TEX_RESOURCE_WORD1_0__ARRAY_MODE_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_X_shift, FORMAT_COMP_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_Y_shift, FORMAT_COMP_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_Z_shift, FORMAT_COMP_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_FORMAT_COMP_UNSIGNED, + FORMAT_COMP_W_shift, FORMAT_COMP_W_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_NUM_FORMAT_NORM, + SQ_TEX_RESOURCE_WORD4_0__NUM_FORMAT_ALL_shift, SQ_TEX_RESOURCE_WORD4_0__NUM_FORMAT_ALL_mask); + CLEARbit(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__SRF_MODE_ALL_bit); + CLEARbit(t->SQ_TEX_RESOURCE4, SQ_TEX_RESOURCE_WORD4_0__FORCE_DEGAMMA_bit); + SETfield(t->SQ_TEX_RESOURCE4, SQ_ENDIAN_NONE, + SQ_TEX_RESOURCE_WORD4_0__ENDIAN_SWAP_shift, SQ_TEX_RESOURCE_WORD4_0__ENDIAN_SWAP_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + SETfield(t->SQ_TEX_RESOURCE4, 0, + BASE_LEVEL_shift, + BASE_LEVEL_mask); /* mip-maps */ + + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + SETfield(t->SQ_TEX_RESOURCE7, SQ_TEX_VTX_VALID_TEXTURE, + EG_SQ_TEX_RESOURCE_WORD7_0__TYPE_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__TYPE_mask); + + /* Initialize sampler registers */ + t->SQ_TEX_SAMPLER0 = 0; + SETfield(t->SQ_TEX_SAMPLER0, SQ_TEX_WRAP, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_mask); + SETfield(t->SQ_TEX_SAMPLER0, SQ_TEX_WRAP, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_mask); + SETfield(t->SQ_TEX_SAMPLER0, SQ_TEX_WRAP, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__CLAMP_X_mask); + SETfield(t->SQ_TEX_SAMPLER0, SQ_TEX_XY_FILTER_POINT, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MAG_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MAG_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, SQ_TEX_XY_FILTER_POINT, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, SQ_TEX_Z_FILTER_NONE, + EG_SQ_TEX_SAMPLER_WORD0_0__Z_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__Z_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, SQ_TEX_Z_FILTER_NONE, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, SQ_TEX_BORDER_COLOR_TRANS_BLACK, + EG_SQ_TEX_SAMPLER_WORD0_0__BORDER_COLOR_TYPE_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__BORDER_COLOR_TYPE_mask); + + t->SQ_TEX_SAMPLER1 = 0; + SETfield(t->SQ_TEX_SAMPLER1, 0x7ff, + EG_SQ_TEX_SAMPLER_WORD1_0__MAX_LOD_shift, + EG_SQ_TEX_SAMPLER_WORD1_0__MAX_LOD_mask); + + t->SQ_TEX_SAMPLER2 = 0; + SETbit(t->SQ_TEX_SAMPLER2, EG_SQ_TEX_SAMPLER_WORD2_0__TYPE_bit); +} + +static void evergreenSetTexFilter(radeonTexObjPtr t, GLenum minf, GLenum magf, GLfloat anisotropy) +{ + /* Force revalidation to account for switches from/to mipmapping. */ + t->validated = GL_FALSE; + + /* Note that EXT_texture_filter_anisotropic is extremely vague about + * how anisotropic filtering interacts with the "normal" filter modes. + * When anisotropic filtering is enabled, we override min and mag + * filter settings completely. This includes driconf's settings. + */ + if (anisotropy >= 2.0 && (minf != GL_NEAREST) && (magf != GL_NEAREST)) { + /*t->pp_txfilter |= R300_TX_MAG_FILTER_ANISO + | R300_TX_MIN_FILTER_ANISO + | R300_TX_MIN_FILTER_MIP_LINEAR + | aniso_filter(anisotropy);*/ + radeon_print(RADEON_TEXTURE, RADEON_NORMAL, "Using maximum anisotropy of %f\n", anisotropy); + return; + } + + switch (minf) + { + case GL_NEAREST: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Point, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_None, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_mask); + break; + case GL_LINEAR: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Linear, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_None, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_mask); + break; + case GL_NEAREST_MIPMAP_NEAREST: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Point, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_Point, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_mask); + break; + case GL_NEAREST_MIPMAP_LINEAR: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Point, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_Linear, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_mask); + break; + case GL_LINEAR_MIPMAP_NEAREST: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Linear, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_Point, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_mask); + break; + case GL_LINEAR_MIPMAP_LINEAR: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Linear, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MIN_FILTER_mask); + SETfield(t->SQ_TEX_SAMPLER0, TEX_MipFilter_Linear, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__MIP_FILTER_mask); + break; + } + + /* Note we don't have 3D mipmaps so only use the mag filter setting + * to set the 3D texture filter mode. + */ + switch (magf) + { + case GL_NEAREST: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Point, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MAG_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MAG_FILTER_mask); + break; + case GL_LINEAR: + SETfield(t->SQ_TEX_SAMPLER0, TEX_XYFilter_Linear, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MAG_FILTER_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__XY_MAG_FILTER_mask); + break; + } +} + +static void evergreenSetTexBorderColor(radeonTexObjPtr t, const GLfloat color[4]) +{ + t->TD_PS_SAMPLER0_BORDER_ALPHA = *((uint32_t*)&(color[3])); + t->TD_PS_SAMPLER0_BORDER_RED = *((uint32_t*)&(color[2])); + t->TD_PS_SAMPLER0_BORDER_GREEN = *((uint32_t*)&(color[1])); + t->TD_PS_SAMPLER0_BORDER_BLUE = *((uint32_t*)&(color[0])); + + SETfield(t->SQ_TEX_SAMPLER0, SQ_TEX_BORDER_COLOR_REGISTER, + EG_SQ_TEX_SAMPLER_WORD0_0__BORDER_COLOR_TYPE_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__BORDER_COLOR_TYPE_mask); +} + +static void evergreenSetDepthTexMode(struct gl_texture_object *tObj) +{ + radeonTexObjPtr t; + + if (!tObj) + return; + + t = radeon_tex_obj(tObj); + + if(!evergreenGetTexFormat(tObj, tObj->Image[0][tObj->BaseLevel]->TexFormat)) + t->validated = GL_FALSE; +} + +static INLINE uint32_t +EG_S_FIXED(float value, uint32_t frac_bits) +{ + return value * (1 << frac_bits); +} + +static GLboolean evergreen_setup_hardware_state(GLcontext * ctx, struct gl_texture_object *texObj, int unit) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + radeonTexObj *t = radeon_tex_obj(texObj); + const struct gl_texture_image *firstImage; + GLuint uTexelPitch, row_align; + + if (context->radeon.radeonScreen->driScreen->dri2.enabled && + t->image_override && + t->bo) + return GL_TRUE; + + firstImage = t->base.Image[0][t->minLod]; + + if (!t->image_override) { + if (!evergreenGetTexFormat(texObj, firstImage->TexFormat)) { + radeon_warning("unsupported texture format in %s\n", + __FUNCTION__); + return GL_FALSE; + } + } + + switch (texObj->Target) + { + case GL_TEXTURE_1D: + SETfield(t->SQ_TEX_RESOURCE0, SQ_TEX_DIM_1D, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_mask); + SETfield(t->SQ_TEX_RESOURCE1, 0, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_shift, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_mask); + break; + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE_NV: + SETfield(t->SQ_TEX_RESOURCE0, SQ_TEX_DIM_2D, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_mask); + SETfield(t->SQ_TEX_RESOURCE1, 0, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_shift, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_mask); + break; + case GL_TEXTURE_3D: + SETfield(t->SQ_TEX_RESOURCE0, SQ_TEX_DIM_3D, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_mask); + SETfield(t->SQ_TEX_RESOURCE1, (firstImage->Depth - 1), // ??? + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_shift, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_mask); + break; + case GL_TEXTURE_CUBE_MAP: + SETfield(t->SQ_TEX_RESOURCE0, SQ_TEX_DIM_CUBEMAP, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__DIM_mask); + SETfield(t->SQ_TEX_RESOURCE1, 0, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_shift, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_DEPTH_mask); + break; + default: + radeon_error("unexpected texture target type in %s\n", __FUNCTION__); + return GL_FALSE; + } + + row_align = context->radeon.texture_row_align - 1; + uTexelPitch = (_mesa_format_row_stride(firstImage->TexFormat, firstImage->Width) + row_align) & ~row_align; + uTexelPitch = uTexelPitch / _mesa_get_format_bytes(firstImage->TexFormat); + uTexelPitch = (uTexelPitch + R700_TEXEL_PITCH_ALIGNMENT_MASK) + & ~R700_TEXEL_PITCH_ALIGNMENT_MASK; + + /* min pitch is 8 */ + if (uTexelPitch < 8) + uTexelPitch = 8; + + SETfield(t->SQ_TEX_RESOURCE0, (uTexelPitch/8)-1, + EG_SQ_TEX_RESOURCE_WORD0_0__PITCH_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__PITCH_mask); + SETfield(t->SQ_TEX_RESOURCE0, firstImage->Width - 1, + EG_SQ_TEX_RESOURCE_WORD0_0__TEX_WIDTH_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__TEX_WIDTH_mask); + SETfield(t->SQ_TEX_RESOURCE1, firstImage->Height - 1, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_HEIGHT_shift, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_HEIGHT_mask); + + t->SQ_TEX_RESOURCE2 = get_base_teximage_offset(t) / 256; + + t->SQ_TEX_RESOURCE3 = radeon_miptree_image_offset(t->mt, 0, t->minLod + 1) / 256; + + SETfield(t->SQ_TEX_RESOURCE4, 0, BASE_LEVEL_shift, BASE_LEVEL_mask); + SETfield(t->SQ_TEX_RESOURCE5, t->maxLod - t->minLod, LAST_LEVEL_shift, LAST_LEVEL_mask); + + SETfield(t->SQ_TEX_SAMPLER1, + EG_S_FIXED(CLAMP(t->base.MinLod - t->minLod, 0, 15), 6), + EG_SQ_TEX_SAMPLER_WORD1_0__MIN_LOD_shift, + EG_SQ_TEX_SAMPLER_WORD1_0__MIN_LOD_mask); + SETfield(t->SQ_TEX_SAMPLER1, + EG_S_FIXED(CLAMP(t->base.MaxLod - t->minLod, 0, 15), 6), + EG_SQ_TEX_SAMPLER_WORD1_0__MAX_LOD_shift, + EG_SQ_TEX_SAMPLER_WORD1_0__MAX_LOD_mask); + SETfield(t->SQ_TEX_SAMPLER2, + EG_S_FIXED(CLAMP(ctx->Texture.Unit[unit].LodBias + t->base.LodBias, -16, 16), 6), + EG_SQ_TEX_SAMPLER_WORD2_0__LOD_BIAS_shift, + EG_SQ_TEX_SAMPLER_WORD2_0__LOD_BIAS_mask); + + if(texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) + { + SETfield(t->SQ_TEX_SAMPLER0, evergreen_translate_shadow_func(texObj->CompareFunc), + EG_SQ_TEX_SAMPLER_WORD0_0__DCF_shift, + EG_SQ_TEX_SAMPLER_WORD0_0__DCF_mask); + } + else + { + CLEARfield(t->SQ_TEX_SAMPLER0, EG_SQ_TEX_SAMPLER_WORD0_0__DCF_mask); + } + + return GL_TRUE; +} + +void evergreenSetTexOffset(__DRIcontext * pDRICtx, GLint texname, + unsigned long long offset, GLint depth, GLuint pitch) +{ + context_t *rmesa = pDRICtx->driverPrivate; + struct gl_texture_object *tObj = + _mesa_lookup_texture(rmesa->radeon.glCtx, texname); + radeonTexObjPtr t = radeon_tex_obj(tObj); + const struct gl_texture_image *firstImage; + uint32_t pitch_val, size, row_align; + + if (!tObj) + return; + + t->image_override = GL_TRUE; + + if (!offset) + return; + + firstImage = t->base.Image[0][t->minLod]; + row_align = rmesa->radeon.texture_row_align - 1; + size = ((_mesa_format_row_stride(firstImage->TexFormat, firstImage->Width) + row_align) & ~row_align) * firstImage->Height; + if (t->bo) { + radeon_bo_unref(t->bo); + t->bo = NULL; + } + t->bo = radeon_legacy_bo_alloc_fake(rmesa->radeon.radeonScreen->bom, size, offset); + t->override_offset = offset; + pitch_val = pitch; + switch (depth) { + case 32: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + pitch_val /= 4; + break; + case 24: + default: + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + pitch_val /= 4; + break; + case 16: + SETfield(t->SQ_TEX_RESOURCE7, FMT_5_6_5, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + pitch_val /= 2; + break; + } + + pitch_val = (pitch_val + R700_TEXEL_PITCH_ALIGNMENT_MASK) + & ~R700_TEXEL_PITCH_ALIGNMENT_MASK; + + /* min pitch is 8 */ + if (pitch_val < 8) + pitch_val = 8; + + SETfield(t->SQ_TEX_RESOURCE0, (pitch_val/8)-1, + EG_SQ_TEX_RESOURCE_WORD0_0__PITCH_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__PITCH_mask); +} + +void evergreenSetTexBuffer(__DRIcontext *pDRICtx, GLint target, GLint glx_texture_format, __DRIdrawable *dPriv) +{ + struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + struct radeon_renderbuffer *rb; + radeon_texture_image *rImage; + radeonContextPtr radeon; + context_t *rmesa; + struct radeon_framebuffer *rfb; + radeonTexObjPtr t; + uint32_t pitch_val; + uint32_t internalFormat, type, format; + + type = GL_BGRA; + format = GL_UNSIGNED_BYTE; + internalFormat = (glx_texture_format == __DRI_TEXTURE_FORMAT_RGB ? 3 : 4); + + radeon = pDRICtx->driverPrivate; + rmesa = pDRICtx->driverPrivate; + + rfb = dPriv->driverPrivate; + texUnit = &radeon->glCtx->Texture.Unit[radeon->glCtx->Texture.CurrentUnit]; + texObj = _mesa_select_tex_object(radeon->glCtx, texUnit, target); + texImage = _mesa_get_tex_image(radeon->glCtx, texObj, target, 0); + + rImage = get_radeon_texture_image(texImage); + t = radeon_tex_obj(texObj); + if (t == NULL) { + return; + } + + radeon_update_renderbuffers(pDRICtx, dPriv, GL_TRUE); + rb = rfb->color_rb[0]; + if (rb->bo == NULL) { + /* Failed to BO for the buffer */ + return; + } + + _mesa_lock_texture(radeon->glCtx, texObj); + if (t->bo) { + radeon_bo_unref(t->bo); + t->bo = NULL; + } + if (rImage->bo) { + radeon_bo_unref(rImage->bo); + rImage->bo = NULL; + } + + radeon_miptree_unreference(&t->mt); + radeon_miptree_unreference(&rImage->mt); + + _mesa_init_teximage_fields(radeon->glCtx, target, texImage, + rb->base.Width, rb->base.Height, 1, 0, rb->cpp); + texImage->RowStride = rb->pitch / rb->cpp; + + rImage->bo = rb->bo; + radeon_bo_ref(rImage->bo); + t->bo = rb->bo; + radeon_bo_ref(t->bo); + t->image_override = GL_TRUE; + t->override_offset = 0; + pitch_val = rb->pitch; + switch (rb->cpp) { + case 4: + if (glx_texture_format == __DRI_TEXTURE_FORMAT_RGB) { + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + } else { + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + } + pitch_val /= 4; + break; + case 3: + default: + // FMT_8_8_8 ??? + SETfield(t->SQ_TEX_RESOURCE7, FMT_8_8_8_8, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_W, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + pitch_val /= 4; + break; + case 2: + SETfield(t->SQ_TEX_RESOURCE7, FMT_5_6_5, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_shift, + EG_SQ_TEX_RESOURCE_WORD7_0__DATA_FORMAT_mask); + + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Z, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_X_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_Y, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Y_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_X, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_Z_mask); + SETfield(t->SQ_TEX_RESOURCE4, SQ_SEL_1, + SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_shift, SQ_TEX_RESOURCE_WORD4_0__DST_SEL_W_mask); + pitch_val /= 2; + break; + } + + pitch_val = (pitch_val + R700_TEXEL_PITCH_ALIGNMENT_MASK) + & ~R700_TEXEL_PITCH_ALIGNMENT_MASK; + + /* min pitch is 8 */ + if (pitch_val < 8) + pitch_val = 8; + + SETfield(t->SQ_TEX_RESOURCE0, (pitch_val/8)-1, + EG_SQ_TEX_RESOURCE_WORD0_0__PITCH_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__PITCH_mask); + SETfield(t->SQ_TEX_RESOURCE0, rb->base.Width - 1, + EG_SQ_TEX_RESOURCE_WORD0_0__TEX_WIDTH_shift, + EG_SQ_TEX_RESOURCE_WORD0_0__TEX_WIDTH_mask); + SETfield(t->SQ_TEX_RESOURCE1, rb->base.Height - 1, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_HEIGHT_shift, + EG_SQ_TEX_RESOURCE_WORD1_0__TEX_HEIGHT_mask); + + t->validated = GL_TRUE; + _mesa_unlock_texture(radeon->glCtx, texObj); + return; +} + +void evergreenUpdateTextureState(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT * evergreen = GET_EVERGREEN_CHIP(context); + struct gl_texture_unit *texUnit; + struct radeon_tex_obj *t; + GLuint unit; + + EVERGREEN_STATECHANGE(context, tx); + + for (unit = 0; unit < R700_MAX_TEXTURE_UNITS; unit++) { + texUnit = &ctx->Texture.Unit[unit]; + t = radeon_tex_obj(ctx->Texture.Unit[unit]._Current); + evergreen->textures[unit] = NULL; + if (texUnit->_ReallyEnabled) { + if (!t) + continue; + evergreen->textures[unit] = t; + } + } +} + +static GLboolean evergreen_validate_texture(GLcontext * ctx, struct gl_texture_object *texObj, int unit) +{ + radeonTexObj *t = radeon_tex_obj(texObj); + + if (!radeon_validate_texture_miptree(ctx, texObj)) + return GL_FALSE; + + /* Configure the hardware registers (more precisely, the cached version + * of the hardware registers). */ + if (!evergreen_setup_hardware_state(ctx, texObj, unit)) + return GL_FALSE; + + t->validated = GL_TRUE; + return GL_TRUE; +} + +GLboolean evergreenValidateBuffers(GLcontext * ctx) +{ + context_t *rmesa = EVERGREEN_CONTEXT(ctx); + struct radeon_renderbuffer *rrb; + struct radeon_bo *pbo; + int i; + int ret; + + radeon_cs_space_reset_bos(rmesa->radeon.cmdbuf.cs); + + rrb = radeon_get_colorbuffer(&rmesa->radeon); + /* color buffer */ + if (rrb && rrb->bo) { + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, + rrb->bo, 0, + RADEON_GEM_DOMAIN_VRAM); + } + + /* depth buffer */ + rrb = radeon_get_depthbuffer(&rmesa->radeon); + if (rrb && rrb->bo) { + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, + rrb->bo, 0, + RADEON_GEM_DOMAIN_VRAM); + } + + for (i = 0; i < ctx->Const.MaxTextureImageUnits; ++i) { + radeonTexObj *t; + + if (!ctx->Texture.Unit[i]._ReallyEnabled) + continue; + + if (!evergreen_validate_texture(ctx, ctx->Texture.Unit[i]._Current, i)) { + radeon_warning("failed to validate texture for unit %d.\n", i); + } + t = radeon_tex_obj(ctx->Texture.Unit[i]._Current); + if (t->image_override && t->bo) + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, + t->bo, + RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM, 0); + else if (t->mt->bo) + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, + t->mt->bo, + RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM, 0); + } + + pbo = (struct radeon_bo *)evergreenGetActiveFpShaderBo(ctx); + if (pbo) { + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, pbo, + RADEON_GEM_DOMAIN_GTT, 0); + } + + pbo = (struct radeon_bo *)evergreenGetActiveVpShaderBo(ctx); + if (pbo) { + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, pbo, + RADEON_GEM_DOMAIN_GTT, 0); + } + + pbo = (struct radeon_bo *)evergreenGetActiveFpShaderConstBo(ctx); + if (pbo) { + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, pbo, + RADEON_GEM_DOMAIN_GTT, 0); + } + + pbo = (struct radeon_bo *)evergreenGetActiveVpShaderConstBo(ctx); + if (pbo) { + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, pbo, + RADEON_GEM_DOMAIN_GTT, 0); + } + + ret = radeon_cs_space_check_with_bo(rmesa->radeon.cmdbuf.cs, first_elem(&rmesa->radeon.dma.reserved)->bo, RADEON_GEM_DOMAIN_GTT, 0); + if (ret) + return GL_FALSE; + return GL_TRUE; +} + +static struct gl_texture_object *evergreenNewTextureObject(GLcontext * ctx, + GLuint name, + GLenum target) +{ + context_t* rmesa = EVERGREEN_CONTEXT(ctx); + radeonTexObj * t = CALLOC_STRUCT(radeon_tex_obj); + + + radeon_print(RADEON_STATE | RADEON_TEXTURE, RADEON_NORMAL, + "%s( %p (target = %s) )\n", __FUNCTION__, + t, _mesa_lookup_enum_by_nr(target)); + + _mesa_initialize_texture_object(&t->base, name, target); + t->base.MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy; + + evergreenSetTexDefaultState(t); + evergreenUpdateTexWrap(t); + evergreenSetTexFilter(t, t->base.MinFilter, t->base.MagFilter, t->base.MaxAnisotropy); + evergreenSetTexBorderColor(t, t->base.BorderColor.f); + + return &t->base; +} + +static void evergreenDeleteTexture(GLcontext * ctx, struct gl_texture_object *texObj) +{ + context_t * rmesa = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT * evergreen = GET_EVERGREEN_CHIP(rmesa); + radeonTexObj* t = radeon_tex_obj(texObj); + + radeon_print(RADEON_STATE | RADEON_TEXTURE, RADEON_NORMAL, + "%s( %p (target = %s) )\n", __FUNCTION__, + (void *)texObj, + _mesa_lookup_enum_by_nr(texObj->Target)); + + if (rmesa) { + int i; + radeon_firevertices(&rmesa->radeon); + + for(i = 0; i < R700_MAX_TEXTURE_UNITS; ++i) + if (evergreen->textures[i] == t) + evergreen->textures[i] = 0; + } + + if (t->bo) { + radeon_bo_unref(t->bo); + t->bo = NULL; + } + + radeon_miptree_unreference(&t->mt); + + _mesa_delete_texture_object(ctx, texObj); +} + +static void evergreenTexParameter(GLcontext * ctx, GLenum target, + struct gl_texture_object *texObj, + GLenum pname, const GLfloat * params) +{ + radeonTexObj* t = radeon_tex_obj(texObj); + GLenum baseFormat; + + radeon_print(RADEON_STATE | RADEON_TEXTURE, RADEON_VERBOSE, + "%s( %s )\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(pname)); + + switch (pname) { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + evergreenSetTexFilter(t, texObj->MinFilter, texObj->MagFilter, texObj->MaxAnisotropy); + break; + + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + evergreenUpdateTexWrap(t); + break; + + case GL_TEXTURE_BORDER_COLOR: + evergreenSetTexBorderColor(t, texObj->BorderColor.f); + break; + + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + t->validated = GL_FALSE; + break; + + case GL_DEPTH_TEXTURE_MODE: + if (!texObj->Image[0][texObj->BaseLevel]) + return; + baseFormat = texObj->Image[0][texObj->BaseLevel]->_BaseFormat; + if (baseFormat == GL_DEPTH_COMPONENT || + baseFormat == GL_DEPTH_STENCIL) { + evergreenSetDepthTexMode(texObj); + break; + } else { + /* If the texture isn't a depth texture, changing this + * state won't cause any changes to the hardware. + * Don't force a flush of texture state. + */ + return; + } + + default: + return; + } +} + +void evergreenInitTextureFuncs(radeonContextPtr radeon, struct dd_function_table *functions) +{ + /* Note: we only plug in the functions we implement in the driver + * since _mesa_init_driver_functions() was already called. + */ + functions->NewTextureImage = radeonNewTextureImage; + functions->FreeTexImageData = radeonFreeTexImageData; + functions->MapTexture = radeonMapTexture; + functions->UnmapTexture = radeonUnmapTexture; + + functions->ChooseTextureFormat = radeonChooseTextureFormat_mesa; + functions->TexImage1D = radeonTexImage1D; + functions->TexImage2D = radeonTexImage2D; + functions->TexImage3D = radeonTexImage3D; + functions->TexSubImage1D = radeonTexSubImage1D; + functions->TexSubImage2D = radeonTexSubImage2D; + functions->TexSubImage3D = radeonTexSubImage3D; + functions->GetTexImage = radeonGetTexImage; + functions->GetCompressedTexImage = radeonGetCompressedTexImage; + functions->NewTextureObject = evergreenNewTextureObject; + functions->DeleteTexture = evergreenDeleteTexture; + functions->IsTextureResident = driIsTextureResident; + + functions->TexParameter = evergreenTexParameter; + + functions->CompressedTexImage2D = radeonCompressedTexImage2D; + functions->CompressedTexSubImage2D = radeonCompressedTexSubImage2D; + + if (radeon->radeonScreen->kernel_mm) { + functions->CopyTexImage2D = radeonCopyTexImage2D; + functions->CopyTexSubImage2D = radeonCopyTexSubImage2D; + } + + functions->GenerateMipmap = radeonGenerateMipmap; + + driInitTextureFormats(); +} diff --git a/src/mesa/drivers/dri/r600/evergreen_tex.h b/src/mesa/drivers/dri/r600/evergreen_tex.h new file mode 100644 index 0000000000..b43508a9ea --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_tex.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008-2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + +#ifndef _EVERGREEN_TEX_H_ +#define _EVERGREEN_TEX_H_ + +extern GLboolean evergreenValidateBuffers(GLcontext * ctx); + +extern void evergreenUpdateTextureState(GLcontext * ctx); +extern void evergreenInitTextureFuncs(radeonContextPtr radeon, struct dd_function_table *functions); +extern void evergreenSetTexOffset(__DRIcontext * pDRICtx, GLint texname, + unsigned long long offset, GLint depth, GLuint pitch); +extern void evergreenSetTexBuffer(__DRIcontext *pDRICtx, GLint target, GLint glx_texture_format, __DRIdrawable *dPriv); + +#endif /* _EVERGREEN_TEX_H_ */ diff --git a/src/mesa/drivers/dri/r600/evergreen_vertprog.c b/src/mesa/drivers/dri/r600/evergreen_vertprog.c new file mode 100644 index 0000000000..4f3db00c7d --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_vertprog.c @@ -0,0 +1,736 @@ +/* + * Copyright (C) 2008-2009 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "main/imports.h" +#include "main/mtypes.h" + +#include "tnl/t_context.h" +#include "program/program.h" +#include "program/prog_parameter.h" +#include "program/prog_statevars.h" + +#include "radeon_debug.h" +#include "r600_context.h" +#include "r600_cmdbuf.h" +#include "r600_emit.h" +#include "program/programopt.h" + +#include "evergreen_vertprog.h" + +unsigned int evergreen_Map_Vertex_Output(r700_AssemblerBase *pAsm, + struct gl_vertex_program *mesa_vp, + unsigned int unStart) +{ + unsigned int i; + unsigned int unBit; + unsigned int unTotal = unStart; + + //!!!!!!! THE ORDER MATCH FS INPUT + + unBit = 1 << VERT_RESULT_HPOS; + if(mesa_vp->Base.OutputsWritten & unBit) + { + pAsm->ucVP_OutputMap[VERT_RESULT_HPOS] = unTotal++; + } + + unBit = 1 << VERT_RESULT_COL0; + if(mesa_vp->Base.OutputsWritten & unBit) + { + pAsm->ucVP_OutputMap[VERT_RESULT_COL0] = unTotal++; + } + + unBit = 1 << VERT_RESULT_COL1; + if(mesa_vp->Base.OutputsWritten & unBit) + { + pAsm->ucVP_OutputMap[VERT_RESULT_COL1] = unTotal++; + } + + //TODO : dealing back face. + unBit = 1 << VERT_RESULT_BFC0; + if(mesa_vp->Base.OutputsWritten & unBit) + { + pAsm->ucVP_OutputMap[VERT_RESULT_BFC0] = unTotal++; + } + + unBit = 1 << VERT_RESULT_BFC1; + if(mesa_vp->Base.OutputsWritten & unBit) + { + pAsm->ucVP_OutputMap[VERT_RESULT_BFC1] = unTotal++; + } + + //TODO : dealing fog. + unBit = 1 << VERT_RESULT_FOGC; + if(mesa_vp->Base.OutputsWritten & unBit) + { + pAsm->ucVP_OutputMap[VERT_RESULT_FOGC] = unTotal++; + } + + //TODO : dealing point size. + unBit = 1 << VERT_RESULT_PSIZ; + if(mesa_vp->Base.OutputsWritten & unBit) + { + pAsm->ucVP_OutputMap[VERT_RESULT_PSIZ] = unTotal++; + } + + for(i=0; i<8; i++) + { + unBit = 1 << (VERT_RESULT_TEX0 + i); + if(mesa_vp->Base.OutputsWritten & unBit) + { + pAsm->ucVP_OutputMap[VERT_RESULT_TEX0 + i] = unTotal++; + } + } + + for(i=VERT_RESULT_VAR0; i<VERT_RESULT_MAX; i++) + { + unBit = 1 << i; + if(mesa_vp->Base.OutputsWritten & unBit) + { + pAsm->ucVP_OutputMap[i] = unTotal++; + } + } + + return (unTotal - unStart); +} + +unsigned int evergreen_Map_Vertex_Input(r700_AssemblerBase *pAsm, + struct gl_vertex_program *mesa_vp, + unsigned int unStart) +{ + int i; + unsigned int unBit; + unsigned int unTotal = unStart; + for(i=0; i<VERT_ATTRIB_MAX; i++) + { + unBit = 1 << i; + if(mesa_vp->Base.InputsRead & unBit) + { + pAsm->ucVP_AttributeMap[i] = unTotal++; + } + } + return (unTotal - unStart); +} + +GLboolean evergreen_Process_Vertex_Program_Vfetch_Instructions( + struct evergreen_vertex_program *vp, + struct gl_vertex_program *mesa_vp) +{ + int i; + unsigned int unBit; + VTX_FETCH_METHOD vtxFetchMethod; + vtxFetchMethod.bEnableMini = GL_FALSE; + vtxFetchMethod.mega_fetch_remainder = 0; + + for(i=0; i<VERT_ATTRIB_MAX; i++) + { + unBit = 1 << i; + if(mesa_vp->Base.InputsRead & unBit) + { + assemble_vfetch_instruction(&vp->r700AsmCode, + i, + vp->r700AsmCode.ucVP_AttributeMap[i], + vp->aos_desc[i].size, + vp->aos_desc[i].type, + &vtxFetchMethod); + } + } + + return GL_TRUE; +} + +GLboolean evergreen_Process_Vertex_Program_Vfetch_Instructions2( + GLcontext *ctx, + struct evergreen_vertex_program *vp, + struct gl_vertex_program *mesa_vp) +{ + int i; + context_t *context = R700_CONTEXT(ctx); + + VTX_FETCH_METHOD vtxFetchMethod; + vtxFetchMethod.bEnableMini = GL_FALSE; + vtxFetchMethod.mega_fetch_remainder = 0; + + for(i=0; i<context->nNumActiveAos; i++) + { + EG_assemble_vfetch_instruction(&vp->r700AsmCode, + vp->r700AsmCode.ucVP_AttributeMap[context->stream_desc[i].element], + context->stream_desc[i].type, + context->stream_desc[i].size, + context->stream_desc[i].element, + context->stream_desc[i]._signed, + context->stream_desc[i].normalize, + context->stream_desc[i].format, + &vtxFetchMethod); + } + + return GL_TRUE; +} + +void evergreen_Map_Vertex_Program(GLcontext *ctx, + struct evergreen_vertex_program *vp, + struct gl_vertex_program *mesa_vp) +{ + GLuint ui; + r700_AssemblerBase *pAsm = &(vp->r700AsmCode); + unsigned int num_inputs; + + // R0 will always be used for index into vertex buffer + pAsm->number_used_registers = 1; + pAsm->starting_vfetch_register_number = pAsm->number_used_registers; + + // Map Inputs: Add 1 to mapping since R0 is used for index + num_inputs = evergreen_Map_Vertex_Input(pAsm, mesa_vp, pAsm->number_used_registers); + pAsm->number_used_registers += num_inputs; + + // Create VFETCH instructions for inputs + if (GL_TRUE != evergreen_Process_Vertex_Program_Vfetch_Instructions2(ctx, vp, mesa_vp) ) + { + radeon_error("Calling evergreen_Process_Vertex_Program_Vfetch_Instructions2 return error. \n"); + return; + } + + // Map Outputs + pAsm->number_of_exports = evergreen_Map_Vertex_Output(pAsm, mesa_vp, pAsm->number_used_registers); + + pAsm->starting_export_register_number = pAsm->number_used_registers; + + pAsm->number_used_registers += pAsm->number_of_exports; + + pAsm->pucOutMask = (unsigned char*) MALLOC(pAsm->number_of_exports); + + for(ui=0; ui<pAsm->number_of_exports; ui++) + { + pAsm->pucOutMask[ui] = 0x0; + } + + /* Map temporary registers (GPRs) */ + pAsm->starting_temp_register_number = pAsm->number_used_registers; + + if(mesa_vp->Base.NumNativeTemporaries >= mesa_vp->Base.NumTemporaries) + { /* arb uses NumNativeTemporaries */ + pAsm->number_used_registers += mesa_vp->Base.NumNativeTemporaries; + } + else + { /* fix func t_vp uses NumTemporaries */ + pAsm->number_used_registers += mesa_vp->Base.NumTemporaries; + } + + pAsm->flag_reg_index = pAsm->number_used_registers++; + + pAsm->uFirstHelpReg = pAsm->number_used_registers; +} + +GLboolean evergreen_Find_Instruction_Dependencies_vp(struct evergreen_vertex_program *vp, + struct gl_vertex_program *mesa_vp) +{ + GLuint i, j; + GLint * puiTEMPwrites; + struct prog_instruction *pILInst; + InstDeps *pInstDeps; + + puiTEMPwrites = (GLint*) MALLOC(sizeof(GLuint)*mesa_vp->Base.NumTemporaries); + for(i=0; i<mesa_vp->Base.NumTemporaries; i++) + { + puiTEMPwrites[i] = -1; + } + + pInstDeps = (InstDeps*)MALLOC(sizeof(InstDeps)*mesa_vp->Base.NumInstructions); + + for(i=0; i<mesa_vp->Base.NumInstructions; i++) + { + pInstDeps[i].nDstDep = -1; + pILInst = &(mesa_vp->Base.Instructions[i]); + + //Dst + if(pILInst->DstReg.File == PROGRAM_TEMPORARY) + { + //Set lastwrite for the temp + puiTEMPwrites[pILInst->DstReg.Index] = i; + } + + //Src + for(j=0; j<3; j++) + { + if(pILInst->SrcReg[j].File == PROGRAM_TEMPORARY) + { + //Set dep. + pInstDeps[i].nSrcDeps[j] = puiTEMPwrites[pILInst->SrcReg[j].Index]; + } + else + { + pInstDeps[i].nSrcDeps[j] = -1; + } + } + } + + vp->r700AsmCode.pInstDeps = pInstDeps; + + FREE(puiTEMPwrites); + + return GL_TRUE; +} + +struct evergreen_vertex_program* evergreenTranslateVertexShader(GLcontext *ctx, + struct gl_vertex_program *mesa_vp) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + + struct evergreen_vertex_program *vp; + unsigned int i; + + vp = calloc(1, sizeof(*vp)); + vp->mesa_program = _mesa_clone_vertex_program(ctx, mesa_vp); + + vp->constbo0 = NULL; + + if (mesa_vp->IsPositionInvariant) + { + _mesa_insert_mvp_code(ctx, vp->mesa_program); + } + + for(i=0; i<context->nNumActiveAos; i++) + { + vp->aos_desc[i].size = context->stream_desc[i].size; + vp->aos_desc[i].stride = context->stream_desc[i].stride; + vp->aos_desc[i].type = context->stream_desc[i].type; + vp->aos_desc[i].format = context->stream_desc[i].format; + } + + if (context->radeon.radeonScreen->chip_family < CHIP_FAMILY_RV770) + { + vp->r700AsmCode.bR6xx = 1; + } + + //Init_Program + Init_r700_AssemblerBase(SPT_VP, &(vp->r700AsmCode), &(vp->r700Shader) ); + + vp->r700AsmCode.bUseMemConstant = GL_TRUE; + vp->r700AsmCode.unAsic = 8; + + evergreen_Map_Vertex_Program(ctx, vp, vp->mesa_program ); + + if(GL_FALSE == evergreen_Find_Instruction_Dependencies_vp(vp, vp->mesa_program)) + { + return NULL; + } + + InitShaderProgram(&(vp->r700AsmCode)); + + for(i=0; i < MAX_SAMPLERS; i++) + { + vp->r700AsmCode.SamplerUnits[i] = vp->mesa_program->Base.SamplerUnits[i]; + } + + vp->r700AsmCode.unCurNumILInsts = vp->mesa_program->Base.NumInstructions; + + if(GL_FALSE == AssembleInstr(0, + 0, + vp->mesa_program->Base.NumInstructions, + &(vp->mesa_program->Base.Instructions[0]), + &(vp->r700AsmCode)) ) + { + return NULL; + } + + if(GL_FALSE == Process_Vertex_Exports(&(vp->r700AsmCode), vp->mesa_program->Base.OutputsWritten) ) + { + return NULL; + } + + if( GL_FALSE == RelocProgram(&(vp->r700AsmCode), &(vp->mesa_program->Base)) ) + { + return GL_FALSE; + } + + vp->r700Shader.nRegs = (vp->r700AsmCode.number_used_registers == 0) ? 0 + : (vp->r700AsmCode.number_used_registers - 1); + + vp->r700Shader.nParamExports = vp->r700AsmCode.number_of_exports; + + vp->translated = GL_TRUE; + + return vp; +} + +void evergreenSelectVertexShader(GLcontext *ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + struct evergreen_vertex_program_cont *vpc; + struct evergreen_vertex_program *vp; + unsigned int i; + GLboolean match; + GLbitfield InputsRead; + + vpc = (struct evergreen_vertex_program_cont *)ctx->VertexProgram._Current; + + InputsRead = vpc->mesa_program.Base.InputsRead; + if (vpc->mesa_program.IsPositionInvariant) + { + InputsRead |= VERT_BIT_POS; + } + + for (vp = vpc->progs; vp; vp = vp->next) + { + match = GL_TRUE; + for(i=0; i<context->nNumActiveAos; i++) + { + if (vp->aos_desc[i].size != context->stream_desc[i].size || + vp->aos_desc[i].format != context->stream_desc[i].format) + { + match = GL_FALSE; + break; + } + } + if (match) + { + context->selected_vp = vp; + return; + } + } + + vp = evergreenTranslateVertexShader(ctx, &(vpc->mesa_program)); + if(!vp) + { + radeon_error("Failed to translate vertex shader. \n"); + return; + } + vp->next = vpc->progs; + vpc->progs = vp; + context->selected_vp = vp; + return; +} + +int evergreen_getTypeSize(GLenum type) +{ + switch (type) + { + case GL_DOUBLE: + return sizeof(GLdouble); + case GL_FLOAT: + return sizeof(GLfloat); + case GL_INT: + return sizeof(GLint); + case GL_UNSIGNED_INT: + return sizeof(GLuint); + case GL_SHORT: + return sizeof(GLshort); + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); + case GL_BYTE: + return sizeof(GLbyte); + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); + default: + assert(0); + return 0; + } +} + +static void evergreenTranslateAttrib(GLcontext *ctx, GLuint unLoc, int count, const struct gl_client_array *input) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + + StreamDesc * pStreamDesc = &(context->stream_desc[context->nNumActiveAos]); + + GLuint stride; + + stride = (input->StrideB == 0) ? evergreen_getTypeSize(input->Type) * input->Size + : input->StrideB; + + if (input->Type == GL_DOUBLE || input->Type == GL_UNSIGNED_INT || input->Type == GL_INT || +#if MESA_BIG_ENDIAN + evergreen_getTypeSize(input->Type) != 4 || +#endif + stride < 4) + { + pStreamDesc->type = GL_FLOAT; + + if (input->StrideB == 0) + { + pStreamDesc->stride = 0; + } + else + { + pStreamDesc->stride = sizeof(GLfloat) * input->Size; + } + pStreamDesc->dwords = input->Size; + pStreamDesc->is_named_bo = GL_FALSE; + } + else + { + pStreamDesc->type = input->Type; + pStreamDesc->dwords = (evergreen_getTypeSize(input->Type) * input->Size + 3)/ 4; + if (!input->BufferObj->Name) + { + if (input->StrideB == 0) + { + pStreamDesc->stride = 0; + } + else + { + pStreamDesc->stride = (evergreen_getTypeSize(pStreamDesc->type) * input->Size + 3) & ~3; + } + + pStreamDesc->is_named_bo = GL_FALSE; + } + } + + pStreamDesc->size = input->Size; + pStreamDesc->dst_loc = context->nNumActiveAos; + pStreamDesc->element = unLoc; + pStreamDesc->format = input->Format; + + switch (pStreamDesc->type) + { //GetSurfaceFormat + case GL_FLOAT: + pStreamDesc->_signed = 0; + pStreamDesc->normalize = GL_FALSE; + break; + case GL_SHORT: + pStreamDesc->_signed = 1; + pStreamDesc->normalize = input->Normalized; + break; + case GL_BYTE: + pStreamDesc->_signed = 1; + pStreamDesc->normalize = input->Normalized; + break; + case GL_UNSIGNED_SHORT: + pStreamDesc->_signed = 0; + pStreamDesc->normalize = input->Normalized; + break; + case GL_UNSIGNED_BYTE: + pStreamDesc->_signed = 0; + pStreamDesc->normalize = input->Normalized; + break; + default: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_DOUBLE: + assert(0); + break; + } + context->nNumActiveAos++; +} + +void evergreenSetVertexFormat(GLcontext *ctx, const struct gl_client_array *arrays[], int count) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + struct evergreen_vertex_program *vpc + = (struct evergreen_vertex_program *)ctx->VertexProgram._Current; + + struct gl_vertex_program * mesa_vp = (struct gl_vertex_program *)&(vpc->mesa_program); + unsigned int unLoc = 0; + unsigned int unBit = mesa_vp->Base.InputsRead; + context->nNumActiveAos = 0; + + if (mesa_vp->IsPositionInvariant) + { + unBit |= VERT_BIT_POS; + } + + while(unBit) + { + if(unBit & 1) + { + evergreenTranslateAttrib(ctx, unLoc, count, arrays[unLoc]); + } + + unBit >>= 1; + ++unLoc; + } + context->radeon.tcl.aos_count = context->nNumActiveAos; +} + +void * evergreenGetActiveVpShaderBo(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + struct evergreen_vertex_program *vp = context->selected_vp;; + + if (vp) + return vp->shaderbo; + else + return NULL; +} + +void * evergreenGetActiveVpShaderConstBo(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + struct evergreen_vertex_program *vp = context->selected_vp;; + + if (vp) + return vp->constbo0; + else + return NULL; +} + +GLboolean evergreenSetupVertexProgram(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct evergreen_vertex_program *vp = context->selected_vp; + + if(GL_FALSE == vp->loaded) + { + if(vp->r700Shader.bNeedsAssembly == GL_TRUE) + { + Assemble( &(vp->r700Shader) ); + } + + /* Load vp to gpu */ + r600EmitShader(ctx, + &(vp->shaderbo), + (GLvoid *)(vp->r700Shader.pProgram), + vp->r700Shader.uShaderBinaryDWORDSize, + "VS"); + + vp->loaded = GL_TRUE; + } + + EVERGREEN_STATECHANGE(context, vs); + + /* TODO : enable this after MemUse fixed *= + (context->chipobj.MemUse)(context, vp->shadercode.buf->id); + */ + + evergreen->SQ_PGM_RESOURCES_VS.u32All = 0; + SETbit(evergreen->SQ_PGM_RESOURCES_VS.u32All, PGM_RESOURCES__PRIME_CACHE_ON_DRAW_bit); + + evergreen->vs.SQ_ALU_CONST_CACHE_VS_0.u32All = 0; /* set from buffer object. */ + + evergreen->vs.SQ_PGM_START_VS.u32All = 0; + + SETfield(evergreen->SQ_PGM_RESOURCES_VS.u32All, vp->r700Shader.nRegs + 1, + NUM_GPRS_shift, NUM_GPRS_mask); + + if(vp->r700Shader.uStackSize) /* we don't use branch for now, it should be zero. */ + { + SETfield(evergreen->SQ_PGM_RESOURCES_VS.u32All, vp->r700Shader.uStackSize, + STACK_SIZE_shift, STACK_SIZE_mask); + } + + EVERGREEN_STATECHANGE(context, spi); + + SETfield(evergreen->SPI_VS_OUT_CONFIG.u32All, + vp->r700Shader.nParamExports ? (vp->r700Shader.nParamExports - 1) : 0, + VS_EXPORT_COUNT_shift, VS_EXPORT_COUNT_mask); + SETfield(evergreen->SPI_PS_IN_CONTROL_0.u32All, vp->r700Shader.nParamExports, + NUM_INTERP_shift, NUM_INTERP_mask); + + /* + SETbit(evergreen->SPI_PS_IN_CONTROL_0.u32All, PERSP_GRADIENT_ENA_bit); + CLEARbit(evergreen->SPI_PS_IN_CONTROL_0.u32All, LINEAR_GRADIENT_ENA_bit); + */ + + return GL_TRUE; +} + +GLboolean evergreenSetupVPconstants(GLcontext * ctx) +{ + context_t *context = EVERGREEN_CONTEXT(ctx); + EVERGREEN_CHIP_CONTEXT *evergreen = GET_EVERGREEN_CHIP(context); + struct evergreen_vertex_program *vp = context->selected_vp; + + struct gl_program_parameter_list *paramList; + unsigned int unNumParamData; + unsigned int ui; + + /* sent out shader constants. */ + paramList = vp->mesa_program->Base.Parameters; + + if(NULL != paramList) { + /* vp->mesa_program was cloned, not updated by glsl shader api. */ + /* _mesa_reference_program has already checked glsl shProg is ok and set ctx->VertexProgem._Current */ + /* so, use ctx->VertexProgem._Current */ + struct gl_program_parameter_list *paramListOrginal = + ctx->VertexProgram._Current->Base.Parameters; + + _mesa_load_state_parameters(ctx, paramList); + + if (paramList->NumParameters > EVERGREEN_MAX_DX9_CONSTS) + return GL_FALSE; + + EVERGREEN_STATECHANGE(context, vs); + + evergreen->vs.num_consts = paramList->NumParameters; + + unNumParamData = paramList->NumParameters; + + for(ui=0; ui<unNumParamData; ui++) { + if(paramList->Parameters[ui].Type == PROGRAM_UNIFORM) + { + evergreen->vs.consts[ui][0].f32All = paramListOrginal->ParameterValues[ui][0]; + evergreen->vs.consts[ui][1].f32All = paramListOrginal->ParameterValues[ui][1]; + evergreen->vs.consts[ui][2].f32All = paramListOrginal->ParameterValues[ui][2]; + evergreen->vs.consts[ui][3].f32All = paramListOrginal->ParameterValues[ui][3]; + } + else + { + evergreen->vs.consts[ui][0].f32All = paramList->ParameterValues[ui][0]; + evergreen->vs.consts[ui][1].f32All = paramList->ParameterValues[ui][1]; + evergreen->vs.consts[ui][2].f32All = paramList->ParameterValues[ui][2]; + evergreen->vs.consts[ui][3].f32All = paramList->ParameterValues[ui][3]; + } + } + + radeonAllocDmaRegion(&context->radeon, + &context->vp_Constbo, + &context->vp_bo_offset, + 256, + 256); + r600EmitShaderConsts(ctx, + context->vp_Constbo, + context->vp_bo_offset, + (GLvoid *)&(evergreen->vs.consts[0][0]), + unNumParamData * 4 * 4); + } else + evergreen->vs.num_consts = 0; + + COMPILED_SUB * pCompiledSub; + GLuint uj; + GLuint unConstOffset = evergreen->vs.num_consts; + for(ui=0; ui<vp->r700AsmCode.unNumPresub; ui++) + { + pCompiledSub = vp->r700AsmCode.presubs[ui].pCompiledSub; + + evergreen->vs.num_consts += pCompiledSub->NumParameters; + + for(uj=0; uj<pCompiledSub->NumParameters; uj++) + { + evergreen->vs.consts[uj + unConstOffset][0].f32All = pCompiledSub->ParameterValues[uj][0]; + evergreen->vs.consts[uj + unConstOffset][1].f32All = pCompiledSub->ParameterValues[uj][1]; + evergreen->vs.consts[uj + unConstOffset][2].f32All = pCompiledSub->ParameterValues[uj][2]; + evergreen->vs.consts[uj + unConstOffset][3].f32All = pCompiledSub->ParameterValues[uj][3]; + } + unConstOffset += pCompiledSub->NumParameters; + } +}
\ No newline at end of file diff --git a/src/mesa/drivers/dri/r600/evergreen_vertprog.h b/src/mesa/drivers/dri/r600/evergreen_vertprog.h new file mode 100644 index 0000000000..5853902115 --- /dev/null +++ b/src/mesa/drivers/dri/r600/evergreen_vertprog.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008-2009 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Richard Li <RichardZ.Li@amd.com>, <richardradeon@gmail.com> + */ + + +#ifndef _EVERGREEN_VERTPROG_H_ +#define _EVERGREEN_VERTPROG_H_ + +#include "main/glheader.h" +#include "main/mtypes.h" + +#include "r700_shader.h" +#include "r700_assembler.h" + +typedef struct evergreenArrayDesc //TEMP +{ + GLint size; //number of data element + GLenum type; //data element type + GLsizei stride; + GLenum format; //GL_RGBA or GL_BGRA +} evergreenArrayDesc; + +struct evergreen_vertex_program +{ + struct gl_vertex_program *mesa_program; /* Must be first */ + + struct evergreen_vertex_program *next; + + r700_AssemblerBase r700AsmCode; + R700_Shader r700Shader; + + GLboolean translated; + GLboolean loaded; + + void * shaderbo; + + GLuint K0used; + void * constbo0; + + evergreenArrayDesc aos_desc[VERT_ATTRIB_MAX]; +}; + +struct evergreen_vertex_program_cont +{ + struct gl_vertex_program mesa_program; + + struct evergreen_vertex_program *progs; +}; + +//Internal +unsigned int evergreen_Map_Vertex_Output(r700_AssemblerBase *pAsm, + struct gl_vertex_program *mesa_vp, + unsigned int unStart); +unsigned int evergreen_Map_Vertex_Input(r700_AssemblerBase *pAsm, + struct gl_vertex_program *mesa_vp, + unsigned int unStart); +GLboolean evergreen_Process_Vertex_Program_Vfetch_Instructions( + struct evergreen_vertex_program *vp, + struct gl_vertex_program *mesa_vp); +GLboolean evergreen_Process_Vertex_Program_Vfetch_Instructions2( + GLcontext *ctx, + struct evergreen_vertex_program *vp, + struct gl_vertex_program *mesa_vp); +void evergreen_Map_Vertex_Program(GLcontext *ctx, + struct evergreen_vertex_program *vp, + struct gl_vertex_program *mesa_vp); +GLboolean evergreen_Find_Instruction_Dependencies_vp(struct evergreen_vertex_program *vp, + struct gl_vertex_program *mesa_vp); + +struct evergreen_vertex_program* evergreenTranslateVertexShader(GLcontext *ctx, + struct gl_vertex_program *mesa_vp); + +/* Interface */ +extern void evergreenSelectVertexShader(GLcontext *ctx); +extern void evergreenSetVertexFormat(GLcontext *ctx, const struct gl_client_array *arrays[], int count); + +extern GLboolean evergreenSetupVertexProgram(GLcontext * ctx); + +extern GLboolean evergreenSetupVPconstants(GLcontext * ctx); + +extern void * evergreenGetActiveVpShaderBo(GLcontext * ctx); + +extern void * evergreenGetActiveVpShaderConstBo(GLcontext * ctx); + +extern int evergreen_getTypeSize(GLenum type); + +#endif /* _EVERGREEN_VERTPROG_H_ */ diff --git a/src/mesa/drivers/dri/r600/r600_blit.c b/src/mesa/drivers/dri/r600/r600_blit.c index 27acff9c16..ef47ae1c05 100644 --- a/src/mesa/drivers/dri/r600/r600_blit.c +++ b/src/mesa/drivers/dri/r600/r600_blit.c @@ -1454,7 +1454,7 @@ set_default_state(context_t *context) SETbit(sq_dyn_gpr_cntl_ps_flush_req, VS_PC_LIMIT_ENABLE_bit); } - BEGIN_BATCH_NO_AUTOSTATE(117); + BEGIN_BATCH_NO_AUTOSTATE(120); R600_OUT_BATCH_REGSEQ(SQ_CONFIG, 6); R600_OUT_BATCH(sq_config); R600_OUT_BATCH(sq_gpr_resource_mgmt_1); @@ -1499,9 +1499,10 @@ set_default_state(context_t *context) R600_OUT_BATCH_REGVAL(PA_SU_VTX_CNTL, (PIX_CENTER_bit) | (X_ROUND_TO_EVEN << PA_SU_VTX_CNTL__ROUND_MODE_shift) | (X_1_256TH << QUANT_MODE_shift)); + R600_OUT_BATCH_REGVAL(PA_SC_AA_CONFIG, 0); R600_OUT_BATCH_REGSEQ(VGT_MAX_VTX_INDX, 4); - R600_OUT_BATCH(2048); + R600_OUT_BATCH(0xffffff); R600_OUT_BATCH(0); R600_OUT_BATCH(0); R600_OUT_BATCH(0); @@ -1614,7 +1615,7 @@ unsigned r600_blit(GLcontext *ctx, /* Flush is needed to make sure that source buffer has correct data */ radeonFlush(ctx); - rcommonEnsureCmdBufSpace(&context->radeon, 308, __FUNCTION__); + rcommonEnsureCmdBufSpace(&context->radeon, 311, __FUNCTION__); /* load shaders */ load_shaders(context->radeon.glCtx); @@ -1623,7 +1624,7 @@ unsigned r600_blit(GLcontext *ctx, return GL_FALSE; /* set clear state */ - /* 117 */ + /* 120 */ set_default_state(context); /* shaders */ diff --git a/src/mesa/drivers/dri/r600/r600_cmdbuf.c b/src/mesa/drivers/dri/r600/r600_cmdbuf.c index 8013553f67..b3331fc8b8 100644 --- a/src/mesa/drivers/dri/r600/r600_cmdbuf.c +++ b/src/mesa/drivers/dri/r600/r600_cmdbuf.c @@ -473,7 +473,14 @@ void r600InitCmdBuf(context_t *r600) /* from rcommonInitCmdBuf */ radeonContextPtr rmesa = &r600->radeon; GLuint size; - r600InitAtoms(r600); + if(r600->radeon.radeonScreen->chip_family >= CHIP_FAMILY_CEDAR) + { + evergreenInitAtoms(r600); + } + else + { + r600InitAtoms(r600); + } /* Initialize command buffer */ size = 256 * driQueryOptioni(&rmesa->optionCache, diff --git a/src/mesa/drivers/dri/r600/r600_cmdbuf.h b/src/mesa/drivers/dri/r600/r600_cmdbuf.h index 78fccd0b60..801bb013f6 100644 --- a/src/mesa/drivers/dri/r600/r600_cmdbuf.h +++ b/src/mesa/drivers/dri/r600/r600_cmdbuf.h @@ -190,6 +190,46 @@ do { \ #define R600_OUT_BATCH_REGSEQ(reg, count) \ R600_OUT_BATCH_REGS((reg), (count)) +/* evergreen */ +#define EVERGREEN_OUT_BATCH_REGS(reg, num) \ +do { \ + if ((reg) >= R600_SET_CONFIG_REG_OFFSET && (reg) < R600_SET_CONFIG_REG_END) { \ + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_CONFIG_REG, (num))); \ + R600_OUT_BATCH(((reg) - R600_SET_CONFIG_REG_OFFSET) >> 2); \ + } else if ((reg) >= R600_SET_CONTEXT_REG_OFFSET && (reg) < R600_SET_CONTEXT_REG_END) { \ + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_CONTEXT_REG, (num))); \ + R600_OUT_BATCH(((reg) - R600_SET_CONTEXT_REG_OFFSET) >> 2); \ + } else if ((reg) >= EG_SET_RESOURCE_OFFSET && (reg) < EG_SET_RESOURCE_END) { \ + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_RESOURCE, (num))); \ + R600_OUT_BATCH(((reg) - EG_SET_RESOURCE_OFFSET) >> 2); \ + } else if ((reg) >= EG_SET_LOOP_CONST_OFFSET && (reg) < EG_SET_LOOP_CONST_END) { \ + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_LOOP_CONST, (num))); \ + R600_OUT_BATCH(((reg) - EG_SET_LOOP_CONST_OFFSET) >> 2); \ + } else if ((reg) >= R600_SET_SAMPLER_OFFSET && (reg) < R600_SET_SAMPLER_END) { \ + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_SAMPLER, (num))); \ + R600_OUT_BATCH(((reg) - R600_SET_SAMPLER_OFFSET) >> 2); \ + } else if ((reg) >= R600_SET_CTL_CONST_OFFSET && (reg) < R600_SET_CTL_CONST_END) { \ + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_CTL_CONST, (num))); \ + R600_OUT_BATCH(((reg) - R600_SET_CTL_CONST_OFFSET) >> 2); \ + } else if ((reg) >= EG_SET_BOOL_CONST_OFFSET && (reg) < EG_SET_BOOL_CONST_END) { \ + R600_OUT_BATCH(CP_PACKET3(R600_IT_SET_BOOL_CONST, (num))); \ + R600_OUT_BATCH(((reg) - EG_SET_BOOL_CONST_OFFSET) >> 2); \ + } else { \ + R600_OUT_BATCH(CP_PACKET0((reg), (num))); \ + } \ +} while (0) + +/** Single register write to command buffer; requires 3 dwords for most things. */ +#define EVERGREEN_OUT_BATCH_REGVAL(reg, val) \ + EVERGREEN_OUT_BATCH_REGS((reg), 1); \ + R600_OUT_BATCH((val)) + +/** Continuous register range write to command buffer; requires 1 dword, + * expects count dwords afterwards for register contents. */ +#define EVERGREEN_OUT_BATCH_REGSEQ(reg, count) \ + EVERGREEN_OUT_BATCH_REGS((reg), (count)) + + extern void r600InitCmdBuf(context_t *r600); #endif /* __R600_CMDBUF_H__ */ diff --git a/src/mesa/drivers/dri/r600/r600_context.c b/src/mesa/drivers/dri/r600/r600_context.c index 389b0412ba..bb959e7d2d 100644 --- a/src/mesa/drivers/dri/r600/r600_context.c +++ b/src/mesa/drivers/dri/r600/r600_context.c @@ -66,6 +66,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "r700_state.h" #include "r700_ioctl.h" +#include "evergreen_context.h" +#include "evergreen_state.h" +#include "evergreen_tex.h" +#include "evergreen_ioctl.h" +#include "evergreen_oglprog.h" #include "utils.h" @@ -247,6 +252,19 @@ static void r600_init_vtbl(radeonContextPtr radeon) static void r600InitConstValues(GLcontext *ctx, radeonScreenPtr screen) { + context_t *context = R700_CONTEXT(ctx); + R700_CHIP_CONTEXT *r700 = (R700_CHIP_CONTEXT*)(&context->hw); + + if( (context->radeon.radeonScreen->chip_family >= CHIP_FAMILY_CEDAR) + &&(context->radeon.radeonScreen->chip_family <= CHIP_FAMILY_HEMLOCK) ) + { + r700->bShaderUseMemConstant = GL_TRUE; + } + else + { + r700->bShaderUseMemConstant = GL_FALSE; + } + ctx->Const.MaxTextureImageUnits = 16; /* 8 per clause on r6xx, 16 on r7xx * but I think mesa only supports 8 at the moment @@ -381,18 +399,45 @@ GLboolean r600CreateContext(gl_api api, r600ParseOptions(r600, screen); r600->radeon.radeonScreen = screen; - r600_init_vtbl(&r600->radeon); + if(screen->chip_family >= CHIP_FAMILY_CEDAR) + { + evergreen_init_vtbl(&r600->radeon); + } + else + { + r600_init_vtbl(&r600->radeon); + } + /* Init default driver functions then plug in our R600-specific functions * (the texture functions are especially important) */ _mesa_init_driver_functions(&functions); - r700InitStateFuncs(&r600->radeon, &functions); - r600InitTextureFuncs(&r600->radeon, &functions); - r700InitShaderFuncs(&functions); + if(screen->chip_family >= CHIP_FAMILY_CEDAR) + { + evergreenCreateChip(r600); + evergreenInitStateFuncs(&r600->radeon, &functions); + evergreenInitTextureFuncs(&r600->radeon, &functions); + evergreenInitShaderFuncs(&functions); + } + else + { + r700InitStateFuncs(&r600->radeon, &functions); + r600InitTextureFuncs(&r600->radeon, &functions); + r700InitShaderFuncs(&functions); + } + radeonInitQueryObjFunctions(&functions); - r700InitIoctlFuncs(&functions); + + if(screen->chip_family >= CHIP_FAMILY_CEDAR) + { + evergreenInitIoctlFuncs(&functions); + } + else + { + r700InitIoctlFuncs(&functions); + } radeonInitBufferObjectFuncs(&functions); if (!radeonInitContext(&r600->radeon, &functions, @@ -435,16 +480,46 @@ GLboolean r600CreateContext(gl_api api, radeon_init_debug(); - r700InitDraw(ctx); + if(screen->chip_family >= CHIP_FAMILY_CEDAR) + { + evergreenInitDraw(ctx); + } + else + { + r700InitDraw(ctx); + } radeon_fbo_init(&r600->radeon); radeonInitSpanFuncs( ctx ); r600InitCmdBuf(r600); - r700InitState(r600->radeon.glCtx); + + if(screen->chip_family >= CHIP_FAMILY_CEDAR) + { + evergreenInitState(r600->radeon.glCtx); + } + else + { + r700InitState(r600->radeon.glCtx); + } r600InitGLExtensions(ctx); return GL_TRUE; } +void r600DestroyContext(__DRIcontext *driContextPriv ) +{ + void *pChip; + context_t *context = (context_t *) driContextPriv->driverPrivate; + + assert(context); + + pChip = context->pChip; + + /* destroy context first, free pChip, in case there are things flush to asic. */ + radeonDestroyContext(driContextPriv); + + FREE(pChip); +} + diff --git a/src/mesa/drivers/dri/r600/r600_context.h b/src/mesa/drivers/dri/r600/r600_context.h index 063dd7c49a..6a83196648 100644 --- a/src/mesa/drivers/dri/r600/r600_context.h +++ b/src/mesa/drivers/dri/r600/r600_context.h @@ -53,6 +53,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "r700_oglprog.h" #include "r700_vertprog.h" +#include "evergreen_chip.h" + struct r600_context; typedef struct r600_context context_t; @@ -63,6 +65,10 @@ typedef struct r600_context context_t; #include "tnl_dd/t_dd_vertex.h" #undef TAG +#define FORCE_CF_TEX_BARRIER 1 + +/* #define GENERATE_SHADER_FOR_2D 1 */ + #define R600_FALLBACK_NONE 0 #define R600_FALLBACK_TCL 1 #define R600_FALLBACK_RAST 2 @@ -103,6 +109,24 @@ struct r600_hw_state { struct radeon_state_atom tx_brdr_clr; }; +struct evergreen_hw_state { + struct radeon_state_atom one_time_init; + struct radeon_state_atom init; + struct radeon_state_atom pa; + struct radeon_state_atom vgt; + struct radeon_state_atom tp; + struct radeon_state_atom sq; + struct radeon_state_atom vs; + struct radeon_state_atom spi; + struct radeon_state_atom sx; + struct radeon_state_atom tx; + struct radeon_state_atom db; + struct radeon_state_atom cb; + struct radeon_state_atom vtx; + struct radeon_state_atom cp; + struct radeon_state_atom timestamp; +}; + typedef struct StreamDesc { GLint size; //number of data element @@ -141,6 +165,9 @@ struct r600_context { struct r600_hw_state atoms; + struct evergreen_hw_state evergreen_atoms; + void * pChip; + struct r700_vertex_program *selected_vp; /* Vertex buffers @@ -150,16 +177,29 @@ struct r600_context { struct r700_index_buffer ind_buf; struct radeon_bo *blit_bo; GLboolean blit_bo_loaded; + + /* Shader const buffer */ + struct radeon_bo * vp_Constbo; + int vp_bo_offset; + struct radeon_bo * fp_Constbo; + int fp_bo_offset; }; +#define EVERGREEN_CONTEXT(ctx) ((context_t *)(ctx->DriverCtx)) + #define R700_CONTEXT(ctx) ((context_t *)(ctx->DriverCtx)) #define GL_CONTEXT(context) ((GLcontext *)(context->radeon.glCtx)) +#define GET_EVERGREEN_CHIP(context) ((EVERGREEN_CHIP_CONTEXT*)(context->pChip)) + extern GLboolean r600CreateContext(gl_api api, const __GLcontextModes * glVisual, __DRIcontext * driContextPriv, void *sharedContextPrivate); +extern void r600DestroyContext(__DRIcontext *driContextPriv ); +extern void evergreenCreateChip(context_t *context); + #define R700_CONTEXT_STATES(context) ((R700_CHIP_CONTEXT *)(&context->hw)) #define R600_NEWPRIM( rmesa ) \ @@ -175,6 +215,13 @@ do { \ r600->radeon.hw.is_dirty = GL_TRUE; \ } while(0) +#define EVERGREEN_STATECHANGE(r600, ATOM) \ +do { \ + R600_NEWPRIM(r600); \ + r600->evergreen_atoms.ATOM.dirty = GL_TRUE; \ + r600->radeon.hw.is_dirty = GL_TRUE; \ +} while(0) + extern GLboolean r700SyncSurf(context_t *context, struct radeon_bo *pbo, uint32_t read_domain, @@ -187,6 +234,9 @@ extern void r700Start3D(context_t *context); extern void r600InitAtoms(context_t *context); extern void r700InitDraw(GLcontext *ctx); +extern void evergreenInitAtoms(context_t *context); +extern void evergreenInitDraw(GLcontext *ctx); + #define RADEON_D_CAPTURE 0 #define RADEON_D_PLAYBACK 1 #define RADEON_D_PLAYBACK_RAW 2 diff --git a/src/mesa/drivers/dri/r600/r600_emit.c b/src/mesa/drivers/dri/r600/r600_emit.c index 1eb89a5305..a840106c14 100644 --- a/src/mesa/drivers/dri/r600/r600_emit.c +++ b/src/mesa/drivers/dri/r600/r600_emit.c @@ -49,6 +49,71 @@ void r600EmitCacheFlush(context_t *rmesa) { } +GLboolean r600AllocShaderConsts(GLcontext * ctx, + void ** constbo, + int sizeinBYTE, + char * szShaderUsage) +{ + radeonContextPtr radeonctx = RADEON_CONTEXT(ctx); + struct radeon_bo * pbo; + + if(sizeinBYTE < 64) /* SQ_ALU_CONST_BUFFER_SIZE need 64 bytes at least to be non 0 */ + { + sizeinBYTE = 64; + } + +shader_again_alloc: + pbo = radeon_bo_open(radeonctx->radeonScreen->bom, + 0, + sizeinBYTE, + 256, + RADEON_GEM_DOMAIN_GTT, + 0); + + radeon_print(RADEON_SHADER, RADEON_NORMAL, "%s %p size %d: %s\n", __func__, pbo, sizeinBYTE, szShaderUsage); + + if (!pbo) { + radeon_print(RADEON_MEMORY | RADEON_CS, RADEON_IMPORTANT, "No memory for buffer object. Flushing command buffer.\n"); + rcommonFlushCmdBuf(radeonctx, __FUNCTION__); + goto shader_again_alloc; + } + + radeon_cs_space_add_persistent_bo(radeonctx->cmdbuf.cs, + pbo, + RADEON_GEM_DOMAIN_GTT, 0); + + if (radeon_cs_space_check_with_bo(radeonctx->cmdbuf.cs, + pbo, + RADEON_GEM_DOMAIN_GTT, 0)) { + radeon_error("failure to revalidate BOs - badness\n"); + return GL_FALSE; + } + + *constbo = (void*)pbo; + + return GL_TRUE; +} +GLboolean r600EmitShaderConsts(GLcontext * ctx, + void * constbo, + int bo_offset, + GLvoid * data, + int sizeinBYTE) +{ + struct radeon_bo * pbo = (struct radeon_bo *)constbo; + uint8_t *out; + + radeon_bo_map(pbo, 1); + + out = (uint8_t*)(pbo->ptr); + out = (uint8_t*)ADD_POINTERS(pbo->ptr, bo_offset); + + memcpy(out, data, sizeinBYTE); + + radeon_bo_unmap(pbo); + + return GL_TRUE; +} + GLboolean r600EmitShader(GLcontext * ctx, void ** shaderbo, GLvoid * data, diff --git a/src/mesa/drivers/dri/r600/r600_emit.h b/src/mesa/drivers/dri/r600/r600_emit.h index 661774d11e..259561539f 100644 --- a/src/mesa/drivers/dri/r600/r600_emit.h +++ b/src/mesa/drivers/dri/r600/r600_emit.h @@ -52,4 +52,14 @@ extern GLboolean r600EmitShader(GLcontext * ctx, extern GLboolean r600DeleteShader(GLcontext * ctx, void * shaderbo); +extern GLboolean r600AllocShaderConsts(GLcontext * ctx, + void ** constbo, + int sizeinBYTE, + char * szShaderUsage); +GLboolean r600EmitShaderConsts(GLcontext * ctx, + void * constbo, + int bo_offset, + GLvoid * data, + int sizeinBYTE); + #endif diff --git a/src/mesa/drivers/dri/r600/r600_texstate.c b/src/mesa/drivers/dri/r600/r600_texstate.c index ba3690b70e..fd928cfe5d 100644 --- a/src/mesa/drivers/dri/r600/r600_texstate.c +++ b/src/mesa/drivers/dri/r600/r600_texstate.c @@ -50,6 +50,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "r700_fragprog.h" #include "r700_vertprog.h" +#include "evergreen_tex.h" + void r600UpdateTextureState(GLcontext * ctx); void r600UpdateTextureState(GLcontext * ctx) @@ -878,6 +880,18 @@ GLboolean r600ValidateBuffers(GLcontext * ctx) RADEON_GEM_DOMAIN_GTT, 0); } + pbo = (struct radeon_bo *)r700GetActiveFpShaderConstBo(ctx); + if (pbo) { + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, pbo, + RADEON_GEM_DOMAIN_GTT, 0); + } + + pbo = (struct radeon_bo *)r700GetActiveVpShaderConstBo(ctx); + if (pbo) { + radeon_cs_space_add_persistent_bo(rmesa->radeon.cmdbuf.cs, pbo, + RADEON_GEM_DOMAIN_GTT, 0); + } + ret = radeon_cs_space_check_with_bo(rmesa->radeon.cmdbuf.cs, first_elem(&rmesa->radeon.dma.reserved)->bo, RADEON_GEM_DOMAIN_GTT, 0); if (ret) return GL_FALSE; @@ -897,6 +911,12 @@ void r600SetTexOffset(__DRIcontext * pDRICtx, GLint texname, if (!tObj) return; + if(rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_CEDAR) + { + evergreenSetTexOffset(pDRICtx, texname, offset, depth, pitch); + return; + } + t->image_override = GL_TRUE; if (!offset) @@ -989,6 +1009,12 @@ void r600SetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint glx_texture_fo radeon = pDRICtx->driverPrivate; rmesa = pDRICtx->driverPrivate; + if(rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_CEDAR) + { + evergreenSetTexBuffer(pDRICtx, target, glx_texture_format, dPriv); + return; + } + rfb = dPriv->driverPrivate; texUnit = &radeon->glCtx->Texture.Unit[radeon->glCtx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(radeon->glCtx, texUnit, target); diff --git a/src/mesa/drivers/dri/r600/r700_assembler.c b/src/mesa/drivers/dri/r600/r700_assembler.c index 9c954cbf70..45ff9c0624 100644 --- a/src/mesa/drivers/dri/r600/r700_assembler.c +++ b/src/mesa/drivers/dri/r600/r700_assembler.c @@ -38,6 +38,7 @@ #include "r600_context.h" #include "r700_assembler.h" +#include "evergreen_sq.h" #define USE_CF_FOR_CONTINUE_BREAK 1 #define USE_CF_FOR_POP_AFTER 1 @@ -258,6 +259,18 @@ GLboolean is_reduction_opcode(PVSDWORD* dest) return GL_FALSE; } +GLboolean EG_is_reduction_opcode(PVSDWORD* dest) +{ + if (dest->dst.op3 == 0) + { + if ( (dest->dst.opcode == EG_OP2_INST_DOT4 || dest->dst.opcode == EG_OP2_INST_DOT4_IEEE || dest->dst.opcode == EG_OP2_INST_CUBE) ) + { + return GL_TRUE; + } + } + return GL_FALSE; +} + GLuint GetSurfaceFormat(GLenum eType, GLuint nChannels, GLuint * pClient_size) { GLuint format = FMT_INVALID; @@ -423,6 +436,60 @@ unsigned int r700GetNumOperands(GLuint opcode, GLuint nIsOp3) return 3; } +unsigned int EG_GetNumOperands(GLuint opcode, GLuint nIsOp3) +{ + if(nIsOp3 > 0) + { + return 3; + } + + switch (opcode) + { + case EG_OP2_INST_ADD: + case EG_OP2_INST_KILLE: + case EG_OP2_INST_KILLGT: + case EG_OP2_INST_KILLGE: + case EG_OP2_INST_KILLNE: + case EG_OP2_INST_MUL: + case EG_OP2_INST_MAX: + case EG_OP2_INST_MIN: + //case EG_OP2_INST_MAX_DX10: + //case EG_OP2_INST_MIN_DX10: + case EG_OP2_INST_SETE: + case EG_OP2_INST_SETNE: + case EG_OP2_INST_SETGT: + case EG_OP2_INST_SETGE: + case EG_OP2_INST_PRED_SETE: + case EG_OP2_INST_PRED_SETGT: + case EG_OP2_INST_PRED_SETGE: + case EG_OP2_INST_PRED_SETNE: + case EG_OP2_INST_DOT4: + case EG_OP2_INST_DOT4_IEEE: + case EG_OP2_INST_CUBE: + return 2; + + case EG_OP2_INST_MOV: + //case SQ_OP2_INST_MOVA_FLOOR: + case EG_OP2_INST_FRACT: + case EG_OP2_INST_FLOOR: + case EG_OP2_INST_TRUNC: + case EG_OP2_INST_EXP_IEEE: + case EG_OP2_INST_LOG_CLAMPED: + case EG_OP2_INST_LOG_IEEE: + case EG_OP2_INST_RECIP_IEEE: + case EG_OP2_INST_RECIPSQRT_IEEE: + case EG_OP2_INST_FLT_TO_INT: + case EG_OP2_INST_SIN: + case EG_OP2_INST_COS: + return 1; + + default: radeon_error( + "Need instruction operand number for %x.\n", opcode); + }; + + return 3; +} + int Init_r700_AssemblerBase(SHADER_PIPE_TYPE spt, r700_AssemblerBase* pAsm, R700_Shader* pShader) { GLuint i; @@ -718,21 +785,55 @@ GLboolean add_vfetch_instruction(r700_AssemblerBase* pAsm, return GL_FALSE; } - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.pop_count = 0x0; - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.count = 0x0; - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_VTX; - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.barrier = 0x1; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, EG_CF_INST_VC, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + } + else + { + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.pop_count = 0x0; + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.count = 0x0; + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_VTX; + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.barrier = 0x1; + } LinkVertexInstruction(pAsm->cf_current_vtx_clause_ptr, vertex_instruction_ptr ); } else { - pAsm->cf_current_vtx_clause_ptr->m_Word1.f.count++; + if(8 == pAsm->unAsic) + { + unsigned int count = GETbits(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask) + 1; + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, count, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_vtx_clause_ptr->m_Word1.f.count++; + } } AddVTXInstruction(pAsm->pR700Shader, vertex_instruction_ptr); @@ -767,20 +868,59 @@ GLboolean add_tex_instruction(r700_AssemblerBase* pAsm, radeon_error("Could not allocate a new TEX CF instruction.\n"); return GL_FALSE; } - - pAsm->cf_current_tex_clause_ptr->m_Word1.f.pop_count = 0x0; - pAsm->cf_current_tex_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_tex_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_tex_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_tex_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_tex_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_TEX; - pAsm->cf_current_tex_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_tex_clause_ptr->m_Word1.f.barrier = 0x0; //0x1; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, EG_CF_INST_TC, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); +#ifdef FORCE_CF_TEX_BARRIER + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); +#else + SETfield(pAsm->cf_current_tex_clause_ptr->m_Word1.val, 0, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); +#endif + } + else + { + pAsm->cf_current_tex_clause_ptr->m_Word1.f.pop_count = 0x0; + pAsm->cf_current_tex_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_tex_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + + pAsm->cf_current_tex_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_tex_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_tex_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_TEX; + pAsm->cf_current_tex_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_tex_clause_ptr->m_Word1.f.barrier = 0x0; //0x1; + } } else - { - pAsm->cf_current_tex_clause_ptr->m_Word1.f.count++; + { + if(8 == pAsm->unAsic) + { + unsigned int count = GETbits(pAsm->cf_current_tex_clause_ptr->m_Word1.val, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask) + 1; + SETfield(pAsm->cf_current_vtx_clause_ptr->m_Word1.val, count, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_tex_clause_ptr->m_Word1.f.count++; + } } // If this clause constains any TEX instruction that is dependent on a previous instruction, @@ -891,6 +1031,188 @@ GLboolean assemble_vfetch_instruction(r700_AssemblerBase* pAsm, return GL_TRUE; } +GLboolean EG_assemble_vfetch_instruction(r700_AssemblerBase* pAsm, + GLuint destination_register, + GLenum type, + GLint size, + GLubyte element, + GLuint _signed, + GLboolean normalize, + GLenum format, + VTX_FETCH_METHOD * pFetchMethod) +{ + GLuint client_size_inbyte; + GLuint data_format; + GLuint mega_fetch_count; + GLuint is_mega_fetch_flag; + + GLuint dst_sel_x, dst_sel_y, dst_sel_z, dst_sel_w; + + R700VertexGenericFetch* vfetch_instruction_ptr; + R700VertexGenericFetch* assembled_vfetch_instruction_ptr + = pAsm->vfetch_instruction_ptr_array[element]; + + if (assembled_vfetch_instruction_ptr == NULL) + { + vfetch_instruction_ptr = (R700VertexGenericFetch*) CALLOC_STRUCT(R700VertexGenericFetch); + if (vfetch_instruction_ptr == NULL) + { + return GL_FALSE; + } + Init_R700VertexGenericFetch(vfetch_instruction_ptr); + } + else + { + vfetch_instruction_ptr = assembled_vfetch_instruction_ptr; + } + + data_format = GetSurfaceFormat(type, size, &client_size_inbyte); + + if(GL_TRUE == pFetchMethod->bEnableMini) //More conditions here + { + //TODO : mini fetch + mega_fetch_count = 0; + is_mega_fetch_flag = 0; + } + else + { + mega_fetch_count = MEGA_FETCH_BYTES - 1; + is_mega_fetch_flag = 0x1; + pFetchMethod->mega_fetch_remainder = MEGA_FETCH_BYTES - client_size_inbyte; + } + + SETfield(vfetch_instruction_ptr->m_Word0.val, EG_VC_INST_FETCH, + EG_VTX_WORD0__VC_INST_shift, + EG_VTX_WORD0__VC_INST_mask); + SETfield(vfetch_instruction_ptr->m_Word0.val, EG_VTX_FETCH_VERTEX_DATA, + EG_VTX_WORD0__FETCH_TYPE_shift, + EG_VTX_WORD0__FETCH_TYPE_mask); + CLEARbit(vfetch_instruction_ptr->m_Word0.val, + EG_VTX_WORD0__FWQ_bit); + SETfield(vfetch_instruction_ptr->m_Word0.val, element, + EG_VTX_WORD0__BUFFER_ID_shift, + EG_VTX_WORD0__BUFFER_ID_mask); + SETfield(vfetch_instruction_ptr->m_Word0.val, 0x0, + EG_VTX_WORD0__SRC_GPR_shift, + EG_VTX_WORD0__SRC_GPR_mask); + SETfield(vfetch_instruction_ptr->m_Word0.val, SQ_ABSOLUTE, + EG_VTX_WORD0__SRC_REL_shift, + EG_VTX_WORD0__SRC_REL_bit); + SETfield(vfetch_instruction_ptr->m_Word0.val, SQ_SEL_X, + EG_VTX_WORD0__SRC_SEL_X_shift, + EG_VTX_WORD0__SRC_SEL_X_mask); + SETfield(vfetch_instruction_ptr->m_Word0.val, mega_fetch_count, + EG_VTX_WORD0__MFC_shift, + EG_VTX_WORD0__MFC_mask); + + if(format == GL_BGRA) + { + dst_sel_x = (size < 1) ? SQ_SEL_0 : SQ_SEL_Z; + dst_sel_y = (size < 2) ? SQ_SEL_0 : SQ_SEL_Y; + dst_sel_z = (size < 3) ? SQ_SEL_0 : SQ_SEL_X; + dst_sel_w = (size < 4) ? SQ_SEL_1 : SQ_SEL_W; + } + else + { + dst_sel_x = (size < 1) ? SQ_SEL_0 : SQ_SEL_X; + dst_sel_y = (size < 2) ? SQ_SEL_0 : SQ_SEL_Y; + dst_sel_z = (size < 3) ? SQ_SEL_0 : SQ_SEL_Z; + dst_sel_w = (size < 4) ? SQ_SEL_1 : SQ_SEL_W; + + } + SETfield(vfetch_instruction_ptr->m_Word1.val, dst_sel_x, + EG_VTX_WORD1__DST_SEL_X_shift, + EG_VTX_WORD1__DST_SEL_X_mask); + SETfield(vfetch_instruction_ptr->m_Word1.val, dst_sel_y, + EG_VTX_WORD1__DST_SEL_Y_shift, + EG_VTX_WORD1__DST_SEL_Y_mask); + SETfield(vfetch_instruction_ptr->m_Word1.val, dst_sel_z, + EG_VTX_WORD1__DST_SEL_Z_shift, + EG_VTX_WORD1__DST_SEL_Z_mask); + SETfield(vfetch_instruction_ptr->m_Word1.val, dst_sel_w, + EG_VTX_WORD1__DST_SEL_W_shift, + EG_VTX_WORD1__DST_SEL_W_mask); + + SETfield(vfetch_instruction_ptr->m_Word1.val, 0, /* use format here, in r6/r7, format used set in const, need to use same */ + EG_VTX_WORD1__UCF_shift, + EG_VTX_WORD1__UCF_bit); + SETfield(vfetch_instruction_ptr->m_Word1.val, data_format, + EG_VTX_WORD1__DATA_FORMAT_shift, + EG_VTX_WORD1__DATA_FORMAT_mask); +#ifdef TEST_VFETCH + SETfield(vfetch_instruction_ptr->m_Word1.val, SQ_FORMAT_COMP_SIGNED, + EG_VTX_WORD1__FCA_shift, + EG_VTX_WORD1__FCA_bit); +#else + if(1 == _signed) + { + SETfield(vfetch_instruction_ptr->m_Word1.val, SQ_FORMAT_COMP_SIGNED, + EG_VTX_WORD1__FCA_shift, + EG_VTX_WORD1__FCA_bit); + } + else + { + SETfield(vfetch_instruction_ptr->m_Word1.val, SQ_FORMAT_COMP_UNSIGNED, + EG_VTX_WORD1__FCA_shift, + EG_VTX_WORD1__FCA_bit); + } +#endif /* TEST_VFETCH */ + + if(GL_TRUE == normalize) + { + SETfield(vfetch_instruction_ptr->m_Word1.val, SQ_NUM_FORMAT_NORM, + EG_VTX_WORD1__NFA_shift, + EG_VTX_WORD1__NFA_mask); + } + else + { + SETfield(vfetch_instruction_ptr->m_Word1.val, SQ_NUM_FORMAT_SCALED, + EG_VTX_WORD1__NFA_shift, + EG_VTX_WORD1__NFA_mask); + } + + /* Destination register */ + SETfield(vfetch_instruction_ptr->m_Word1.val, destination_register, + EG_VTX_WORD1_GPR__DST_GPR_shift, + EG_VTX_WORD1_GPR__DST_GPR_mask); + SETfield(vfetch_instruction_ptr->m_Word1.val, SQ_ABSOLUTE, + EG_VTX_WORD1_GPR__DST_REL_shift, + EG_VTX_WORD1_GPR__DST_REL_bit); + + + SETfield(vfetch_instruction_ptr->m_Word2.val, 0, + EG_VTX_WORD2__OFFSET_shift, + EG_VTX_WORD2__OFFSET_mask); + SETfield(vfetch_instruction_ptr->m_Word2.val, SQ_ENDIAN_NONE, + EG_VTX_WORD2__ENDIAN_SWAP_shift, + EG_VTX_WORD2__ENDIAN_SWAP_mask); + SETfield(vfetch_instruction_ptr->m_Word2.val, 0, + EG_VTX_WORD2__CBNS_shift, + EG_VTX_WORD2__CBNS_bit); + SETfield(vfetch_instruction_ptr->m_Word2.val, is_mega_fetch_flag, + EG_VTX_WORD2__MEGA_FETCH_shift, + EG_VTX_WORD2__MEGA_FETCH_mask); + + if (assembled_vfetch_instruction_ptr == NULL) + { + if ( GL_FALSE == add_vfetch_instruction(pAsm, (R700VertexInstruction *)vfetch_instruction_ptr) ) + { + return GL_FALSE; + } + + if (pAsm->vfetch_instruction_ptr_array[element] != NULL) + { + return GL_FALSE; + } + else + { + pAsm->vfetch_instruction_ptr_array[element] = vfetch_instruction_ptr; + } + } + + return GL_TRUE; +} + GLboolean assemble_vfetch_instruction2(r700_AssemblerBase* pAsm, GLuint destination_register, GLenum type, @@ -1357,7 +1679,7 @@ GLboolean assemble_src(r700_AssemblerBase *pAsm, break; case PROGRAM_INPUT: setaddrmode_PVSSRC(&(pAsm->S[fld].src), ADDR_ABSOLUTE); - pAsm->S[fld].src.rtype = SRC_REG_INPUT; + pAsm->S[fld].src.rtype = SRC_REG_GPR; switch (pAsm->currentShaderType) { case SPT_FP: @@ -1368,6 +1690,19 @@ GLboolean assemble_src(r700_AssemblerBase *pAsm, break; } break; + case PROGRAM_OUTPUT: + setaddrmode_PVSSRC(&(pAsm->S[fld].src), ADDR_ABSOLUTE); + pAsm->S[fld].src.rtype = SRC_REG_GPR; + switch (pAsm->currentShaderType) + { + case SPT_FP: + pAsm->S[fld].src.reg = pAsm->uiFP_OutputMap[pILInst->SrcReg[src].Index]; + break; + case SPT_VP: + pAsm->S[fld].src.reg = pAsm->ucVP_OutputMap[pILInst->SrcReg[src].Index]; + break; + } + break; default: radeon_error("Invalid source argument type : %d \n", pILInst->SrcReg[src].File); return GL_FALSE; @@ -1521,7 +1856,7 @@ GLboolean tex_src(r700_AssemblerBase *pAsm) bValidTexCoord = GL_TRUE; pAsm->S[0].src.reg = pAsm->ucVP_AttributeMap[pILInst->SrcReg[0].Index]; - pAsm->S[0].src.rtype = SRC_REG_INPUT; + pAsm->S[0].src.rtype = SRC_REG_GPR; break; } } @@ -1544,7 +1879,7 @@ GLboolean tex_src(r700_AssemblerBase *pAsm) bValidTexCoord = GL_TRUE; pAsm->S[0].src.reg = pAsm->uiFP_AttributeMap[pILInst->SrcReg[0].Index]; - pAsm->S[0].src.rtype = SRC_REG_INPUT; + pAsm->S[0].src.rtype = SRC_REG_GPR; break; case FRAG_ATTRIB_FACE: fprintf(stderr, "FRAG_ATTRIB_FACE unsupported\n"); @@ -1560,7 +1895,7 @@ GLboolean tex_src(r700_AssemblerBase *pAsm) bValidTexCoord = GL_TRUE; pAsm->S[0].src.reg = pAsm->uiFP_AttributeMap[pILInst->SrcReg[0].Index]; - pAsm->S[0].src.rtype = SRC_REG_INPUT; + pAsm->S[0].src.rtype = SRC_REG_GPR; } } @@ -1606,19 +1941,68 @@ GLboolean assemble_tex_instruction(r700_AssemblerBase *pAsm, GLboolean normalize texture_coordinate_source = &(pAsm->S[0].src); texture_unit_source = &(pAsm->S[1].src); - tex_instruction_ptr->m_Word0.f.tex_inst = pAsm->D.dst.opcode; - tex_instruction_ptr->m_Word0.f.bc_frac_mode = 0x0; - tex_instruction_ptr->m_Word0.f.fetch_whole_quad = 0x0; - tex_instruction_ptr->m_Word0.f.alt_const = 0; - - if(SPT_VP == pAsm->currentShaderType) + if(8 == pAsm->unAsic) /* evergreen */ { - tex_instruction_ptr->m_Word0.f.resource_id = texture_unit_source->reg + VERT_ATTRIB_MAX; - pAsm->unVetTexBits |= 1 << texture_unit_source->reg; + + SETfield(tex_instruction_ptr->m_Word0.val, pAsm->D.dst.opcode, + EG_TEX_WORD0__TEX_INST_shift, + EG_TEX_WORD0__TEX_INST_mask); + + if( (SQ_TEX_INST_GET_GRADIENTS_H == pAsm->D.dst.opcode) + ||(SQ_TEX_INST_GET_GRADIENTS_V == pAsm->D.dst.opcode) ) + { + /* Use fine texel derivative calculation rather than use quad derivative */ + SETfield(tex_instruction_ptr->m_Word0.val, 1, + EG_TEX_WORD0__INST_MOD_shift, + EG_TEX_WORD0__INST_MOD_mask); + } + else + { + SETfield(tex_instruction_ptr->m_Word0.val, 0, + EG_TEX_WORD0__INST_MOD_shift, + EG_TEX_WORD0__INST_MOD_mask); + } + + CLEARbit(tex_instruction_ptr->m_Word0.val, EG_TEX_WORD0__FWQ_bit); + + if(SPT_VP == pAsm->currentShaderType) + { + SETfield(tex_instruction_ptr->m_Word0.val, (texture_unit_source->reg + VERT_ATTRIB_MAX), + EG_TEX_WORD0__RESOURCE_ID_shift, + EG_TEX_WORD0__RESOURCE_ID_mask); + pAsm->unVetTexBits |= 1 << texture_unit_source->reg; + } + else + { + SETfield(tex_instruction_ptr->m_Word0.val, texture_unit_source->reg, + EG_TEX_WORD0__RESOURCE_ID_shift, + EG_TEX_WORD0__RESOURCE_ID_mask); + } + + CLEARbit(tex_instruction_ptr->m_Word0.val, EG_TEX_WORD0__ALT_CONST_bit); + SETfield(tex_instruction_ptr->m_Word0.val, 0, + EG_TEX_WORD0__RIM_shift, + EG_TEX_WORD0__RIM_mask); + SETfield(tex_instruction_ptr->m_Word0.val, 0, + EG_TEX_WORD0__SIM_shift, + EG_TEX_WORD0__SIM_mask); } else { - tex_instruction_ptr->m_Word0.f.resource_id = texture_unit_source->reg; + tex_instruction_ptr->m_Word0.f.tex_inst = pAsm->D.dst.opcode; + tex_instruction_ptr->m_Word0.f.bc_frac_mode = 0x0; + tex_instruction_ptr->m_Word0.f.fetch_whole_quad = 0x0; + tex_instruction_ptr->m_Word0.f.alt_const = 0; + + if(SPT_VP == pAsm->currentShaderType) + { + tex_instruction_ptr->m_Word0.f.resource_id = texture_unit_source->reg + VERT_ATTRIB_MAX; + pAsm->unVetTexBits |= 1 << texture_unit_source->reg; + } + else + { + tex_instruction_ptr->m_Word0.f.resource_id = texture_unit_source->reg; + } } tex_instruction_ptr->m_Word1.f.lod_bias = 0x0; @@ -1644,8 +2028,20 @@ GLboolean assemble_tex_instruction(r700_AssemblerBase *pAsm, GLboolean normalize if ( (pAsm->D.dst.rtype == DST_REG_TEMPORARY) || (pAsm->D.dst.rtype == DST_REG_OUT) ) { - tex_instruction_ptr->m_Word0.f.src_gpr = texture_coordinate_source->reg; - tex_instruction_ptr->m_Word0.f.src_rel = SQ_ABSOLUTE; + if(8 == pAsm->unAsic) /* evergreen */ + { + SETfield(tex_instruction_ptr->m_Word0.val, texture_coordinate_source->reg, + EG_TEX_WORD0__SRC_GPR_shift, + EG_TEX_WORD0__SRC_GPR_mask); + SETfield(tex_instruction_ptr->m_Word0.val, SQ_ABSOLUTE, + EG_TEX_WORD0__SRC_REL_shift, + EG_TEX_WORD0__SRC_REL_bit); + } + else + { + tex_instruction_ptr->m_Word0.f.src_gpr = texture_coordinate_source->reg; + tex_instruction_ptr->m_Word0.f.src_rel = SQ_ABSOLUTE; + } tex_instruction_ptr->m_Word1.f.dst_gpr = pAsm->D.dst.reg; tex_instruction_ptr->m_Word1.f.dst_rel = SQ_ABSOLUTE; @@ -1696,7 +2092,8 @@ void initialize(r700_AssemblerBase *pAsm) GLboolean assemble_alu_src(R700ALUInstruction* alu_instruction_ptr, int source_index, PVSSRC* pSource, - BITS scalar_channel_index) + BITS scalar_channel_index, + r700_AssemblerBase *pAsm) { BITS src_sel; BITS src_rel; @@ -1745,14 +2142,23 @@ GLboolean assemble_alu_src(R700ALUInstruction* alu_instruction_ptr, else { if ( (pSource->rtype == SRC_REG_TEMPORARY) || - (pSource->rtype == SRC_REG_INPUT) + (pSource->rtype == SRC_REG_GPR) ) { src_sel = pSource->reg; } else if (pSource->rtype == SRC_REG_CONSTANT) { - src_sel = pSource->reg + CFILE_REGISTER_OFFSET; + /* TODO : 4 const buffers */ + if(GL_TRUE == pAsm->bUseMemConstant) + { + src_sel = pSource->reg + SQ_ALU_SRC_KCACHE0_BASE; + pAsm->kcacheUsed = SQ_ALU_SRC_KCACHE0_BASE; + } + else + { + src_sel = pSource->reg + CFILE_REGISTER_OFFSET; + } } else if (pSource->rtype == SRC_REC_LITERAL) { @@ -1902,6 +2308,17 @@ GLboolean add_alu_instruction(r700_AssemblerBase* pAsm, pAsm->cf_current_alu_clause_ptr->m_Word1.f.count += (GetInstructionSize(alu_instruction_ptr->m_ShaderInstType) / 2); } + /* TODO : handle 4 bufs */ + if( (pAsm->kcacheUsed > 0) && (GL_TRUE == pAsm->bUseMemConstant) ) + { + pAsm->cf_current_alu_clause_ptr->m_Word0.f.kcache_bank0 = 0x0; + pAsm->cf_current_alu_clause_ptr->m_Word0.f.kcache_bank1 = 0x0; + pAsm->cf_current_alu_clause_ptr->m_Word0.f.kcache_mode0 = SQ_CF_KCACHE_LOCK_2; + pAsm->cf_current_alu_clause_ptr->m_Word1.f.kcache_mode1 = SQ_CF_KCACHE_NOP; + pAsm->cf_current_alu_clause_ptr->m_Word1.f.kcache_addr0 = 0x0; + pAsm->cf_current_alu_clause_ptr->m_Word1.f.kcache_addr1 = 0x0; + } + // If this clause constains any instruction that is forward dependent on a TEX instruction, // set the whole_quad_mode for this clause if ( pAsm->pInstDeps[pAsm->uiCurInst].nDstDep > (-1) ) @@ -1925,6 +2342,80 @@ GLboolean add_alu_instruction(r700_AssemblerBase* pAsm, return GL_TRUE; } +GLboolean EG_add_ps_interp(r700_AssemblerBase* pAsm) +{ + R700ALUInstruction * alu_instruction_ptr = NULL; + + int ui; + unsigned int uj; + unsigned int unWord0Temp = 0x380C00; + unsigned int unWord1Temp = 0x146B10; //SQ_SEL_X + + if(pAsm->uIIns > 0) + { + for(ui=(pAsm->uIIns-1); ui>=0; ui--) + { + for(uj=0; uj<8; uj++) + { + alu_instruction_ptr = (R700ALUInstruction*) CALLOC_STRUCT(R700ALUInstruction); + Init_R700ALUInstruction(alu_instruction_ptr); + alu_instruction_ptr->m_Word0.val = unWord0Temp; + alu_instruction_ptr->m_Word1.val = unWord1Temp; + + if(uj < 4) + { + SETfield(alu_instruction_ptr->m_Word1.val, EG_OP2_INST_INTERP_ZW, + EG_ALU_WORD1_OP2__ALU_INST_shift, EG_ALU_WORD1_OP2__ALU_INST_mask); + } + else + { + SETfield(alu_instruction_ptr->m_Word1.val, EG_OP2_INST_INTERP_XY, + EG_ALU_WORD1_OP2__ALU_INST_shift, EG_ALU_WORD1_OP2__ALU_INST_mask); + } + if( (uj > 1) && (uj < 6) ) + { + SETfield(alu_instruction_ptr->m_Word1.val, 1, + EG_ALU_WORD1_OP2__WRITE_MASK_shift, EG_ALU_WORD1_OP2__WRITE_MASK_bit); + } + else + { + SETfield(alu_instruction_ptr->m_Word1.val, 0, + EG_ALU_WORD1_OP2__WRITE_MASK_shift, EG_ALU_WORD1_OP2__WRITE_MASK_bit); + } + if( (uj > 1) && (uj < 6) ) + { + SETfield(alu_instruction_ptr->m_Word1.val, ui, + EG_ALU_WORD1__DST_GPR_shift, EG_ALU_WORD1__DST_GPR_mask); + } + else + { + SETfield(alu_instruction_ptr->m_Word1.val, 111, + EG_ALU_WORD1__DST_GPR_shift, EG_ALU_WORD1__DST_GPR_mask); + } + + SETfield(alu_instruction_ptr->m_Word1.val, (uj % 4), + EG_ALU_WORD1__DST_CHAN_shift, EG_ALU_WORD1__DST_CHAN_mask); + SETfield(alu_instruction_ptr->m_Word0.val, (1 - (uj % 2)), + EG_ALU_WORD0__SRC0_CHAN_shift, EG_ALU_WORD0__SRC0_CHAN_mask); + SETfield(alu_instruction_ptr->m_Word0.val, (EG_ALU_SRC_PARAM_BASE + ui), + EG_ALU_WORD0__SRC1_SEL_shift, EG_ALU_WORD0__SRC1_SEL_mask); + if(3 == (uj % 4)) + { + SETfield(alu_instruction_ptr->m_Word0.val, 1, + EG_ALU_WORD0__LAST_shift, EG_ALU_WORD0__LAST_bit); + } + + if(GL_FALSE == add_alu_instruction(pAsm, alu_instruction_ptr, 4) ) + { + return GL_FALSE; + } + } + } + } + + return GL_TRUE; +} + void get_src_properties(R700ALUInstruction* alu_instruction_ptr, int source_index, BITS* psrc_sel, @@ -2175,8 +2666,16 @@ GLboolean check_scalar(r700_AssemblerBase* pAsm, BITS src_neg [3] = {0,0,0}; GLuint swizzle_key; + GLuint number_of_operands; - GLuint number_of_operands = r700GetNumOperands(pAsm->D.dst.opcode, pAsm->D.dst.op3); + if(8 == pAsm->unAsic) + { + number_of_operands = EG_GetNumOperands(pAsm->D.dst.opcode, pAsm->D.dst.op3); + } + else + { + number_of_operands = r700GetNumOperands(pAsm->D.dst.opcode, pAsm->D.dst.op3); + } for (src=0; src<number_of_operands; src++) { @@ -2264,8 +2763,16 @@ GLboolean check_vector(r700_AssemblerBase* pAsm, BITS src_neg [3] = {0,0,0}; GLuint swizzle_key; + GLuint number_of_operands; - GLuint number_of_operands = r700GetNumOperands(pAsm->D.dst.opcode, pAsm->D.dst.op3); + if(8 == pAsm->unAsic) + { + number_of_operands = EG_GetNumOperands(pAsm->D.dst.opcode, pAsm->D.dst.op3); + } + else + { + number_of_operands = r700GetNumOperands(pAsm->D.dst.opcode, pAsm->D.dst.op3); + } for (src=0; src<number_of_operands; src++) { @@ -2345,12 +2852,23 @@ GLboolean assemble_alu_instruction(r700_AssemblerBase *pAsm) PVSSRC * pcurrent_source; int current_source_index; GLuint contiguous_slots_needed; + GLuint uNumSrc; + GLboolean bSplitInst; + + if(8 == pAsm->unAsic) + { + uNumSrc = EG_GetNumOperands(pAsm->D.dst.opcode, pAsm->D.dst.op3); + } + else + { + uNumSrc = r700GetNumOperands(pAsm->D.dst.opcode, pAsm->D.dst.op3); + } - GLuint uNumSrc = r700GetNumOperands(pAsm->D.dst.opcode, pAsm->D.dst.op3); //GLuint channel_swizzle, j; //GLuint chan_counter[4] = {0, 0, 0, 0}; //PVSSRC * pSource[3]; - GLboolean bSplitInst = GL_FALSE; + bSplitInst = GL_FALSE; + pAsm->kcacheUsed = 0; if (1 == pAsm->D.dst.math) { @@ -2384,7 +2902,7 @@ GLboolean assemble_alu_instruction(r700_AssemblerBase *pAsm) default: channel_swizzle = SQ_SEL_MASK; break; } if ( ((pSource[j]->rtype == SRC_REG_TEMPORARY) || - (pSource[j]->rtype == SRC_REG_INPUT)) + (pSource[j]->rtype == SRC_REG_GPR)) && (channel_swizzle <= SQ_SEL_W) ) { chan_counter[channel_swizzle]++; @@ -2449,7 +2967,8 @@ GLboolean assemble_alu_instruction(r700_AssemblerBase *pAsm) if (GL_FALSE == assemble_alu_src(alu_instruction_ptr, current_source_index, pcurrent_source, - scalar_channel_index) ) + scalar_channel_index, + pAsm) ) { return GL_FALSE; } @@ -2463,7 +2982,8 @@ GLboolean assemble_alu_instruction(r700_AssemblerBase *pAsm) if (GL_FALSE == assemble_alu_src(alu_instruction_ptr, current_source_index, pcurrent_source, - scalar_channel_index) ) + scalar_channel_index, + pAsm) ) { return GL_FALSE; } @@ -2546,7 +3066,8 @@ GLboolean assemble_alu_instruction(r700_AssemblerBase *pAsm) if ( GL_FALSE == assemble_alu_src(alu_instruction_ptr, current_source_index, pcurrent_source, - scalar_channel_index) ) + scalar_channel_index, + pAsm) ) { return GL_FALSE; } @@ -2987,7 +3508,14 @@ GLboolean assemble_DOT(r700_AssemblerBase *pAsm) return GL_FALSE; } - pAsm->D.dst.opcode = SQ_OP2_INST_DOT4; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_DOT4; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_DOT4; + } if( GL_FALSE == assemble_dst(pAsm) ) { @@ -3004,7 +3532,14 @@ GLboolean assemble_DOT(r700_AssemblerBase *pAsm) return GL_FALSE; } - if(OPCODE_DP3 == pAsm->pILInst[pAsm->uiCurInst].Opcode) + if(OPCODE_DP2 == pAsm->pILInst[pAsm->uiCurInst].Opcode) + { + zerocomp_PVSSRC(&(pAsm->S[0].src),2); + zerocomp_PVSSRC(&(pAsm->S[0].src),3); + zerocomp_PVSSRC(&(pAsm->S[1].src),2); + zerocomp_PVSSRC(&(pAsm->S[1].src),3); + } + else if(OPCODE_DP3 == pAsm->pILInst[pAsm->uiCurInst].Opcode) { zerocomp_PVSSRC(&(pAsm->S[0].src), 3); zerocomp_PVSSRC(&(pAsm->S[1].src), 3); @@ -3062,6 +3597,11 @@ GLboolean assemble_DST(r700_AssemblerBase *pAsm) GLboolean assemble_EX2(r700_AssemblerBase *pAsm) { + if(8 == pAsm->unAsic) + { + return assemble_math_function(pAsm, EG_OP2_INST_EXP_IEEE); + } + return assemble_math_function(pAsm, SQ_OP2_INST_EXP_IEEE); } @@ -3094,7 +3634,14 @@ GLboolean assemble_EXP(r700_AssemblerBase *pAsm) return GL_FALSE; } - pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_EXP_IEEE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + } pAsm->D.dst.math = 1; if( GL_FALSE == assemble_dst(pAsm) ) @@ -3143,7 +3690,14 @@ GLboolean assemble_EXP(r700_AssemblerBase *pAsm) // EX2 dst.z, a.x if ((pAsm->pILInst->DstReg.WriteMask >> 2) & 0x1) { - pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_EXP_IEEE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + } pAsm->D.dst.math = 1; if( GL_FALSE == assemble_dst(pAsm) ) @@ -3218,6 +3772,11 @@ GLboolean assemble_FLR(r700_AssemblerBase *pAsm) GLboolean assemble_FLR_INT(r700_AssemblerBase *pAsm) { + if(8 == pAsm->unAsic) + { + return assemble_math_function(pAsm, EG_OP2_INST_FLT_TO_INT); + } + return assemble_math_function(pAsm, SQ_OP2_INST_FLT_TO_INT); } @@ -3300,6 +3859,11 @@ GLboolean assemble_KIL(r700_AssemblerBase *pAsm, GLuint opcode) GLboolean assemble_LG2(r700_AssemblerBase *pAsm) { + if(8 == pAsm->unAsic) + { + return assemble_math_function(pAsm, EG_OP2_INST_LOG_IEEE); + } + return assemble_math_function(pAsm, SQ_OP2_INST_LOG_IEEE); } @@ -3339,7 +3903,14 @@ GLboolean assemble_LRP(r700_AssemblerBase *pAsm) return GL_FALSE; } - pAsm->D.dst.opcode = SQ_OP3_INST_MULADD; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP3_INST_MULADD; + } + else + { + pAsm->D.dst.opcode = SQ_OP3_INST_MULADD; + } pAsm->D.dst.op3 = 1; pAsm->D.dst.rtype = DST_REG_TEMPORARY; @@ -3437,7 +4008,14 @@ GLboolean assemble_LOG(r700_AssemblerBase *pAsm) // LG2 tmp2.x, tmp1.x // FLOOR tmp3.x, tmp2.x - pAsm->D.dst.opcode = SQ_OP2_INST_LOG_IEEE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_LOG_IEEE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_LOG_IEEE; + } pAsm->D.dst.math = 1; setaddrmode_PVSDST(&(pAsm->D.dst), ADDR_ABSOLUTE); @@ -3528,7 +4106,14 @@ GLboolean assemble_LOG(r700_AssemblerBase *pAsm) return GL_FALSE; } - pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_EXP_IEEE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + } pAsm->D.dst.math = 1; if( GL_FALSE == assemble_dst(pAsm) ) @@ -3610,7 +4195,14 @@ GLboolean assemble_MAD(struct r700_AssemblerBase *pAsm) return GL_FALSE; } - pAsm->D.dst.opcode = SQ_OP3_INST_MULADD; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP3_INST_MULADD; + } + else + { + pAsm->D.dst.opcode = SQ_OP3_INST_MULADD; + } pAsm->D.dst.op3 = 1; tmp = (-1); @@ -3778,7 +4370,14 @@ GLboolean assemble_LIT(r700_AssemblerBase *pAsm) swizzleagain_PVSSRC(&(pAsm->S[0].src), SQ_SEL_Y, SQ_SEL_Y, SQ_SEL_Y, SQ_SEL_Y); /* dst.z = log(src.y) */ - pAsm->D.dst.opcode = SQ_OP2_INST_LOG_CLAMPED; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_LOG_CLAMPED; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_LOG_CLAMPED; + } pAsm->D.dst.math = 1; pAsm->D.dst.rtype = dstType; pAsm->D.dst.reg = dstReg; @@ -3809,7 +4408,14 @@ GLboolean assemble_LIT(r700_AssemblerBase *pAsm) swizzleagain_PVSSRC(&(pAsm->S[2].src), SQ_SEL_X, SQ_SEL_X, SQ_SEL_X, SQ_SEL_X); /* tmp.x = amd MUL_LIT(src.w, dst.z, src.x ) */ - pAsm->D.dst.opcode = SQ_OP3_INST_MUL_LIT; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP3_INST_MUL_LIT; + } + else + { + pAsm->D.dst.opcode = SQ_OP3_INST_MUL_LIT; + } pAsm->D.dst.math = 1; pAsm->D.dst.op3 = 1; pAsm->D.dst.rtype = DST_REG_TEMPORARY; @@ -3842,7 +4448,14 @@ GLboolean assemble_LIT(r700_AssemblerBase *pAsm) } /* dst.z = exp(tmp.x) */ - pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_EXP_IEEE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + } pAsm->D.dst.math = 1; pAsm->D.dst.rtype = dstType; pAsm->D.dst.reg = dstReg; @@ -3997,7 +4610,14 @@ GLboolean assemble_POW(r700_AssemblerBase *pAsm) tmp = gethelpr(pAsm); // LG2 tmp.x, a.swizzle - pAsm->D.dst.opcode = SQ_OP2_INST_LOG_IEEE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_LOG_IEEE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_LOG_IEEE; + } pAsm->D.dst.math = 1; setaddrmode_PVSDST(&(pAsm->D.dst), ADDR_ABSOLUTE); @@ -4041,7 +4661,14 @@ GLboolean assemble_POW(r700_AssemblerBase *pAsm) // EX2 dst.mask, tmp.x // EX2 tmp.x, tmp.x - pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_EXP_IEEE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_EXP_IEEE; + } pAsm->D.dst.math = 1; setaddrmode_PVSDST(&(pAsm->D.dst), ADDR_ABSOLUTE); @@ -4085,11 +4712,21 @@ GLboolean assemble_POW(r700_AssemblerBase *pAsm) GLboolean assemble_RCP(r700_AssemblerBase *pAsm) { + if(8 == pAsm->unAsic) + { + return assemble_math_function(pAsm, EG_OP2_INST_RECIP_IEEE); + } + return assemble_math_function(pAsm, SQ_OP2_INST_RECIP_IEEE); } GLboolean assemble_RSQ(r700_AssemblerBase *pAsm) { + if(8 == pAsm->unAsic) + { + return assemble_math_function(pAsm, EG_OP2_INST_RECIPSQRT_IEEE); + } + return assemble_math_function(pAsm, SQ_OP2_INST_RECIPSQRT_IEEE); } @@ -4175,7 +4812,14 @@ GLboolean assemble_SCS(r700_AssemblerBase *pAsm) } // COS dst.x, a.x - pAsm->D.dst.opcode = SQ_OP2_INST_COS; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_COS; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_COS; + } pAsm->D.dst.math = 1; assemble_dst(pAsm); @@ -4194,7 +4838,14 @@ GLboolean assemble_SCS(r700_AssemblerBase *pAsm) } // SIN dst.y, a.x - pAsm->D.dst.opcode = SQ_OP2_INST_SIN; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_SIN; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_SIN; + } pAsm->D.dst.math = 1; assemble_dst(pAsm); @@ -4349,6 +5000,65 @@ GLboolean assemble_SLT(r700_AssemblerBase *pAsm) return GL_TRUE; } +GLboolean assemble_SSG(r700_AssemblerBase *pAsm) +{ + checkop1(pAsm); + + GLuint tmp = gethelpr(pAsm); + /* tmp = (src > 0 ? 1 : src) */ + pAsm->D.dst.opcode = SQ_OP3_INST_CNDGT; + pAsm->D.dst.op3 = 1; + pAsm->D.dst.rtype = DST_REG_TEMPORARY; + pAsm->D.dst.reg = tmp; + + if( GL_FALSE == assemble_src(pAsm, 0, -1) ) + { + return GL_FALSE; + } + + setswizzle_PVSSRC(&(pAsm->S[1].src), SQ_SEL_1); + + if( GL_FALSE == assemble_src(pAsm, 0, 2) ) + { + return GL_FALSE; + } + + if( GL_FALSE == next_ins(pAsm) ) + { + return GL_FALSE; + } + + /* dst = (-tmp > 0 ? -1 : tmp) */ + pAsm->D.dst.opcode = SQ_OP3_INST_CNDGT; + pAsm->D.dst.op3 = 1; + + if( GL_FALSE == assemble_dst(pAsm) ) + { + return GL_FALSE; + } + + setaddrmode_PVSSRC(&(pAsm->S[0].src), ADDR_ABSOLUTE); + pAsm->S[0].src.rtype = SRC_REG_TEMPORARY; + pAsm->S[0].src.reg = tmp; + noswizzle_PVSSRC(&(pAsm->S[0].src)); + neg_PVSSRC(&(pAsm->S[0].src)); + + setswizzle_PVSSRC(&(pAsm->S[1].src), SQ_SEL_1); + neg_PVSSRC(&(pAsm->S[1].src)); + + setaddrmode_PVSSRC(&(pAsm->S[2].src), ADDR_ABSOLUTE); + pAsm->S[2].src.rtype = SRC_REG_TEMPORARY; + pAsm->S[2].src.reg = tmp; + noswizzle_PVSSRC(&(pAsm->S[2].src)); + + if( GL_FALSE == next_ins(pAsm) ) + { + return GL_FALSE; + } + + return GL_TRUE; +} + GLboolean assemble_STP(r700_AssemblerBase *pAsm) { return GL_TRUE; @@ -4387,7 +5097,14 @@ GLboolean assemble_TEX(r700_AssemblerBase *pAsm) if (pAsm->pILInst[pAsm->uiCurInst].Opcode == OPCODE_TXP) { GLuint tmp = gethelpr(pAsm); - pAsm->D.dst.opcode = SQ_OP2_INST_RECIP_IEEE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_RECIP_IEEE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_RECIP_IEEE; + } pAsm->D.dst.math = 1; setaddrmode_PVSDST(&(pAsm->D.dst), ADDR_ABSOLUTE); pAsm->D.dst.rtype = DST_REG_TEMPORARY; @@ -4437,7 +5154,14 @@ GLboolean assemble_TEX(r700_AssemblerBase *pAsm) GLuint tmp2 = gethelpr(pAsm); /* tmp1.xyzw = CUBE(R0.zzxy, R0.yxzz) */ - pAsm->D.dst.opcode = SQ_OP2_INST_CUBE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_CUBE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_CUBE; + } setaddrmode_PVSDST(&(pAsm->D.dst), ADDR_ABSOLUTE); pAsm->D.dst.rtype = DST_REG_TEMPORARY; pAsm->D.dst.reg = tmp1; @@ -4462,7 +5186,14 @@ GLboolean assemble_TEX(r700_AssemblerBase *pAsm) } /* tmp1.z = RCP_e(|tmp1.z|) */ - pAsm->D.dst.opcode = SQ_OP2_INST_RECIP_IEEE; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP2_INST_RECIP_IEEE; + } + else + { + pAsm->D.dst.opcode = SQ_OP2_INST_RECIP_IEEE; + } pAsm->D.dst.math = 1; setaddrmode_PVSDST(&(pAsm->D.dst), ADDR_ABSOLUTE); pAsm->D.dst.rtype = DST_REG_TEMPORARY; @@ -4481,7 +5212,14 @@ GLboolean assemble_TEX(r700_AssemblerBase *pAsm) * MULADD R0.y, R0.y, PS1, (0x3FC00000, 1.5f).x * muladd has no writemask, have to use another temp */ - pAsm->D.dst.opcode = SQ_OP3_INST_MULADD; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP3_INST_MULADD; + } + else + { + pAsm->D.dst.opcode = SQ_OP3_INST_MULADD; + } pAsm->D.dst.op3 = 1; setaddrmode_PVSDST(&(pAsm->D.dst), ADDR_ABSOLUTE); pAsm->D.dst.rtype = DST_REG_TEMPORARY; @@ -4668,7 +5406,14 @@ GLboolean assemble_XPD(r700_AssemblerBase *pAsm) return GL_FALSE; } - pAsm->D.dst.opcode = SQ_OP3_INST_MULADD; + if(8 == pAsm->unAsic) + { + pAsm->D.dst.opcode = EG_OP3_INST_MULADD; + } + else + { + pAsm->D.dst.opcode = SQ_OP3_INST_MULADD; + } pAsm->D.dst.op3 = 1; if(0xF != pAsm->pILInst[pAsm->uiCurInst].DstReg.WriteMask) @@ -4825,16 +5570,49 @@ GLboolean jumpToOffest(r700_AssemblerBase *pAsm, GLuint pops, GLint offset) return GL_FALSE; } - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = pops; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_JUMP, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + pops, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = pops; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_JUMP; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_JUMP; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } pAsm->cf_current_cf_clause_ptr->m_Word0.f.addr = pAsm->cf_current_cf_clause_ptr->m_uIndex + offset; @@ -4848,17 +5626,50 @@ GLboolean pops(r700_AssemblerBase *pAsm, GLuint pops) return GL_FALSE; } - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = pops; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_POP, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + pops, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = pops; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_POP; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_POP; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } pAsm->cf_current_cf_clause_ptr->m_Word0.f.addr = pAsm->cf_current_cf_clause_ptr->m_uIndex + 1; return GL_TRUE; @@ -4876,23 +5687,66 @@ GLboolean assemble_IF(r700_AssemblerBase *pAsm, GLboolean bHasElse) return GL_FALSE; } - if(GL_TRUE != bHasElse) - { - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; + if(8 == pAsm->unAsic) + { + if(GL_TRUE != bHasElse) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + } + else + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + } + + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_JUMP, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); } else { - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; - } - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(GL_TRUE != bHasElse) + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; + } + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_JUMP; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_JUMP; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } pAsm->FCSP++; pAsm->fc_stack[pAsm->FCSP].type = FC_IF; @@ -4919,16 +5773,49 @@ GLboolean assemble_ELSE(r700_AssemblerBase *pAsm) return GL_FALSE; } - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; /// - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_ELSE, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; /// + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_ELSE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_ELSE; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } pAsm->fc_stack[pAsm->FCSP].mid = (R700ControlFlowGenericClause **)_mesa_realloc( (void *)pAsm->fc_stack[pAsm->FCSP].mid, 0, @@ -4988,17 +5875,49 @@ GLboolean assemble_BGNLOOP(r700_AssemblerBase *pAsm) return GL_FALSE; } - - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_LOOP_START_NO_AL, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_START_NO_AL; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_START_NO_AL; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } pAsm->FCSP++; pAsm->fc_stack[pAsm->FCSP].type = FC_LOOP; @@ -5039,18 +5958,50 @@ GLboolean assemble_BRK(r700_AssemblerBase *pAsm) return GL_FALSE; } - - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_LOOP_BREAK, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_BREAK; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_BREAK; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } pAsm->fc_stack[unFCSP].mid = (R700ControlFlowGenericClause **)_mesa_realloc( (void *)pAsm->fc_stack[unFCSP].mid, @@ -5064,18 +6015,52 @@ GLboolean assemble_BRK(r700_AssemblerBase *pAsm) return GL_FALSE; } - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_POP, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_POP; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_POP; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; - pAsm->cf_current_cf_clause_ptr->m_Word0.f.addr = pAsm->cf_current_cf_clause_ptr->m_uIndex + 1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } + + pAsm->cf_current_cf_clause_ptr->m_Word0.f.addr = pAsm->cf_current_cf_clause_ptr->m_uIndex + 1; checkStackDepth(pAsm, FC_PUSH_VPM, GL_TRUE); @@ -5109,18 +6094,50 @@ GLboolean assemble_CONT(r700_AssemblerBase *pAsm) return GL_FALSE; } - - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_LOOP_CONTINUE, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_CONTINUE; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_CONTINUE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } pAsm->fc_stack[unFCSP].mid = (R700ControlFlowGenericClause **)_mesa_realloc( (void *)pAsm->fc_stack[unFCSP].mid, @@ -5134,17 +6151,51 @@ GLboolean assemble_CONT(r700_AssemblerBase *pAsm) return GL_FALSE; } - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_POP, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_POP; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_POP; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; pAsm->cf_current_cf_clause_ptr->m_Word0.f.addr = pAsm->cf_current_cf_clause_ptr->m_uIndex + 1; checkStackDepth(pAsm, FC_PUSH_VPM, GL_TRUE); @@ -5163,17 +6214,49 @@ GLboolean assemble_ENDLOOP(r700_AssemblerBase *pAsm) return GL_FALSE; } - - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_LOOP_END, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_END; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_END; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } pAsm->cf_current_cf_clause_ptr->m_Word0.f.addr = pAsm->fc_stack[pAsm->FCSP].first->m_uIndex + 1; pAsm->fc_stack[pAsm->FCSP].first->m_Word0.f.addr = pAsm->cf_current_cf_clause_ptr->m_uIndex + 1; @@ -5235,17 +6318,51 @@ void add_return_inst(r700_AssemblerBase *pAsm) { return; } - //pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_RETURN; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_RETURN, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + //pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_RETURN; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } } GLboolean assemble_BGNSUB(r700_AssemblerBase *pAsm, GLint nILindex, GLuint uiIL_Shift) @@ -5368,17 +6485,50 @@ GLboolean assemble_CAL(r700_AssemblerBase *pAsm, return GL_FALSE; } - pAsm->cf_current_cf_clause_ptr->m_Word1.f.call_count = 1; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_CALL, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.call_count = 1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_CALL; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_CALL; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } /* Put in caller */ if( (pAsm->unCallerArrayPointer + 1) > pAsm->unCallerArraySize ) @@ -5579,16 +6729,49 @@ GLboolean breakLoopOnFlag(r700_AssemblerBase *pAsm, GLuint unFCSP) return GL_FALSE; } - pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__POP_COUNT_shift, EG_CF_WORD1__POP_COUNT_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + EG_CF_INST_LOOP_BREAK, + EG_CF_WORD1__CF_INST_shift, EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__CF_CONST_shift, EG_CF_WORD1__CF_CONST_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + SQ_CF_COND_ACTIVE, + EG_CF_WORD1__COND_shift, EG_CF_WORD1__COND_mask); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__EOP_shift, EG_CF_WORD1__EOP_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__VPM_shift, EG_CF_WORD1__VPM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 0, + EG_CF_WORD1__WQM_shift, EG_CF_WORD1__WQM_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__BARRIER_shift, EG_CF_WORD1__BARRIER_bit); + SETfield(pAsm->cf_current_cf_clause_ptr->m_Word1.val, + 1, + EG_CF_WORD1__COUNT_shift, EG_CF_WORD1__COUNT_mask); + } + else + { + pAsm->cf_current_cf_clause_ptr->m_Word1.f.pop_count = 1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_const = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cond = SQ_CF_COND_ACTIVE; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_BREAK; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_LOOP_BREAK; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + pAsm->cf_current_cf_clause_ptr->m_Word1.f.barrier = 0x1; + } pAsm->fc_stack[unFCSP].mid = (R700ControlFlowGenericClause **)_mesa_realloc( (void *)pAsm->fc_stack[unFCSP].mid, @@ -5677,10 +6860,19 @@ GLboolean AssembleInstr(GLuint uiFirstInst, return GL_FALSE; break; case OPCODE_COS: - if ( GL_FALSE == assemble_TRIG(pR700AsmCode, SQ_OP2_INST_COS) ) - return GL_FALSE; + if(8 == pR700AsmCode->unAsic) + { + if ( GL_FALSE == assemble_TRIG(pR700AsmCode, EG_OP2_INST_COS) ) + return GL_FALSE; + } + else + { + if ( GL_FALSE == assemble_TRIG(pR700AsmCode, SQ_OP2_INST_COS) ) + return GL_FALSE; + } break; + case OPCODE_DP2: case OPCODE_DP3: case OPCODE_DP4: case OPCODE_DPH: @@ -5794,8 +6986,16 @@ GLboolean AssembleInstr(GLuint uiFirstInst, return GL_FALSE; break; case OPCODE_SIN: - if ( GL_FALSE == assemble_TRIG(pR700AsmCode, SQ_OP2_INST_SIN) ) - return GL_FALSE; + if(8 == pR700AsmCode->unAsic) + { + if ( GL_FALSE == assemble_TRIG(pR700AsmCode, EG_OP2_INST_SIN) ) + return GL_FALSE; + } + else + { + if ( GL_FALSE == assemble_TRIG(pR700AsmCode, SQ_OP2_INST_SIN) ) + return GL_FALSE; + } break; case OPCODE_SCS: if ( GL_FALSE == assemble_SCS(pR700AsmCode) ) @@ -5872,6 +7072,13 @@ GLboolean AssembleInstr(GLuint uiFirstInst, // return GL_FALSE; // break; + case OPCODE_SSG: + if ( GL_FALSE == assemble_SSG(pR700AsmCode) ) + { + return GL_FALSE; + } + break; + case OPCODE_SWZ: if ( GL_FALSE == assemble_MOV(pR700AsmCode) ) { @@ -6006,7 +7213,7 @@ GLboolean AssembleInstr(GLuint uiFirstInst, return GL_TRUE; default: - radeon_error("internal: unknown instruction\n"); + radeon_error("r600: unknown instruction %d\n", pILInst[i].Opcode); return GL_FALSE; } } @@ -6016,7 +7223,15 @@ GLboolean AssembleInstr(GLuint uiFirstInst, GLboolean InitShaderProgram(r700_AssemblerBase * pAsm) { +#ifndef GENERATE_SHADER_FOR_2D setRetInLoopFlag(pAsm, SQ_SEL_0); +#endif + + if((SPT_FP == pAsm->currentShaderType) && (8 == pAsm->unAsic)) + { + EG_add_ps_interp(pAsm); + } + pAsm->alu_x_opcode = SQ_CF_INST_ALU; return GL_TRUE; } @@ -6039,6 +7254,7 @@ GLboolean RelocProgram(r700_AssemblerBase * pAsm, struct gl_program * pILProg) plstCFmain = pAsm->CALLSTACK[0].plstCFInstructions_local; +#ifndef GENERATE_SHADER_FOR_2D /* remove flags init if they are not used */ if((pAsm->unCFflags & HAS_LOOPRET) == 0) { @@ -6069,6 +7285,7 @@ GLboolean RelocProgram(r700_AssemblerBase * pAsm, struct gl_program * pILProg) pInst = pInst->pNextInst; }; } +#endif /* GENERATE_SHADER_FOR_2D */ if(pAsm->CALLSTACK[0].max > 0) { @@ -6175,13 +7392,20 @@ GLboolean RelocProgram(r700_AssemblerBase * pAsm, struct gl_program * pILProg) } else { - if(pAsm->bR6xx) + if(8 == pAsm->unAsic) { - uNumSrc = r700GetNumOperands(pALU->m_Word1_OP2.f6.alu_inst, 0); + uNumSrc = EG_GetNumOperands(pALU->m_Word1_OP2.f.alu_inst, 0); } else { - uNumSrc = r700GetNumOperands(pALU->m_Word1_OP2.f.alu_inst, 0); + if(pAsm->bR6xx) + { + uNumSrc = r700GetNumOperands(pALU->m_Word1_OP2.f6.alu_inst, 0); + } + else + { + uNumSrc = r700GetNumOperands(pALU->m_Word1_OP2.f.alu_inst, 0); + } } if(2 == uNumSrc) { /* 2 srcs */ @@ -6472,12 +7696,42 @@ GLboolean Process_Export(r700_AssemblerBase* pAsm, pAsm->cf_current_export_clause_ptr->m_Word0.f.index_gpr = 0x0; pAsm->cf_current_export_clause_ptr->m_Word0.f.elem_size = 0x3; - pAsm->cf_current_export_clause_ptr->m_Word1.f.burst_count = (export_count - 1); - pAsm->cf_current_export_clause_ptr->m_Word1.f.end_of_program = 0x0; - pAsm->cf_current_export_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; - pAsm->cf_current_export_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT; // _DONE - pAsm->cf_current_export_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; - pAsm->cf_current_export_clause_ptr->m_Word1.f.barrier = 0x1; + if(8 == pAsm->unAsic) + { + SETfield(pAsm->cf_current_export_clause_ptr->m_Word1.val, + (export_count - 1), + EG_CF_ALLOC_EXPORT_WORD1__BURST_COUNT_shift, + EG_CF_ALLOC_EXPORT_WORD1__BURST_COUNT_mask); + SETfield(pAsm->cf_current_export_clause_ptr->m_Word1.val, + 0, + EG_CF_ALLOC_EXPORT_WORD1__EOP_shift, + EG_CF_ALLOC_EXPORT_WORD1__EOP_bit); + SETfield(pAsm->cf_current_export_clause_ptr->m_Word1.val, + 0, + EG_CF_ALLOC_EXPORT_WORD1__VPM_shift, + EG_CF_ALLOC_EXPORT_WORD1__VPM_bit); + SETfield(pAsm->cf_current_export_clause_ptr->m_Word1.val, + EG_CF_INST_EXPORT, + EG_CF_WORD1__CF_INST_shift, + EG_CF_WORD1__CF_INST_mask); + SETfield(pAsm->cf_current_export_clause_ptr->m_Word1.val, + 0, + EG_CF_ALLOC_EXPORT_WORD1__MARK_shift, + EG_CF_ALLOC_EXPORT_WORD1__MARK_bit); + SETfield(pAsm->cf_current_export_clause_ptr->m_Word1.val, + 1, + EG_CF_ALLOC_EXPORT_WORD1__BARRIER_shift, + EG_CF_ALLOC_EXPORT_WORD1__BARRIER_bit); + } + else + { + pAsm->cf_current_export_clause_ptr->m_Word1.f.burst_count = (export_count - 1); + pAsm->cf_current_export_clause_ptr->m_Word1.f.end_of_program = 0x0; + pAsm->cf_current_export_clause_ptr->m_Word1.f.valid_pixel_mode = 0x0; + pAsm->cf_current_export_clause_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT; // _DONE + pAsm->cf_current_export_clause_ptr->m_Word1.f.whole_quad_mode = 0x0; + pAsm->cf_current_export_clause_ptr->m_Word1.f.barrier = 0x1; + } if (export_count == 1) { @@ -6605,8 +7859,22 @@ GLboolean Process_Fragment_Exports(r700_AssemblerBase *pR700AsmCode, if(pR700AsmCode->cf_last_export_ptr != NULL) { - pR700AsmCode->cf_last_export_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT_DONE; - pR700AsmCode->cf_last_export_ptr->m_Word1.f.end_of_program = 0x1; + if(8 == pR700AsmCode->unAsic) + { + SETfield(pR700AsmCode->cf_last_export_ptr->m_Word1.val, + 1, + EG_CF_ALLOC_EXPORT_WORD1__EOP_shift, + EG_CF_ALLOC_EXPORT_WORD1__EOP_bit); + SETfield(pR700AsmCode->cf_last_export_ptr->m_Word1.val, + EG_CF_INST_EXPORT_DONE, + EG_CF_WORD1__CF_INST_shift, + EG_CF_WORD1__CF_INST_mask); + } + else + { + pR700AsmCode->cf_last_export_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT_DONE; + pR700AsmCode->cf_last_export_ptr->m_Word1.f.end_of_program = 0x1; + } } return GL_TRUE; @@ -6652,7 +7920,17 @@ GLboolean Process_Vertex_Exports(r700_AssemblerBase *pR700AsmCode, export_count--; } - pR700AsmCode->cf_last_export_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT_DONE; + if(8 == pR700AsmCode->unAsic) + { + SETfield(pR700AsmCode->cf_last_export_ptr->m_Word1.val, + EG_CF_INST_EXPORT_DONE, + EG_CF_WORD1__CF_INST_shift, + EG_CF_WORD1__CF_INST_mask); + } + else + { + pR700AsmCode->cf_last_export_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT_DONE; + } pR700AsmCode->number_of_exports = export_count; @@ -6747,7 +8025,17 @@ GLboolean Process_Vertex_Exports(r700_AssemblerBase *pR700AsmCode, // At least one param should be exported if (export_count) { - pR700AsmCode->cf_last_export_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT_DONE; + if(8 == pR700AsmCode->unAsic) + { + SETfield(pR700AsmCode->cf_last_export_ptr->m_Word1.val, + EG_CF_INST_EXPORT_DONE, + EG_CF_WORD1__CF_INST_shift, + EG_CF_WORD1__CF_INST_mask); + } + else + { + pR700AsmCode->cf_last_export_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT_DONE; + } } else { @@ -6765,7 +8053,17 @@ GLboolean Process_Vertex_Exports(r700_AssemblerBase *pR700AsmCode, pR700AsmCode->cf_last_export_ptr->m_Word1_SWIZ.f.sel_y = SQ_SEL_0; pR700AsmCode->cf_last_export_ptr->m_Word1_SWIZ.f.sel_z = SQ_SEL_0; pR700AsmCode->cf_last_export_ptr->m_Word1_SWIZ.f.sel_w = SQ_SEL_1; - pR700AsmCode->cf_last_export_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT_DONE; + if(8 == pR700AsmCode->unAsic) + { + SETfield(pR700AsmCode->cf_last_export_ptr->m_Word1.val, + EG_CF_INST_EXPORT_DONE, + EG_CF_WORD1__CF_INST_shift, + EG_CF_WORD1__CF_INST_mask); + } + else + { + pR700AsmCode->cf_last_export_ptr->m_Word1.f.cf_inst = SQ_CF_INST_EXPORT_DONE; + } } pR700AsmCode->cf_last_export_ptr->m_Word1.f.end_of_program = 0x1; diff --git a/src/mesa/drivers/dri/r600/r700_assembler.h b/src/mesa/drivers/dri/r600/r700_assembler.h index dbc6cdb190..d357b0e3ec 100644 --- a/src/mesa/drivers/dri/r600/r700_assembler.h +++ b/src/mesa/drivers/dri/r600/r700_assembler.h @@ -108,7 +108,7 @@ typedef enum AddressMode typedef enum SrcRegisterType { SRC_REG_TEMPORARY = 0, - SRC_REG_INPUT = 1, + SRC_REG_GPR = 1, SRC_REG_CONSTANT = 2, SRC_REG_ALT_TEMPORARY = 3, SRC_REC_LITERAL = 4, @@ -464,6 +464,10 @@ typedef struct r700_AssemblerBase GLuint uiCurInst; GLubyte SamplerUnits[MAX_SAMPLERS]; GLboolean bR6xx; + + /* TODO : merge bR6xx */ + GLuint unAsic; + /* helper to decide which type of instruction to assemble */ GLboolean is_tex; /* we inserted helper intructions and need barrier on next TEX ins */ @@ -489,6 +493,9 @@ typedef struct r700_AssemblerBase GLuint shadow_regs[R700_MAX_TEXTURE_UNITS]; + GLboolean bUseMemConstant; + GLuint kcacheUsed; + } r700_AssemblerBase; //Internal use @@ -512,6 +519,8 @@ GLuint GetSurfaceFormat(GLenum eType, GLuint nChannels, GLuint * pClient_size); unsigned int r700GetNumOperands(GLuint opcode, GLuint nIsOp3); +unsigned int EG_GetNumOperands(GLuint opcode, GLuint nIsOp3); + GLboolean IsTex(gl_inst_opcode Opcode); GLboolean IsAlu(gl_inst_opcode Opcode); int check_current_clause(r700_AssemblerBase* pAsm, @@ -535,6 +544,18 @@ GLboolean assemble_vfetch_instruction2(r700_AssemblerBase* pAsm, GLboolean normalize, GLenum format, VTX_FETCH_METHOD * pFetchMethod); + +GLboolean EG_assemble_vfetch_instruction(r700_AssemblerBase* pAsm, + GLuint destination_register, + GLenum type, + GLint size, + GLubyte element, + GLuint _signed, + GLboolean normalize, + GLenum format, + VTX_FETCH_METHOD * pFetchMethod); +//----------------------- + GLboolean cleanup_vfetch_instructions(r700_AssemblerBase* pAsm); GLuint gethelpr(r700_AssemblerBase* pAsm); void resethelpr(r700_AssemblerBase* pAsm); @@ -553,8 +574,10 @@ GLboolean assemble_tex_instruction(r700_AssemblerBase *pAsm, GLboolean normalize void initialize(r700_AssemblerBase *pAsm); GLboolean assemble_alu_src(R700ALUInstruction* alu_instruction_ptr, int source_index, - PVSSRC* pSource, - BITS scalar_channel_index); + PVSSRC* pSource, + BITS scalar_channel_index, + r700_AssemblerBase *pAsm); + GLboolean add_alu_instruction(r700_AssemblerBase* pAsm, R700ALUInstruction* alu_instruction_ptr, GLuint contiguous_slots_needed); @@ -625,6 +648,7 @@ GLboolean assemble_LOGIC_PRED(r700_AssemblerBase *pAsm, BITS opcode); GLboolean assemble_TRIG(r700_AssemblerBase *pAsm, BITS opcode); GLboolean assemble_SLT(r700_AssemblerBase *pAsm); +GLboolean assemble_SSG(r700_AssemblerBase *pAsm); GLboolean assemble_STP(r700_AssemblerBase *pAsm); GLboolean assemble_TEX(r700_AssemblerBase *pAsm); GLboolean assemble_XPD(r700_AssemblerBase *pAsm); @@ -663,6 +687,7 @@ GLboolean callPreSub(r700_AssemblerBase* pAsm, COMPILED_SUB * pCompiledSub, GLshort uOutReg, GLshort uNumValidSrc); +GLboolean EG_add_ps_interp(r700_AssemblerBase* pAsm); //Interface GLboolean AssembleInstr(GLuint uiFirstInst, diff --git a/src/mesa/drivers/dri/r600/r700_chip.c b/src/mesa/drivers/dri/r600/r700_chip.c index bf8063391a..71f1af7562 100644 --- a/src/mesa/drivers/dri/r600/r700_chip.c +++ b/src/mesa/drivers/dri/r600/r700_chip.c @@ -173,7 +173,6 @@ static void r700SetupVTXConstants(GLcontext * ctx, { context_t *context = R700_CONTEXT(ctx); struct radeon_aos * paos = (struct radeon_aos *)pAos; - unsigned int nVBsize; BATCH_LOCALS(&context->radeon); unsigned int uSQ_VTX_CONSTANT_WORD0_0; @@ -194,18 +193,8 @@ static void r700SetupVTXConstants(GLcontext * ctx, else r700SyncSurf(context, paos->bo, RADEON_GEM_DOMAIN_GTT, 0, VC_ACTION_ENA_bit); - if(0 == pStreamDesc->stride) - { - nVBsize = paos->count * pStreamDesc->size * getTypeSize(pStreamDesc->type); - } - else - { - nVBsize = (paos->count - 1) * pStreamDesc->stride - + pStreamDesc->size * getTypeSize(pStreamDesc->type); - } - uSQ_VTX_CONSTANT_WORD0_0 = paos->offset; - uSQ_VTX_CONSTANT_WORD1_0 = nVBsize - 1; + uSQ_VTX_CONSTANT_WORD1_0 = paos->bo->size - paos->offset - 1; SETfield(uSQ_VTX_CONSTANT_WORD2_0, 0, BASE_ADDRESS_HI_shift, BASE_ADDRESS_HI_mask); /* TODO */ SETfield(uSQ_VTX_CONSTANT_WORD2_0, pStreamDesc->stride, SQ_VTX_CONSTANT_WORD2_0__STRIDE_shift, @@ -721,6 +710,7 @@ static void r700SendPSState(GLcontext *ctx, struct radeon_state_atom *atom) context_t *context = R700_CONTEXT(ctx); R700_CHIP_CONTEXT *r700 = R700_CONTEXT_STATES(context); struct radeon_bo * pbo; + struct radeon_bo * pbo_const; BATCH_LOCALS(&context->radeon); radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); @@ -750,6 +740,9 @@ static void r700SendPSState(GLcontext *ctx, struct radeon_state_atom *atom) R600_OUT_BATCH_REGVAL(SQ_LOOP_CONST_0, 0x01000FFF); END_BATCH(); + pbo_const = (struct radeon_bo *)r700GetActiveFpShaderConstBo(GL_CONTEXT(context)); + //TODO : set up shader const + COMMIT_BATCH(); } @@ -759,13 +752,14 @@ static void r700SendVSState(GLcontext *ctx, struct radeon_state_atom *atom) context_t *context = R700_CONTEXT(ctx); R700_CHIP_CONTEXT *r700 = R700_CONTEXT_STATES(context); struct radeon_bo * pbo; + struct radeon_bo * pbo_const; BATCH_LOCALS(&context->radeon); radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__); pbo = (struct radeon_bo *)r700GetActiveVpShaderBo(GL_CONTEXT(context)); if (!pbo) - return; + return; r700SyncSurf(context, pbo, RADEON_GEM_DOMAIN_GTT, 0, SH_ACTION_ENA_bit); @@ -788,6 +782,29 @@ static void r700SendVSState(GLcontext *ctx, struct radeon_state_atom *atom) //R600_OUT_BATCH_REGVAL((SQ_LOOP_CONST_0 + (SQ_LOOP_CONST_vs<2)), 0x0100000F); END_BATCH(); + /* TODO : handle 4 bufs */ + if(GL_TRUE == r700->bShaderUseMemConstant) + { + pbo_const = (struct radeon_bo *)r700GetActiveVpShaderConstBo(GL_CONTEXT(context)); + if(NULL != pbo_const) + { + r700SyncSurf(context, pbo_const, RADEON_GEM_DOMAIN_GTT, 0, SH_ACTION_ENA_bit); /* TODO : Check kc bit. */ + + BEGIN_BATCH_NO_AUTOSTATE(3); + R600_OUT_BATCH_REGVAL(SQ_ALU_CONST_BUFFER_SIZE_VS_0, (r700->vs.num_consts * 4)/16 ); + END_BATCH(); + + BEGIN_BATCH_NO_AUTOSTATE(3 + 2); + R600_OUT_BATCH_REGSEQ(SQ_ALU_CONST_CACHE_VS_0, 1); + R600_OUT_BATCH(r700->vs.SQ_ALU_CONST_CACHE_VS_0.u32All); + R600_OUT_BATCH_RELOC(r700->vs.SQ_ALU_CONST_CACHE_VS_0.u32All, + pbo_const, + r700->vs.SQ_ALU_CONST_CACHE_VS_0.u32All, + RADEON_GEM_DOMAIN_GTT, 0, 0); + END_BATCH(); + } + } + COMMIT_BATCH(); } @@ -1558,45 +1575,55 @@ static void r600_init_query_stateobj(radeonContextPtr radeon, int SZ) void r600InitAtoms(context_t *context) { - radeon_print(RADEON_STATE, RADEON_NORMAL, "%s %p\n", __func__, context); - context->radeon.hw.max_state_size = 10 + 5 + 14; /* start 3d, idle, cb/db flush */ - - /* Setup the atom linked list */ - make_empty_list(&context->radeon.hw.atomlist); - context->radeon.hw.atomlist.name = "atom-list"; - - ALLOC_STATE(sq, always, 34, r700SendSQConfig); - ALLOC_STATE(db, always, 17, r700SendDBState); - ALLOC_STATE(stencil, always, 4, r700SendStencilState); - ALLOC_STATE(db_target, always, 16, r700SendDepthTargetState); - ALLOC_STATE(sc, always, 15, r700SendSCState); - ALLOC_STATE(scissor, always, 22, r700SendScissorState); - ALLOC_STATE(aa, always, 12, r700SendAAState); - ALLOC_STATE(cl, always, 12, r700SendCLState); - ALLOC_STATE(gb, always, 6, r700SendGBState); - ALLOC_STATE(ucp, ucp, (R700_MAX_UCP * 6), r700SendUCPState); - ALLOC_STATE(su, always, 9, r700SendSUState); - ALLOC_STATE(poly, always, 10, r700SendPolyState); - ALLOC_STATE(cb, cb, 18, r700SendCBState); - ALLOC_STATE(clrcmp, always, 6, r700SendCBCLRCMPState); - ALLOC_STATE(cb_target, always, 31, r700SendRenderTargetState); - ALLOC_STATE(blnd, blnd, (6 + (R700_MAX_RENDER_TARGETS * 3)), r700SendCBBlendState); - ALLOC_STATE(blnd_clr, always, 6, r700SendCBBlendColorState); - ALLOC_STATE(sx, always, 9, r700SendSXState); - ALLOC_STATE(vgt, always, 41, r700SendVGTState); - ALLOC_STATE(spi, always, (59 + R700_MAX_SHADER_EXPORTS), r700SendSPIState); - ALLOC_STATE(vpt, always, 16, r700SendViewportState); - ALLOC_STATE(fs, always, 18, r700SendFSState); - ALLOC_STATE(vs, always, 21, r700SendVSState); - ALLOC_STATE(ps, always, 24, r700SendPSState); - ALLOC_STATE(vs_consts, vs_consts, (2 + (R700_MAX_DX9_CONSTS * 4)), r700SendVSConsts); - ALLOC_STATE(ps_consts, ps_consts, (2 + (R700_MAX_DX9_CONSTS * 4)), r700SendPSConsts); - ALLOC_STATE(vtx, vtx, (VERT_ATTRIB_MAX * 18), r700SendVTXState); - ALLOC_STATE(tx, tx, (R700_TEXTURE_NUMBERUNITS * 20), r700SendTexState); - ALLOC_STATE(tx_smplr, tx, (R700_TEXTURE_NUMBERUNITS * 5), r700SendTexSamplerState); - ALLOC_STATE(tx_brdr_clr, tx, (R700_TEXTURE_NUMBERUNITS * 6), r700SendTexBorderColorState); - r600_init_query_stateobj(&context->radeon, 6 * 2); - - context->radeon.hw.is_dirty = GL_TRUE; - context->radeon.hw.all_dirty = GL_TRUE; + R700_CHIP_CONTEXT *r700 = (R700_CHIP_CONTEXT*)(&context->hw); + radeon_print(RADEON_STATE, RADEON_NORMAL, "%s %p\n", __func__, context); + context->radeon.hw.max_state_size = 10 + 5 + 14; /* start 3d, idle, cb/db flush */ + + /* Setup the atom linked list */ + make_empty_list(&context->radeon.hw.atomlist); + context->radeon.hw.atomlist.name = "atom-list"; + + ALLOC_STATE(sq, always, 34, r700SendSQConfig); + ALLOC_STATE(db, always, 17, r700SendDBState); + ALLOC_STATE(stencil, always, 4, r700SendStencilState); + ALLOC_STATE(db_target, always, 16, r700SendDepthTargetState); + ALLOC_STATE(sc, always, 15, r700SendSCState); + ALLOC_STATE(scissor, always, 22, r700SendScissorState); + ALLOC_STATE(aa, always, 12, r700SendAAState); + ALLOC_STATE(cl, always, 12, r700SendCLState); + ALLOC_STATE(gb, always, 6, r700SendGBState); + ALLOC_STATE(ucp, ucp, (R700_MAX_UCP * 6), r700SendUCPState); + ALLOC_STATE(su, always, 9, r700SendSUState); + ALLOC_STATE(poly, always, 10, r700SendPolyState); + ALLOC_STATE(cb, cb, 18, r700SendCBState); + ALLOC_STATE(clrcmp, always, 6, r700SendCBCLRCMPState); + ALLOC_STATE(cb_target, always, 31, r700SendRenderTargetState); + ALLOC_STATE(blnd, blnd, (6 + (R700_MAX_RENDER_TARGETS * 3)), r700SendCBBlendState); + ALLOC_STATE(blnd_clr, always, 6, r700SendCBBlendColorState); + ALLOC_STATE(sx, always, 9, r700SendSXState); + ALLOC_STATE(vgt, always, 41, r700SendVGTState); + ALLOC_STATE(spi, always, (59 + R700_MAX_SHADER_EXPORTS), r700SendSPIState); + ALLOC_STATE(vpt, always, 16, r700SendViewportState); + ALLOC_STATE(fs, always, 18, r700SendFSState); + if(GL_TRUE == r700->bShaderUseMemConstant) + { + ALLOC_STATE(vs, always, 36, r700SendVSState); + ALLOC_STATE(ps, always, 24, r700SendPSState); /* TODO : not imp yet, fix later. */ + } + else + { + ALLOC_STATE(vs, always, 21, r700SendVSState); + ALLOC_STATE(ps, always, 24, r700SendPSState); + ALLOC_STATE(vs_consts, vs_consts, (2 + (R700_MAX_DX9_CONSTS * 4)), r700SendVSConsts); + ALLOC_STATE(ps_consts, ps_consts, (2 + (R700_MAX_DX9_CONSTS * 4)), r700SendPSConsts); + } + + ALLOC_STATE(vtx, vtx, (VERT_ATTRIB_MAX * 18), r700SendVTXState); + ALLOC_STATE(tx, tx, (R700_TEXTURE_NUMBERUNITS * 20), r700SendTexState); + ALLOC_STATE(tx_smplr, tx, (R700_TEXTURE_NUMBERUNITS * 5), r700SendTexSamplerState); + ALLOC_STATE(tx_brdr_clr, tx, (R700_TEXTURE_NUMBERUNITS * 6), r700SendTexBorderColorState); + r600_init_query_stateobj(&context->radeon, 6 * 2); + + context->radeon.hw.is_dirty = GL_TRUE; + context->radeon.hw.all_dirty = GL_TRUE; } diff --git a/src/mesa/drivers/dri/r600/r700_chip.h b/src/mesa/drivers/dri/r600/r700_chip.h index 0b6b72f850..ebf1840a79 100644 --- a/src/mesa/drivers/dri/r600/r700_chip.h +++ b/src/mesa/drivers/dri/r600/r700_chip.h @@ -43,6 +43,8 @@ #define SETbit(x, bit) ( (x) |= (bit) ) #define CLEARbit(x, bit) ( (x) &= ~(bit) ) +#define GETbits(x, shift, mask) ( ((x) & (mask)) >> (shift) ) + #define R700_TEXTURE_NUMBERUNITS 16 #define R700_MAX_RENDER_TARGETS 8 #define R700_MAX_VIEWPORTS 16 @@ -238,6 +240,9 @@ typedef struct _VS_STATE_STRUCT union UINT_FLOAT SQ_PGM_CF_OFFSET_VS ; /* 0xA234 */ GLboolean dirty; int num_consts; + + union UINT_FLOAT SQ_ALU_CONST_CACHE_VS_0; + union UINT_FLOAT consts[R700_MAX_DX9_CONSTS][4]; } VS_STATE_STRUCT; @@ -499,6 +504,8 @@ typedef struct _R700_CHIP_CONTEXT GLboolean bEnablePerspective; + GLboolean bShaderUseMemConstant; + } R700_CHIP_CONTEXT; #endif /* _R700_CHIP_H_ */ diff --git a/src/mesa/drivers/dri/r600/r700_fragprog.c b/src/mesa/drivers/dri/r600/r700_fragprog.c index f9d84b6ed6..6fdd93a330 100644 --- a/src/mesa/drivers/dri/r600/r700_fragprog.c +++ b/src/mesa/drivers/dri/r600/r700_fragprog.c @@ -362,6 +362,9 @@ GLboolean r700TranslateFragmentShader(struct r700_fragment_program *fp, struct gl_fragment_program *mesa_fp, GLcontext *ctx) { + context_t *context = R700_CONTEXT(ctx); + R700_CHIP_CONTEXT *r700 = (R700_CHIP_CONTEXT*)(&context->hw); + GLuint number_of_colors_exported; GLboolean z_enabled = GL_FALSE; GLuint unBit, shadow_unit; @@ -373,6 +376,17 @@ GLboolean r700TranslateFragmentShader(struct r700_fragment_program *fp, //Init_Program Init_r700_AssemblerBase( SPT_FP, &(fp->r700AsmCode), &(fp->r700Shader) ); + if(GL_TRUE == r700->bShaderUseMemConstant) + { + fp->r700AsmCode.bUseMemConstant = GL_TRUE; + } + else + { + fp->r700AsmCode.bUseMemConstant = GL_FALSE; + } + + fp->r700AsmCode.unAsic = 7; + if(mesa_fp->Base.InputsRead & FRAG_BIT_WPOS) { insert_wpos_code(ctx, mesa_fp); @@ -481,6 +495,14 @@ void * r700GetActiveFpShaderBo(GLcontext * ctx) return fp->shaderbo; } +void * r700GetActiveFpShaderConstBo(GLcontext * ctx) +{ + struct r700_fragment_program *fp = (struct r700_fragment_program *) + (ctx->FragmentProgram._Current); + + return fp->constbo0; +} + GLboolean r700SetupFragmentProgram(GLcontext * ctx) { context_t *context = R700_CONTEXT(ctx); @@ -768,6 +790,17 @@ GLboolean r700SetupFragmentProgram(GLcontext * ctx) r700->ps.consts[ui][2].f32All = paramList->ParameterValues[ui][2]; r700->ps.consts[ui][3].f32All = paramList->ParameterValues[ui][3]; } + + /* Load fp constants to gpu */ + if( (GL_TRUE == r700->bShaderUseMemConstant) && (unNumParamData > 0) ) + { + r600EmitShader(ctx, + &(fp->constbo0), + (GLvoid *)&(paramList->ParameterValues[0][0]), + unNumParamData * 4, + "FS Const"); + } + } else r700->ps.num_consts = 0; diff --git a/src/mesa/drivers/dri/r600/r700_fragprog.h b/src/mesa/drivers/dri/r600/r700_fragprog.h index 39c59c9201..aaa6043d5d 100644 --- a/src/mesa/drivers/dri/r600/r700_fragprog.h +++ b/src/mesa/drivers/dri/r600/r700_fragprog.h @@ -43,6 +43,9 @@ struct r700_fragment_program void * shaderbo; + GLuint k0used; + void * constbo0; + GLboolean WritesDepth; GLuint optimization; }; @@ -67,4 +70,6 @@ extern GLboolean r700SetupFragmentProgram(GLcontext * ctx); extern void * r700GetActiveFpShaderBo(GLcontext * ctx); +extern void * r700GetActiveFpShaderConstBo(GLcontext * ctx); + #endif /*_R700_FRAGPROG_H_*/ diff --git a/src/mesa/drivers/dri/r600/r700_oglprog.c b/src/mesa/drivers/dri/r600/r700_oglprog.c index 8351792511..e0c9179004 100644 --- a/src/mesa/drivers/dri/r600/r700_oglprog.c +++ b/src/mesa/drivers/dri/r600/r700_oglprog.c @@ -48,6 +48,12 @@ static void freeVertProgCache(GLcontext *ctx, struct r700_vertex_program_cont *c tmp = vp->next; /* Release DMA region */ r600DeleteShader(ctx, vp->shaderbo); + + if(NULL != vp->constbo0) + { + r600DeleteShader(ctx, vp->constbo0); + } + /* Clean up */ Clean_Up_Assembler(&(vp->r700AsmCode)); Clean_Up_Shader(&(vp->r700Shader)); @@ -79,6 +85,7 @@ static struct gl_program *r700NewProgram(GLcontext * ctx, &vpc->mesa_program, target, id); + break; case GL_FRAGMENT_PROGRAM_NV: case GL_FRAGMENT_PROGRAM_ARB: @@ -92,6 +99,8 @@ static struct gl_program *r700NewProgram(GLcontext * ctx, fp->shaderbo = NULL; + fp->constbo0 = NULL; + break; default: _mesa_problem(ctx, "Bad target in r700NewProgram"); @@ -121,6 +130,11 @@ static void r700DeleteProgram(GLcontext * ctx, struct gl_program *prog) r600DeleteShader(ctx, fp->shaderbo); + if(NULL != fp->constbo0) + { + r600DeleteShader(ctx, fp->constbo0); + } + /* Clean up */ Clean_Up_Assembler(&(fp->r700AsmCode)); Clean_Up_Shader(&(fp->r700Shader)); @@ -145,6 +159,13 @@ r700ProgramStringNotify(GLcontext * ctx, GLenum target, struct gl_program *prog) break; case GL_FRAGMENT_PROGRAM_ARB: r600DeleteShader(ctx, fp->shaderbo); + + if(NULL != fp->constbo0) + { + r600DeleteShader(ctx, fp->constbo0); + fp->constbo0 = NULL; + } + Clean_Up_Assembler(&(fp->r700AsmCode)); Clean_Up_Shader(&(fp->r700Shader)); fp->translated = GL_FALSE; diff --git a/src/mesa/drivers/dri/r600/r700_render.c b/src/mesa/drivers/dri/r600/r700_render.c index c5771f9fd0..f90c69c416 100644 --- a/src/mesa/drivers/dri/r600/r700_render.c +++ b/src/mesa/drivers/dri/r600/r700_render.c @@ -644,6 +644,7 @@ static void r700SetupStreams(GLcontext *ctx, const struct gl_client_array *input #endif ) { + assert(count); r700ConvertAttrib(ctx, count, input[i], &context->stream_desc[index]); } else diff --git a/src/mesa/drivers/dri/r600/r700_state.c b/src/mesa/drivers/dri/r600/r700_state.c index 5ea8918611..925b4ffe6d 100644 --- a/src/mesa/drivers/dri/r600/r700_state.c +++ b/src/mesa/drivers/dri/r600/r700_state.c @@ -1580,7 +1580,16 @@ static void r700InitSQConfig(GLcontext * ctx) CLEARbit(r700->sq_config.SQ_CONFIG.u32All, VC_ENABLE_bit); else SETbit(r700->sq_config.SQ_CONFIG.u32All, VC_ENABLE_bit); - SETbit(r700->sq_config.SQ_CONFIG.u32All, DX9_CONSTS_bit); + + if(GL_TRUE == r700->bShaderUseMemConstant) + { + CLEARbit(r700->sq_config.SQ_CONFIG.u32All, DX9_CONSTS_bit); + } + else + { + SETbit(r700->sq_config.SQ_CONFIG.u32All, DX9_CONSTS_bit); + } + SETbit(r700->sq_config.SQ_CONFIG.u32All, ALU_INST_PREFER_VECTOR_bit); SETfield(r700->sq_config.SQ_CONFIG.u32All, ps_prio, PS_PRIO_shift, PS_PRIO_mask); SETfield(r700->sq_config.SQ_CONFIG.u32All, vs_prio, VS_PRIO_shift, VS_PRIO_mask); @@ -1689,8 +1698,9 @@ void r700InitState(GLcontext * ctx) //------------------- SETbit(r700->PA_SC_MODE_CNTL.u32All, FORCE_EOV_CNTDWN_ENABLE_bit); } - /* Do scale XY and Z by 1/W0. */ - r700->bEnablePerspective = GL_TRUE; + /* Do scale XY and Z by 1/W0. */ + r700->bEnablePerspective = GL_TRUE; + CLEARbit(r700->PA_CL_VTE_CNTL.u32All, VTX_XY_FMT_bit); CLEARbit(r700->PA_CL_VTE_CNTL.u32All, VTX_Z_FMT_bit); SETbit(r700->PA_CL_VTE_CNTL.u32All, VTX_W0_FMT_bit); diff --git a/src/mesa/drivers/dri/r600/r700_vertprog.c b/src/mesa/drivers/dri/r600/r700_vertprog.c index 6a2a09eaf1..7ed4b7d238 100644 --- a/src/mesa/drivers/dri/r600/r700_vertprog.c +++ b/src/mesa/drivers/dri/r600/r700_vertprog.c @@ -305,12 +305,17 @@ struct r700_vertex_program* r700TranslateVertexShader(GLcontext *ctx, struct gl_vertex_program *mesa_vp) { context_t *context = R700_CONTEXT(ctx); + + R700_CHIP_CONTEXT *r700 = (R700_CHIP_CONTEXT*)(&context->hw); + struct r700_vertex_program *vp; unsigned int i; vp = calloc(1, sizeof(*vp)); vp->mesa_program = _mesa_clone_vertex_program(ctx, mesa_vp); + vp->constbo0 = NULL; + if (mesa_vp->IsPositionInvariant) { _mesa_insert_mvp_code(ctx, vp->mesa_program); @@ -331,6 +336,18 @@ struct r700_vertex_program* r700TranslateVertexShader(GLcontext *ctx, //Init_Program Init_r700_AssemblerBase(SPT_VP, &(vp->r700AsmCode), &(vp->r700Shader) ); + + if(GL_TRUE == r700->bShaderUseMemConstant) + { + vp->r700AsmCode.bUseMemConstant = GL_TRUE; + } + else + { + vp->r700AsmCode.bUseMemConstant = GL_FALSE; + } + + vp->r700AsmCode.unAsic = 7; + Map_Vertex_Program(ctx, vp, vp->mesa_program ); if(GL_FALSE == Find_Instruction_Dependencies_vp(vp, vp->mesa_program)) @@ -576,6 +593,17 @@ void * r700GetActiveVpShaderBo(GLcontext * ctx) return NULL; } +void * r700GetActiveVpShaderConstBo(GLcontext * ctx) +{ + context_t *context = R700_CONTEXT(ctx); + struct r700_vertex_program *vp = context->selected_vp;; + + if (vp) + return vp->constbo0; + else + return NULL; +} + GLboolean r700SetupVertexProgram(GLcontext * ctx) { context_t *context = R700_CONTEXT(ctx); @@ -600,6 +628,19 @@ GLboolean r700SetupVertexProgram(GLcontext * ctx) vp->r700Shader.uShaderBinaryDWORDSize, "VS"); + if(GL_TRUE == r700->bShaderUseMemConstant) + { + paramList = vp->mesa_program->Base.Parameters; + if(NULL != paramList) + { + unNumParamData = paramList->NumParameters; + r600AllocShaderConsts(ctx, + &(vp->constbo0), + unNumParamData *4*4, + "VSCON"); + } + } + vp->loaded = GL_TRUE; } @@ -616,7 +657,9 @@ GLboolean r700SetupVertexProgram(GLcontext * ctx) r700->vs.SQ_PGM_RESOURCES_VS.u32All = 0; SETbit(r700->vs.SQ_PGM_RESOURCES_VS.u32All, PGM_RESOURCES__PRIME_CACHE_ON_DRAW_bit); - r700->vs.SQ_PGM_START_VS.u32All = 0; /* set from buffer object. */ + r700->vs.SQ_ALU_CONST_CACHE_VS_0.u32All = 0; /* set from buffer object. */ + + r700->vs.SQ_PGM_START_VS.u32All = 0; SETfield(r700->vs.SQ_PGM_RESOURCES_VS.u32All, vp->r700Shader.nRegs + 1, NUM_GPRS_shift, NUM_GPRS_mask); @@ -687,6 +730,16 @@ GLboolean r700SetupVertexProgram(GLcontext * ctx) r700->vs.consts[ui][3].f32All = paramList->ParameterValues[ui][3]; } } + + /* Load vp constants to gpu */ + if(GL_TRUE == r700->bShaderUseMemConstant) + { + r600EmitShaderConsts(ctx, + vp->constbo0, + 0, + (GLvoid *)&(r700->vs.consts[0][0]), + unNumParamData * 4 * 4); + } } else r700->vs.num_consts = 0; diff --git a/src/mesa/drivers/dri/r600/r700_vertprog.h b/src/mesa/drivers/dri/r600/r700_vertprog.h index 645c9ac84a..9acdc8e350 100644 --- a/src/mesa/drivers/dri/r600/r700_vertprog.h +++ b/src/mesa/drivers/dri/r600/r700_vertprog.h @@ -56,6 +56,9 @@ struct r700_vertex_program void * shaderbo; + GLuint K0used; + void * constbo0; + ArrayDesc aos_desc[VERT_ATTRIB_MAX]; }; @@ -97,6 +100,8 @@ extern GLboolean r700SetupVertexProgram(GLcontext * ctx); extern void * r700GetActiveVpShaderBo(GLcontext * ctx); +extern void * r700GetActiveVpShaderConstBo(GLcontext * ctx); + extern int getTypeSize(GLenum type); #endif /* _R700_VERTPROG_H_ */ diff --git a/src/mesa/drivers/dri/radeon/radeon_chipset.h b/src/mesa/drivers/dri/radeon/radeon_chipset.h index 7d54fabebb..61106fbc43 100644 --- a/src/mesa/drivers/dri/radeon/radeon_chipset.h +++ b/src/mesa/drivers/dri/radeon/radeon_chipset.h @@ -400,6 +400,46 @@ #define PCI_CHIP_RV740_94B5 0x94B5 #define PCI_CHIP_RV740_94B9 0x94B9 +#define PCI_CHIP_CEDAR_68E0 0x68E0 +#define PCI_CHIP_CEDAR_68E1 0x68E1 +#define PCI_CHIP_CEDAR_68E4 0x68E4 +#define PCI_CHIP_CEDAR_68E5 0x68E5 +#define PCI_CHIP_CEDAR_68E8 0x68E8 +#define PCI_CHIP_CEDAR_68E9 0x68E9 +#define PCI_CHIP_CEDAR_68F1 0x68F1 +#define PCI_CHIP_CEDAR_68F8 0x68F8 +#define PCI_CHIP_CEDAR_68F9 0x68F9 +#define PCI_CHIP_CEDAR_68FE 0x68FE + +#define PCI_CHIP_REDWOOD_68C0 0x68C0 +#define PCI_CHIP_REDWOOD_68C1 0x68C1 +#define PCI_CHIP_REDWOOD_68C8 0x68C8 +#define PCI_CHIP_REDWOOD_68C9 0x68C9 +#define PCI_CHIP_REDWOOD_68D8 0x68D8 +#define PCI_CHIP_REDWOOD_68D9 0x68D9 +#define PCI_CHIP_REDWOOD_68DA 0x68DA +#define PCI_CHIP_REDWOOD_68DE 0x68DE + +#define PCI_CHIP_JUNIPER_68A0 0x68A0 +#define PCI_CHIP_JUNIPER_68A1 0x68A1 +#define PCI_CHIP_JUNIPER_68A8 0x68A8 +#define PCI_CHIP_JUNIPER_68A9 0x68A9 +#define PCI_CHIP_JUNIPER_68B0 0x68B0 +#define PCI_CHIP_JUNIPER_68B8 0x68B8 +#define PCI_CHIP_JUNIPER_68B9 0x68B9 +#define PCI_CHIP_JUNIPER_68BE 0x68BE + +#define PCI_CHIP_CYPRESS_6880 0x6880 +#define PCI_CHIP_CYPRESS_6888 0x6888 +#define PCI_CHIP_CYPRESS_6889 0x6889 +#define PCI_CHIP_CYPRESS_688A 0x688A +#define PCI_CHIP_CYPRESS_6898 0x6898 +#define PCI_CHIP_CYPRESS_6899 0x6899 +#define PCI_CHIP_CYPRESS_689E 0x689E + +#define PCI_CHIP_HEMLOCK_689C 0x689C +#define PCI_CHIP_HEMLOCK_689D 0x689D + enum { CHIP_FAMILY_R100, CHIP_FAMILY_RV100, @@ -438,6 +478,11 @@ enum { CHIP_FAMILY_RV730, CHIP_FAMILY_RV710, CHIP_FAMILY_RV740, + CHIP_FAMILY_CEDAR, + CHIP_FAMILY_REDWOOD, + CHIP_FAMILY_JUNIPER, + CHIP_FAMILY_CYPRESS, + CHIP_FAMILY_HEMLOCK, CHIP_FAMILY_LAST }; diff --git a/src/mesa/drivers/dri/radeon/radeon_common_context.c b/src/mesa/drivers/dri/radeon/radeon_common_context.c index 92663bf66d..07f7cba354 100644 --- a/src/mesa/drivers/dri/radeon/radeon_common_context.c +++ b/src/mesa/drivers/dri/radeon/radeon_common_context.c @@ -93,6 +93,11 @@ static const char* get_chip_family_name(int chip_family) case CHIP_FAMILY_RV730: return "RV730"; case CHIP_FAMILY_RV710: return "RV710"; case CHIP_FAMILY_RV740: return "RV740"; + case CHIP_FAMILY_CEDAR: return "CEDAR"; + case CHIP_FAMILY_REDWOOD: return "REDWOOD"; + case CHIP_FAMILY_JUNIPER: return "JUNIPER"; + case CHIP_FAMILY_CYPRESS: return "CYPRESS"; + case CHIP_FAMILY_HEMLOCK: return "HEMLOCK"; default: return "unknown"; } } diff --git a/src/mesa/drivers/dri/radeon/radeon_common_context.h b/src/mesa/drivers/dri/radeon/radeon_common_context.h index f06e5fdf24..024e31f8ec 100644 --- a/src/mesa/drivers/dri/radeon/radeon_common_context.h +++ b/src/mesa/drivers/dri/radeon/radeon_common_context.h @@ -244,6 +244,8 @@ struct radeon_tex_obj { GLuint SQ_TEX_RESOURCE5; GLuint SQ_TEX_RESOURCE6; + GLuint SQ_TEX_RESOURCE7; + GLuint SQ_TEX_SAMPLER0; GLuint SQ_TEX_SAMPLER1; GLuint SQ_TEX_SAMPLER2; diff --git a/src/mesa/drivers/dri/radeon/radeon_fbo.c b/src/mesa/drivers/dri/radeon/radeon_fbo.c index 517485091a..0597d4250d 100644 --- a/src/mesa/drivers/dri/radeon/radeon_fbo.c +++ b/src/mesa/drivers/dri/radeon/radeon_fbo.c @@ -609,6 +609,7 @@ radeon_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) void radeon_fbo_init(struct radeon_context *radeon) { +#if FEATURE_EXT_framebuffer_object radeon->glCtx->Driver.NewFramebuffer = radeon_new_framebuffer; radeon->glCtx->Driver.NewRenderbuffer = radeon_new_renderbuffer; radeon->glCtx->Driver.BindFramebuffer = radeon_bind_framebuffer; @@ -617,7 +618,10 @@ void radeon_fbo_init(struct radeon_context *radeon) radeon->glCtx->Driver.FinishRenderTexture = radeon_finish_render_texture; radeon->glCtx->Driver.ResizeBuffers = radeon_resize_buffers; radeon->glCtx->Driver.ValidateFramebuffer = radeon_validate_framebuffer; +#endif +#if FEATURE_EXT_framebuffer_blit radeon->glCtx->Driver.BlitFramebuffer = _mesa_meta_BlitFramebuffer; +#endif } diff --git a/src/mesa/drivers/dri/radeon/radeon_mipmap_tree.c b/src/mesa/drivers/dri/radeon/radeon_mipmap_tree.c index c6e5f110ea..ddfde3edaf 100644 --- a/src/mesa/drivers/dri/radeon/radeon_mipmap_tree.c +++ b/src/mesa/drivers/dri/radeon/radeon_mipmap_tree.c @@ -199,10 +199,10 @@ static void calculate_miptree_layout_r300(radeonContextPtr rmesa, radeon_mipmap_ for(face = 0; face < mt->faces; face++) compute_tex_image_offset(rmesa, mt, face, level, &curOffset); - /* r600 cube levels seems to be aligned to 8 faces but - * we have separate register for 1'st level offset so add + /* from r700? cube levels seems to be aligned to 8 faces, + * as we have separate register for 1'st level offset add * 2 image alignment after 1'st mip level */ - if(rmesa->radeonScreen->chip_family >= CHIP_FAMILY_R600 && + if(rmesa->radeonScreen->chip_family >= CHIP_FAMILY_RV770 && mt->target == GL_TEXTURE_CUBE_MAP && level >= 1) curOffset += 2 * mt->levels[level].size; } diff --git a/src/mesa/drivers/dri/radeon/radeon_screen.c b/src/mesa/drivers/dri/radeon/radeon_screen.c index fa97a19302..2ea77e56c7 100644 --- a/src/mesa/drivers/dri/radeon/radeon_screen.c +++ b/src/mesa/drivers/dri/radeon/radeon_screen.c @@ -916,6 +916,61 @@ static int radeon_set_screen_flags(radeonScreenPtr screen, int device_id) screen->chip_flags = RADEON_CHIPSET_TCL; break; + case PCI_CHIP_CEDAR_68E0: + case PCI_CHIP_CEDAR_68E1: + case PCI_CHIP_CEDAR_68E4: + case PCI_CHIP_CEDAR_68E5: + case PCI_CHIP_CEDAR_68E8: + case PCI_CHIP_CEDAR_68E9: + case PCI_CHIP_CEDAR_68F1: + case PCI_CHIP_CEDAR_68F8: + case PCI_CHIP_CEDAR_68F9: + case PCI_CHIP_CEDAR_68FE: + screen->chip_family = CHIP_FAMILY_CEDAR; + screen->chip_flags = RADEON_CHIPSET_TCL; + break; + + case PCI_CHIP_REDWOOD_68C0: + case PCI_CHIP_REDWOOD_68C1: + case PCI_CHIP_REDWOOD_68C8: + case PCI_CHIP_REDWOOD_68C9: + case PCI_CHIP_REDWOOD_68D8: + case PCI_CHIP_REDWOOD_68D9: + case PCI_CHIP_REDWOOD_68DA: + case PCI_CHIP_REDWOOD_68DE: + screen->chip_family = CHIP_FAMILY_REDWOOD; + screen->chip_flags = RADEON_CHIPSET_TCL; + break; + + case PCI_CHIP_JUNIPER_68A0: + case PCI_CHIP_JUNIPER_68A1: + case PCI_CHIP_JUNIPER_68A8: + case PCI_CHIP_JUNIPER_68A9: + case PCI_CHIP_JUNIPER_68B0: + case PCI_CHIP_JUNIPER_68B8: + case PCI_CHIP_JUNIPER_68B9: + case PCI_CHIP_JUNIPER_68BE: + screen->chip_family = CHIP_FAMILY_JUNIPER; + screen->chip_flags = RADEON_CHIPSET_TCL; + break; + + case PCI_CHIP_CYPRESS_6880: + case PCI_CHIP_CYPRESS_6888: + case PCI_CHIP_CYPRESS_6889: + case PCI_CHIP_CYPRESS_688A: + case PCI_CHIP_CYPRESS_6898: + case PCI_CHIP_CYPRESS_6899: + case PCI_CHIP_CYPRESS_689E: + screen->chip_family = CHIP_FAMILY_CYPRESS; + screen->chip_flags = RADEON_CHIPSET_TCL; + break; + + case PCI_CHIP_HEMLOCK_689C: + case PCI_CHIP_HEMLOCK_689D: + screen->chip_family = CHIP_FAMILY_HEMLOCK; + screen->chip_flags = RADEON_CHIPSET_TCL; + break; + default: fprintf(stderr, "unknown chip id 0x%x, can't guess.\n", device_id); @@ -1116,7 +1171,7 @@ radeonCreateScreen( __DRIscreen *sPriv ) } } else - { + { screen->fbLocation = (temp & 0xffff) << 16; } } diff --git a/src/mesa/drivers/glslcompiler/Makefile b/src/mesa/drivers/glslcompiler/Makefile deleted file mode 100644 index 6da9f93f59..0000000000 --- a/src/mesa/drivers/glslcompiler/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# Makefile for stand-alone GL-SL compiler - -TOP = ../../../.. - -include $(TOP)/configs/current - - -PROGRAM = glslcompiler - -OBJECTS = \ - glslcompiler.o \ - ../common/driverfuncs.o \ - ../../libmesa.a \ - $(TOP)/src/mapi/glapi/libglapi.a - -INCLUDES = \ - -I$(TOP)/include \ - -I$(TOP)/include/GL/internal \ - -I$(TOP)/src/mapi \ - -I$(TOP)/src/mesa \ - -I$(TOP)/src/mesa/main \ - -I$(TOP)/src/mesa/glapi \ - -I$(TOP)/src/mesa/math \ - -I$(TOP)/src/mesa/transform \ - -I$(TOP)/src/mesa/shader \ - -I$(TOP)/src/mesa/swrast \ - -I$(TOP)/src/mesa/swrast_setup \ - - -default: $(PROGRAM) - $(INSTALL) $(PROGRAM) $(TOP)/bin - - -glslcompiler: $(OBJECTS) - $(CC) $(OBJECTS) $(GL_LIB_DEPS) -o $@ - - -glslcompiler.o: glslcompiler.c - $(CC) -c $(INCLUDES) $(CFLAGS) glslcompiler.c -o $@ - - -clean: - -rm -f *.o *~ $(PROGRAM) diff --git a/src/mesa/drivers/glslcompiler/glslcompiler.c b/src/mesa/drivers/glslcompiler/glslcompiler.c deleted file mode 100644 index 7259bf4c56..0000000000 --- a/src/mesa/drivers/glslcompiler/glslcompiler.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2007 Brian Paul, Tungsten Graphics, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \mainpage - * - * Stand-alone Shading Language compiler. - * Basically, a command-line program which accepts GLSL shaders and emits - * vertex/fragment programs (GPU instructions). - * - * This file is basically just a Mesa device driver but instead of building - * a shared library we build an executable. - * - * We can emit programs in three different formats: - * 1. ARB-style (GL_ARB_vertex/fragment_program) - * 2. NV-style (GL_NV_vertex/fragment_program) - * 3. debug-style (a slightly more sophisticated, internal format) - * - * Note that the ARB and NV program languages can't express all the - * features that might be used by a fragment program (examples being - * uniform and varying vars). So, the ARB/NV programs that are - * emitted aren't always legal programs in those languages. - */ - - -#include "main/imports.h" -#include "main/context.h" -#include "main/extensions.h" -#include "main/framebuffer.h" -#include "main/shaderapi.h" -#include "main/shaderobj.h" -#include "program/prog_print.h" -#include "drivers/common/driverfuncs.h" -#include "tnl/tnl.h" -#include "tnl/t_context.h" -#include "tnl/t_pipeline.h" -#include "swrast/swrast.h" -#include "swrast_setup/swrast_setup.h" -#include "vbo/vbo.h" - - -static const char *Prog = "glslcompiler"; - - -struct options { - GLboolean LineNumbers; - GLboolean Link; - gl_prog_print_mode Mode; - const char *VertFile; - const char *FragFile; - const char *GeoFile; - const char *OutputFile; - GLboolean Params; - struct gl_sl_pragmas Pragmas; -}; - -static struct options Options; - - -/** - * GLSL compiler driver context. (kind of an artificial thing for now) - */ -struct compiler_context -{ - GLcontext MesaContext; - int foo; -}; - -typedef struct compiler_context CompilerContext; - - - -static void -UpdateState(GLcontext *ctx, GLuint new_state) -{ - /* easy - just propogate */ - _swrast_InvalidateState( ctx, new_state ); - _swsetup_InvalidateState( ctx, new_state ); - _tnl_InvalidateState( ctx, new_state ); - _vbo_InvalidateState( ctx, new_state ); -} - - - -static GLboolean -CreateContext(void) -{ - struct dd_function_table ddFuncs; - GLvisual *vis; - GLframebuffer *buf; - GLcontext *ctx; - CompilerContext *cc; - - vis = _mesa_create_visual(GL_FALSE, GL_FALSE, /* RGB */ - 8, 8, 8, 8, /* color */ - 0, 0, /* z, stencil */ - 0, 0, 0, 0, 1); /* accum */ - buf = _mesa_create_framebuffer(vis); - - cc = calloc(1, sizeof(*cc)); - if (!vis || !buf || !cc) { - if (vis) - _mesa_destroy_visual(vis); - if (buf) - _mesa_destroy_framebuffer(buf); - free(cc); - return GL_FALSE; - } - - _mesa_init_driver_functions(&ddFuncs); - ddFuncs.GetString = NULL;/*get_string;*/ - ddFuncs.UpdateState = UpdateState; - ddFuncs.GetBufferSize = NULL; - - ctx = &cc->MesaContext; - _mesa_initialize_context(ctx, vis, NULL, &ddFuncs, cc); - _mesa_enable_sw_extensions(ctx); - - if (!_swrast_CreateContext( ctx ) || - !_vbo_CreateContext( ctx ) || - !_tnl_CreateContext( ctx ) || - !_swsetup_CreateContext( ctx )) { - _mesa_destroy_visual(vis); - _mesa_destroy_framebuffer(buf); - _mesa_free_context_data(ctx); - free(cc); - return GL_FALSE; - } - TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline; - _swsetup_Wakeup( ctx ); - - /* Override the context's default pragma settings */ - ctx->Shader.DefaultPragmas = Options.Pragmas; - - _mesa_make_current(ctx, buf, buf); - - return GL_TRUE; -} - - -static void -LoadAndCompileShader(GLuint shader, const char *text) -{ - GLint stat; - _mesa_ShaderSourceARB(shader, 1, (const GLchar **) &text, NULL); - _mesa_CompileShaderARB(shader); - _mesa_GetShaderiv(shader, GL_COMPILE_STATUS, &stat); - if (!stat) { - GLchar log[1000]; - GLsizei len; - _mesa_GetShaderInfoLog(shader, 1000, &len, log); - fprintf(stderr, "%s: problem compiling shader: %s\n", Prog, log); - exit(1); - } - else { - printf("Shader compiled OK\n"); - } -} - - -/** - * Read a shader from a file. - */ -static void -ReadShader(GLuint shader, const char *filename) -{ - const int max = 100*1000; - int n; - char *buffer = (char*) malloc(max); - FILE *f = fopen(filename, "r"); - if (!f) { - fprintf(stderr, "%s: Unable to open shader file %s\n", Prog, filename); - exit(1); - } - - n = fread(buffer, 1, max, f); - /* - printf("%s: read %d bytes from shader file %s\n", Prog, n, filename); - */ - if (n > 0) { - buffer[n] = 0; - LoadAndCompileShader(shader, buffer); - } - - fclose(f); - free(buffer); -} - - -static void -CheckLink(GLuint v_shader, GLuint f_shader) -{ - GLuint prog; - GLint stat; - - prog = _mesa_CreateProgram(); - - _mesa_AttachShader(prog, v_shader); - _mesa_AttachShader(prog, f_shader); - - _mesa_LinkProgramARB(prog); - _mesa_GetProgramiv(prog, GL_LINK_STATUS, &stat); - if (!stat) { - GLchar log[1000]; - GLsizei len; - _mesa_GetProgramInfoLog(prog, 1000, &len, log); - fprintf(stderr, "Linker error:\n%s\n", log); - } - else { - fprintf(stderr, "Link success!\n"); - } -} - - -static void -PrintShaderInstructions(GLuint shader, FILE *f) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); - struct gl_program *prog = sh->Program; - _mesa_fprint_program_opt(stdout, prog, Options.Mode, Options.LineNumbers); - if (Options.Params) - _mesa_print_program_parameters(ctx, prog); -} - - -static GLuint -CompileShader(const char *filename, GLenum type) -{ - GLuint shader; - - assert(type == GL_FRAGMENT_SHADER || - type == GL_VERTEX_SHADER || - type == GL_GEOMETRY_SHADER_ARB); - - shader = _mesa_CreateShader(type); - ReadShader(shader, filename); - - return shader; -} - - -static void -Usage(void) -{ - printf("Mesa GLSL stand-alone compiler\n"); - printf("Usage:\n"); - printf(" --vs FILE vertex shader input filename\n"); - printf(" --fs FILE fragment shader input filename\n"); - printf(" --gs FILE geometry shader input filename\n"); - printf(" --arb emit ARB-style instructions\n"); - printf(" --nv emit NV-style instructions\n"); - printf(" --link run linker\n"); - printf(" --debug force #pragma debug(on)\n"); - printf(" --nodebug force #pragma debug(off)\n"); - printf(" --opt force #pragma optimize(on)\n"); - printf(" --noopt force #pragma optimize(off)\n"); - printf(" --number, -n emit line numbers (if --arb or --nv)\n"); - printf(" --output, -o FILE output filename\n"); - printf(" --params also emit program parameter info\n"); - printf(" --help display this information\n"); -} - - -static void -ParseOptions(int argc, char *argv[]) -{ - int i; - - Options.LineNumbers = GL_FALSE; - Options.Mode = PROG_PRINT_DEBUG; - Options.VertFile = NULL; - Options.FragFile = NULL; - Options.GeoFile = NULL; - Options.OutputFile = NULL; - Options.Params = GL_FALSE; - Options.Pragmas.IgnoreOptimize = GL_FALSE; - Options.Pragmas.IgnoreDebug = GL_FALSE; - Options.Pragmas.Debug = GL_FALSE; - Options.Pragmas.Optimize = GL_TRUE; - - if (argc == 1) { - Usage(); - exit(0); - } - - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "--vs") == 0) { - Options.VertFile = argv[i + 1]; - i++; - } - else if (strcmp(argv[i], "--fs") == 0) { - Options.FragFile = argv[i + 1]; - i++; - } - else if (strcmp(argv[i], "--gs") == 0) { - Options.GeoFile = argv[i + 1]; - i++; - } - else if (strcmp(argv[i], "--arb") == 0) { - Options.Mode = PROG_PRINT_ARB; - } - else if (strcmp(argv[i], "--nv") == 0) { - Options.Mode = PROG_PRINT_NV; - } - else if (strcmp(argv[i], "--link") == 0) { - Options.Link = GL_TRUE; - } - else if (strcmp(argv[i], "--debug") == 0) { - Options.Pragmas.IgnoreDebug = GL_TRUE; - Options.Pragmas.Debug = GL_TRUE; - } - else if (strcmp(argv[i], "--nodebug") == 0) { - Options.Pragmas.IgnoreDebug = GL_TRUE; - Options.Pragmas.Debug = GL_FALSE; - } - else if (strcmp(argv[i], "--opt") == 0) { - Options.Pragmas.IgnoreOptimize = GL_TRUE; - Options.Pragmas.Optimize = GL_TRUE; - } - else if (strcmp(argv[i], "--noopt") == 0) { - Options.Pragmas.IgnoreOptimize = GL_TRUE; - Options.Pragmas.Optimize = GL_FALSE; - } - else if (strcmp(argv[i], "--number") == 0 || - strcmp(argv[i], "-n") == 0) { - Options.LineNumbers = GL_TRUE; - } - else if (strcmp(argv[i], "--output") == 0 || - strcmp(argv[i], "-o") == 0) { - Options.OutputFile = argv[i + 1]; - i++; - } - else if (strcmp(argv[i], "--params") == 0) { - Options.Params = GL_TRUE; - } - else if (strcmp(argv[i], "--help") == 0) { - Usage(); - exit(0); - } - else { - printf("Unknown option: %s\n", argv[i]); - Usage(); - exit(1); - } - } - - if (Options.Mode == PROG_PRINT_DEBUG) { - /* always print line numbers when emitting debug-style output */ - Options.LineNumbers = GL_TRUE; - } -} - - -int -main(int argc, char *argv[]) -{ - GLuint v_shader = 0, f_shader = 0, g_shader = 0; - - ParseOptions(argc, argv); - - if (!CreateContext()) { - fprintf(stderr, "%s: Failed to create compiler context\n", Prog); - exit(1); - } - - if (Options.VertFile) { - v_shader = CompileShader(Options.VertFile, GL_VERTEX_SHADER); - } - - if (Options.FragFile) { - f_shader = CompileShader(Options.FragFile, GL_FRAGMENT_SHADER); - } - - if (Options.GeoFile) { - g_shader = CompileShader(Options.GeoFile, GL_GEOMETRY_SHADER_ARB); - } - - - if (v_shader || f_shader || g_shader) { - if (Options.OutputFile) { - FILE *f; - fclose(stdout); - /*stdout =*/ f = freopen(Options.OutputFile, "w", stdout); - if (!f) { - fprintf(stderr, "freopen error\n"); - } - } - if (stdout && v_shader) { - PrintShaderInstructions(v_shader, stdout); - } - if (stdout && f_shader) { - PrintShaderInstructions(f_shader, stdout); - } - if (stdout && g_shader) { - PrintShaderInstructions(g_shader, stdout); - } - if (Options.OutputFile) { - fclose(stdout); - } - } - - if (Options.Link) { - if (!v_shader || !f_shader) { - fprintf(stderr, - "--link option requires both a vertex and fragment shader.\n"); - exit(1); - } - - CheckLink(v_shader, f_shader); - } - - return 0; -} diff --git a/src/mesa/drivers/osmesa/Makefile b/src/mesa/drivers/osmesa/Makefile index c6b4a04085..39ab09af80 100644 --- a/src/mesa/drivers/osmesa/Makefile +++ b/src/mesa/drivers/osmesa/Makefile @@ -23,8 +23,7 @@ INCLUDE_DIRS = \ CORE_MESA = \ $(TOP)/src/mesa/libmesa.a \ $(TOP)/src/mapi/glapi/libglapi.a \ - $(TOP)/src/glsl/cl/libglslcl.a \ - $(TOP)/src/glsl/pp/libglslpp.a + $(TOP)/src/glsl/libglsl.a .c.o: $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ @@ -37,9 +36,9 @@ default: $(TOP)/$(LIB_DIR)/$(OSMESA_LIB_NAME) # sources. We can also build libOSMesa16/libOSMesa32 by setting # -DCHAN_BITS=16/32. $(TOP)/$(LIB_DIR)/$(OSMESA_LIB_NAME): $(OBJECTS) $(CORE_MESA) - $(MKLIB) -o $(OSMESA_LIB) -linker '$(CC)' -ldflags '$(LDFLAGS)' \ + $(MKLIB) -o $(OSMESA_LIB) -linker '$(CXX)' -ldflags '$(LDFLAGS)' \ -major $(MESA_MAJOR) -minor $(MESA_MINOR) -patch $(MESA_TINY) \ - -install $(TOP)/$(LIB_DIR) $(MKLIB_OPTIONS) \ + -install $(TOP)/$(LIB_DIR) -cplusplus $(MKLIB_OPTIONS) \ -id $(INSTALL_LIB_DIR)/lib$(OSMESA_LIB).$(MESA_MAJOR).dylib \ $(OSMESA_LIB_DEPS) $(OBJECTS) $(CORE_MESA) diff --git a/src/mesa/drivers/x11/Makefile b/src/mesa/drivers/x11/Makefile index b5b0c1f11a..f759da0a97 100644 --- a/src/mesa/drivers/x11/Makefile +++ b/src/mesa/drivers/x11/Makefile @@ -57,9 +57,10 @@ default: $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME): $(OBJECTS) $(CORE_MESA) - @ $(MKLIB) -o $(GL_LIB) -linker '$(CC)' -ldflags '$(LDFLAGS)' \ + @ $(MKLIB) -o $(GL_LIB) -linker '$(CXX)' -ldflags '$(LDFLAGS)' \ -major $(GL_MAJOR) -minor $(GL_MINOR) -patch $(GL_TINY) \ - -install $(TOP)/$(LIB_DIR) $(MKLIB_OPTIONS) \ + -install $(TOP)/$(LIB_DIR) \ + -cplusplus $(MKLIB_OPTIONS) \ -id $(INSTALL_LIB_DIR)/lib$(GL_LIB).$(GL_MAJOR).dylib \ $(GL_LIB_DEPS) $(OBJECTS) $(CORE_MESA) diff --git a/src/mesa/main/accum.h b/src/mesa/main/accum.h index 63740f07ed..c2b74b23cb 100644 --- a/src/mesa/main/accum.h +++ b/src/mesa/main/accum.h @@ -55,6 +55,8 @@ _mesa_init_accum_dispatch(struct _glapi_table *disp); #else /* FEATURE_accum */ +#include "main/compiler.h" + #define _MESA_INIT_ACCUM_FUNCTIONS(driver, impl) do { } while (0) static INLINE void diff --git a/src/mesa/main/attrib.h b/src/mesa/main/attrib.h index 6b48a17663..83b28a65b7 100644 --- a/src/mesa/main/attrib.h +++ b/src/mesa/main/attrib.h @@ -48,6 +48,8 @@ _mesa_init_attrib_dispatch(struct _glapi_table *disp); #else /* FEATURE_attrib_stack */ +#include "main/compiler.h" + static INLINE void _mesa_PushClientAttrib( GLbitfield mask ) { diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c index 4e232b5731..4797f29b4d 100644 --- a/src/mesa/main/bufferobj.c +++ b/src/mesa/main/bufferobj.c @@ -590,7 +590,7 @@ bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer) bindTarget = get_buffer_target(ctx, target); if (!bindTarget) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)"); + _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target); return; } @@ -1553,27 +1553,27 @@ _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, if (readOffset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(readOffset = %d)", readOffset); + "glCopyBuffserSubData(readOffset = %d)", (int) readOffset); return; } if (writeOffset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(writeOffset = %d)", writeOffset); + "glCopyBuffserSubData(writeOffset = %d)", (int) writeOffset); return; } if (readOffset + size > src->Size) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyBuffserSubData(readOffset + size = %d)", - readOffset, size); + (int) (readOffset + size)); return; } if (writeOffset + size > dst->Size) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyBuffserSubData(writeOffset + size = %d)", - writeOffset, size); + (int) (writeOffset + size)); return; } @@ -1617,13 +1617,13 @@ _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, if (offset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset = %ld)", offset); + "glMapBufferRange(offset = %ld)", (long)offset); return NULL; } if (length < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(length = %ld)", length); + "glMapBufferRange(length = %ld)", (long)length); return NULL; } @@ -1708,13 +1708,13 @@ _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) if (offset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset = %ld)", offset); + "glMapBufferRange(offset = %ld)", (long)offset); return; } if (length < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(length = %ld)", length); + "glMapBufferRange(length = %ld)", (long)length); return; } @@ -1746,8 +1746,8 @@ _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) if (offset + length > bufObj->Length) { _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset %ld + length %ld > mapped length %ld)", - offset, length, bufObj->Length); + "glMapBufferRange(offset %ld + length %ld > mapped length %ld)", + (long)offset, (long)length, (long)bufObj->Length); return; } diff --git a/src/mesa/main/colortab.h b/src/mesa/main/colortab.h index 652fb58246..744f092d93 100644 --- a/src/mesa/main/colortab.h +++ b/src/mesa/main/colortab.h @@ -53,6 +53,8 @@ _mesa_init_colortable_dispatch(struct _glapi_table *disp); #else /* FEATURE_colortable */ +#include "main/compiler.h" + #define _MESA_INIT_COLORTABLE_FUNCTIONS(driver, impl) do { } while (0) static INLINE void GLAPIENTRY diff --git a/src/mesa/main/compiler.h b/src/mesa/main/compiler.h index e0507ccf86..ded69c3106 100644 --- a/src/mesa/main/compiler.h +++ b/src/mesa/main/compiler.h @@ -316,6 +316,11 @@ static INLINE GLuint CPU_TO_LE32(GLuint x) #endif #endif +#if (__GNUC__ >= 3) +#define PRINTFLIKE(f, a) __attribute__ ((format(__printf__, f, a))) +#else +#define PRINTFLIKE(f, a) +#endif #ifndef NULL #define NULL 0 diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index b01fed1781..8e34ec4124 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -140,6 +140,10 @@ #include "sparc/sparc.h" #endif +#include "glsl_parser_extras.h" + + + #ifndef MESA_VERBOSE int MESA_VERBOSE = 0; #endif @@ -339,16 +343,16 @@ _mesa_destroy_visual( GLvisual *vis ) static void dummy_enum_func(void) { - gl_buffer_index bi; - gl_colortable_index ci; - gl_face_index fi; - gl_frag_attrib fa; - gl_frag_result fr; - gl_texture_index ti; - gl_vert_attrib va; - gl_vert_result vr; - gl_geom_attrib ga; - gl_geom_result gr; + gl_buffer_index bi = BUFFER_FRONT_LEFT; + gl_colortable_index ci = COLORTABLE_PRECONVOLUTION; + gl_face_index fi = FACE_POS_X; + gl_frag_attrib fa = FRAG_ATTRIB_WPOS; + gl_frag_result fr = FRAG_RESULT_DEPTH; + gl_texture_index ti = TEXTURE_2D_ARRAY_INDEX; + gl_vert_attrib va = VERT_ATTRIB_POS; + gl_vert_result vr = VERT_RESULT_HPOS; + gl_geom_attrib ga = GEOM_ATTRIB_POSITION; + gl_geom_result gr = GEOM_RESULT_POS; (void) bi; (void) ci; @@ -434,6 +438,11 @@ one_time_init( GLcontext *ctx ) } _glthread_UNLOCK_MUTEX(OneTimeLock); + /* Hopefully atexit() is widely available. If not, we may need some + * #ifdef tests here. + */ + atexit(_mesa_destroy_shader_compiler); + dummy_enum_func(); } @@ -1695,7 +1704,7 @@ _mesa_valid_to_render(GLcontext *ctx, const char *where) /* using shaders */ if (!ctx->Shader.CurrentProgram->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(shader not linked), where"); + "%s(shader not linked)", where); return GL_FALSE; } #if 0 /* not normally enabled */ diff --git a/src/mesa/main/convolve.h b/src/mesa/main/convolve.h index 59492bc7c5..d1401885df 100644 --- a/src/mesa/main/convolve.h +++ b/src/mesa/main/convolve.h @@ -70,6 +70,8 @@ _mesa_init_convolve_dispatch(struct _glapi_table *disp); #else /* FEATURE_convolve */ +#include "main/compiler.h" + #define _MESA_INIT_CONVOLVE_FUNCTIONS(driver, impl) do { } while (0) static INLINE void GLAPIENTRY diff --git a/src/mesa/main/core.h b/src/mesa/main/core.h new file mode 100644 index 0000000000..ea6e6bf118 --- /dev/null +++ b/src/mesa/main/core.h @@ -0,0 +1,66 @@ +/* + * Mesa 3-D graphics library + * Version: 7.9 + * + * Copyright (C) 2010 LunarG Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Chia-I Wu <olv@lunarg.com> + */ + + +/** + * \file core.h + * The public header of core mesa. + * + * This file is the (only) public header of core mesa. It is supposed to be + * used by GLX, WGL, and GLSL. It is important that headers directly or + * indirectly included here do not perform feature tests (#if FEATURE_xxx). + */ + + +#ifndef CORE_H +#define CORE_H + + +#include "main/glheader.h" +#include "main/compiler.h" +#include "main/imports.h" +#include "main/macros.h" + +#include "main/version.h" /* for MESA_VERSION_STRING */ +#include "main/context.h" /* for _mesa_share_state */ +#include "main/mtypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* for GLSL */ +#include "program/prog_parameter.h" +#include "program/prog_uniform.h" + +#ifdef __cplusplus +} +#endif + + +#endif /* CORE_H */ diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 825073ca88..8a20a66363 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -36,7 +36,7 @@ struct gl_pixelstore_attrib; struct gl_display_list; -#if FEATURE_ARB_vertex_buffer_object +/* GL_ARB_vertex_buffer_object */ /* Modifies GL_MAP_UNSYNCHRONIZED_BIT to allow driver to fail (return * NULL) if buffer is unavailable for immediate mapping. * @@ -49,7 +49,6 @@ struct gl_display_list; * respect the contents of already referenced data. */ #define MESA_MAP_NOWAIT_BIT 0x0040 -#endif /** @@ -595,6 +594,27 @@ struct dd_function_table { /*@}*/ + /** + * \name GLSL shader/program functions. + */ + /*@{*/ + /** + * Called when a shader is compiled. + * + * Note that not all shader objects get ShaderCompile called on + * them. Notably, the shaders containing builtin functions do not + * have CompileShader() called, so if lowering passes are done they + * need to also be performed in LinkShader(). + */ + GLboolean (*CompileShader)(GLcontext *ctx, struct gl_shader *shader); + /** + * Called when a shader program is linked. + * + * This gives drivers an opportunity to clone the IR and make their + * own transformations on it for the purposes of code generation. + */ + GLboolean (*LinkShader)(GLcontext *ctx, struct gl_shader_program *shader); + /*@}*/ /** * \name State-changing functions. @@ -709,7 +729,6 @@ struct dd_function_table { /** * \name Vertex/pixel buffer object functions */ -#if FEATURE_ARB_vertex_buffer_object /*@{*/ void (*BindBuffer)( GLcontext *ctx, GLenum target, struct gl_buffer_object *obj ); @@ -753,12 +772,10 @@ struct dd_function_table { GLboolean (*UnmapBuffer)( GLcontext *ctx, GLenum target, struct gl_buffer_object *obj ); /*@}*/ -#endif /** * \name Functions for GL_APPLE_object_purgeable */ -#if FEATURE_APPLE_object_purgeable /*@{*/ /* variations on ObjectPurgeable */ GLenum (*BufferObjectPurgeable)( GLcontext *ctx, struct gl_buffer_object *obj, GLenum option ); @@ -770,12 +787,10 @@ struct dd_function_table { GLenum (*RenderObjectUnpurgeable)( GLcontext *ctx, struct gl_renderbuffer *obj, GLenum option ); GLenum (*TextureObjectUnpurgeable)( GLcontext *ctx, struct gl_texture_object *obj, GLenum option ); /*@}*/ -#endif /** - * \name Functions for GL_EXT_framebuffer_object + * \name Functions for GL_EXT_framebuffer_{object,blit}. */ -#if FEATURE_EXT_framebuffer_object /*@{*/ struct gl_framebuffer * (*NewFramebuffer)(GLcontext *ctx, GLuint name); struct gl_renderbuffer * (*NewRenderbuffer)(GLcontext *ctx, GLuint name); @@ -794,13 +809,10 @@ struct dd_function_table { void (*ValidateFramebuffer)(GLcontext *ctx, struct gl_framebuffer *fb); /*@}*/ -#endif -#if FEATURE_EXT_framebuffer_blit void (*BlitFramebuffer)(GLcontext *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif /** * \name Query objects @@ -955,7 +967,6 @@ struct dd_function_table { void (*EndCallList)( GLcontext *ctx ); -#if FEATURE_ARB_sync /** * \name GL_ARB_sync interfaces */ @@ -969,14 +980,12 @@ struct dd_function_table { void (*ServerWaitSync)(GLcontext *, struct gl_sync_object *, GLbitfield, GLuint64); /*@}*/ -#endif /** GL_NV_conditional_render */ void (*BeginConditionalRender)(GLcontext *ctx, struct gl_query_object *q, GLenum mode); void (*EndConditionalRender)(GLcontext *ctx, struct gl_query_object *q); -#if FEATURE_OES_draw_texture /** * \name GL_OES_draw_texture interface */ @@ -984,9 +993,10 @@ struct dd_function_table { void (*DrawTex)(GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height); /*@}*/ -#endif -#if FEATURE_OES_EGL_image + /** + * \name GL_OES_EGL_image interface + */ void (*EGLImageTargetTexture2D)(GLcontext *ctx, GLenum target, struct gl_texture_object *texObj, struct gl_texture_image *texImage, @@ -994,9 +1004,10 @@ struct dd_function_table { void (*EGLImageTargetRenderbufferStorage)(GLcontext *ctx, struct gl_renderbuffer *rb, void *image_handle); -#endif -#if FEATURE_EXT_transform_feedback + /** + * \name GL_EXT_transform_feedback interface + */ struct gl_transform_feedback_object * (*NewTransformFeedback)(GLcontext *ctx, GLuint name); void (*DeleteTransformFeedback)(GLcontext *ctx, @@ -1011,7 +1022,6 @@ struct dd_function_table { struct gl_transform_feedback_object *obj); void (*DrawTransformFeedback)(GLcontext *ctx, GLenum mode, struct gl_transform_feedback_object *obj); -#endif }; @@ -1094,7 +1104,7 @@ typedef struct { void (GLAPIENTRYP VertexAttrib3fvNV)( GLuint index, const GLfloat *v ); void (GLAPIENTRYP VertexAttrib4fNV)( GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w ); void (GLAPIENTRYP VertexAttrib4fvNV)( GLuint index, const GLfloat *v ); -#if FEATURE_ARB_vertex_program + /* GL_ARB_vertex_program */ void (GLAPIENTRYP VertexAttrib1fARB)( GLuint index, GLfloat x ); void (GLAPIENTRYP VertexAttrib1fvARB)( GLuint index, const GLfloat *v ); void (GLAPIENTRYP VertexAttrib2fARB)( GLuint index, GLfloat x, GLfloat y ); @@ -1103,7 +1113,6 @@ typedef struct { void (GLAPIENTRYP VertexAttrib3fvARB)( GLuint index, const GLfloat *v ); void (GLAPIENTRYP VertexAttrib4fARB)( GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w ); void (GLAPIENTRYP VertexAttrib4fvARB)( GLuint index, const GLfloat *v ); -#endif /*@}*/ void (GLAPIENTRYP Rectf)( GLfloat, GLfloat, GLfloat, GLfloat ); diff --git a/src/mesa/main/depthstencil.c b/src/mesa/main/depthstencil.c index 885e718a76..dbaa841645 100644 --- a/src/mesa/main/depthstencil.c +++ b/src/mesa/main/depthstencil.c @@ -359,7 +359,7 @@ _mesa_new_z24_renderbuffer_wrapper(GLcontext *ctx, dsrb->Format == MESA_FORMAT_X8_Z24); ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); - z24rb = _mesa_new_renderbuffer(ctx, 0); + z24rb = ctx->Driver.NewRenderbuffer(ctx, 0); if (!z24rb) return NULL; @@ -645,7 +645,7 @@ _mesa_new_s8_renderbuffer_wrapper(GLcontext *ctx, struct gl_renderbuffer *dsrb) dsrb->Format == MESA_FORMAT_S8_Z24); ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); - s8rb = _mesa_new_renderbuffer(ctx, 0); + s8rb = ctx->Driver.NewRenderbuffer(ctx, 0); if (!s8rb) return NULL; diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c index 727414d529..5042e14a54 100644 --- a/src/mesa/main/dlist.c +++ b/src/mesa/main/dlist.c @@ -6070,8 +6070,15 @@ exec_GetAttribLocationARB(GLuint program, const GLchar *name) FLUSH_VERTICES(ctx, 0); return CALL_GetAttribLocationARB(ctx->Exec, (program, name)); } -/* XXX more shader functions needed here */ +static GLint GLAPIENTRY +exec_GetUniformLocationARB(GLuint program, const GLchar *name) +{ + GET_CURRENT_CONTEXT(ctx); + FLUSH_VERTICES(ctx, 0); + return CALL_GetUniformLocationARB(ctx->Exec, (program, name)); +} +/* XXX more shader functions needed here */ #if FEATURE_EXT_framebuffer_blit @@ -9491,6 +9498,7 @@ _mesa_create_save_table(void) /* ARB 30/31/32. GL_ARB_shader_objects, GL_ARB_vertex/fragment_shader */ SET_BindAttribLocationARB(table, exec_BindAttribLocationARB); SET_GetAttribLocationARB(table, exec_GetAttribLocationARB); + SET_GetUniformLocationARB(table, exec_GetUniformLocationARB); /* XXX additional functions need to be implemented here! */ /* 299. GL_EXT_blend_equation_separate */ diff --git a/src/mesa/main/dlist.h b/src/mesa/main/dlist.h index f8255facc5..d3f5c5cb4e 100644 --- a/src/mesa/main/dlist.h +++ b/src/mesa/main/dlist.h @@ -81,6 +81,8 @@ extern void _mesa_init_dlist_dispatch(struct _glapi_table *disp); #else /* FEATURE_dlist */ +#include "main/compiler.h" + #define _MESA_INIT_DLIST_FUNCTIONS(driver, impl) do { } while (0) #define _MESA_INIT_DLIST_VTXFMT(vfmt, impl) do { } while (0) diff --git a/src/mesa/main/es_generator.py b/src/mesa/main/es_generator.py index 9a8f5a6f5e..ecb34bb5cd 100644 --- a/src/mesa/main/es_generator.py +++ b/src/mesa/main/es_generator.py @@ -215,6 +215,10 @@ extern void _mesa_error(void *ctx, GLenum error, const char *fmtString, ... ); #ifdef IN_DRI_DRIVER #define _GLAPI_USE_REMAP_TABLE #endif +/* glapi uses GLAPIENTRY while GLES headers define GL_APIENTRY */ +#ifndef GLAPIENTRY +#define GLAPIENTRY GL_APIENTRY +#endif #include "%sapi/glapi/glapitable.h" #include "%sapi/glapi/glapioffsets.h" #include "%sapi/glapi/glapidispatch.h" @@ -603,13 +607,15 @@ for funcName in keys: # are complete; remove the extra ", " at the front of each. passthroughDeclarationString = passthroughDeclarationString[2:] passthroughCallString = passthroughCallString[2:] + if not passthroughDeclarationString: + passthroughDeclarationString = "void" # The Mesa functions are scattered across all the Mesa # header files. The easiest way to manage declarations # is to create them ourselves. if funcName in allSpecials: print "/* this function is special and is defined elsewhere */" - print "extern %s GLAPIENTRY %s(%s);" % (returnType, passthroughFuncName, passthroughDeclarationString) + print "extern %s GL_APIENTRY %s(%s);" % (returnType, passthroughFuncName, passthroughDeclarationString) # A function may be a core function (i.e. it exists in # the core specification), a core addition (extension @@ -662,7 +668,7 @@ for funcName in keys: print continue - print "static %s %s(%s)" % (returnType, fullFuncName, declarationString) + print "static %s GL_APIENTRY %s(%s)" % (returnType, fullFuncName, declarationString) print "{" # Start printing our code pieces. Start with any local diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c index 19a1eebe6e..c9862ca29e 100644 --- a/src/mesa/main/extensions.c +++ b/src/mesa/main/extensions.c @@ -969,7 +969,7 @@ _mesa_get_extension_count(GLcontext *ctx) if (0) _mesa_debug(ctx, "%u of %d extensions enabled\n", ctx->Extensions.Count, - Elements(default_extensions)); + (int) Elements(default_extensions)); return ctx->Extensions.Count; } diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 9a84e5a79c..f80dd85993 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -93,6 +93,8 @@ delete_dummy_framebuffer(struct gl_framebuffer *fb) void _mesa_init_fbobjects(GLcontext *ctx) { + _glthread_INIT_MUTEX(DummyFramebuffer.Mutex); + _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex); DummyFramebuffer.Delete = delete_dummy_framebuffer; DummyRenderbuffer.Delete = delete_dummy_renderbuffer; } diff --git a/src/mesa/main/feedback.h b/src/mesa/main/feedback.h index 3e8283ed23..0762930044 100644 --- a/src/mesa/main/feedback.h +++ b/src/mesa/main/feedback.h @@ -63,6 +63,8 @@ _mesa_init_feedback_dispatch(struct _glapi_table *disp); #else /* FEATURE_feedback */ +#include "main/compiler.h" + #define _MESA_INIT_FEEDBACK_FUNCTIONS(driver, impl) do { } while (0) static INLINE void diff --git a/src/mesa/main/formats.c b/src/mesa/main/formats.c index 90449cc04f..112d7a0088 100644 --- a/src/mesa/main/formats.c +++ b/src/mesa/main/formats.c @@ -940,6 +940,18 @@ _mesa_is_format_compressed(gl_format format) /** + * Determine if the given format represents a packed depth/stencil buffer. + */ +GLboolean +_mesa_is_format_packed_depth_stencil(gl_format format) +{ + const struct gl_format_info *info = _mesa_get_format_info(format); + + return info->BaseFormat == GL_DEPTH_STENCIL; +} + + +/** * Return color encoding for given format. * \return GL_LINEAR or GL_SRGB */ diff --git a/src/mesa/main/formats.h b/src/mesa/main/formats.h index ad176caaa0..e9467f486b 100644 --- a/src/mesa/main/formats.h +++ b/src/mesa/main/formats.h @@ -190,6 +190,9 @@ _mesa_get_format_block_size(gl_format format, GLuint *bw, GLuint *bh); extern GLboolean _mesa_is_format_compressed(gl_format format); +extern GLboolean +_mesa_is_format_packed_depth_stencil(gl_format format); + extern GLenum _mesa_get_format_color_encoding(gl_format format); diff --git a/src/mesa/main/framebuffer.c b/src/mesa/main/framebuffer.c index e0aac26f62..a98c09cfbf 100644 --- a/src/mesa/main/framebuffer.c +++ b/src/mesa/main/framebuffer.c @@ -611,7 +611,7 @@ _mesa_update_depth_buffer(GLcontext *ctx, depthRb = fb->Attachment[attIndex].Renderbuffer; - if (depthRb && depthRb->_BaseFormat == GL_DEPTH_STENCIL) { + if (depthRb && _mesa_is_format_packed_depth_stencil(depthRb->Format)) { /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */ if (!fb->_DepthBuffer || fb->_DepthBuffer->Wrapped != depthRb @@ -652,7 +652,7 @@ _mesa_update_stencil_buffer(GLcontext *ctx, stencilRb = fb->Attachment[attIndex].Renderbuffer; - if (stencilRb && stencilRb->_BaseFormat == GL_DEPTH_STENCIL) { + if (stencilRb && _mesa_is_format_packed_depth_stencil(stencilRb->Format)) { /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */ if (!fb->_StencilBuffer || fb->_StencilBuffer->Wrapped != stencilRb diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c index 632dadd1a5..a3cb5ec168 100644 --- a/src/mesa/main/get.c +++ b/src/mesa/main/get.c @@ -1661,16 +1661,22 @@ check_extra(GLcontext *ctx, const char *func, const struct value_desc *d) for (e = d->extra; *e != EXTRA_END; e++) switch (*e) { case EXTRA_VERSION_30: - if (version < 30) - return GL_FALSE; + if (version >= 30) { + total++; + enabled++; + } break; case EXTRA_VERSION_31: - if (version < 31) - return GL_FALSE; + if (version >= 31) { + total++; + enabled++; + } break; case EXTRA_VERSION_32: - if (version < 32) - return GL_FALSE; + if (version >= 32) { + total++; + enabled++; + } break; case EXTRA_NEW_BUFFERS: if (ctx->NewState & _NEW_BUFFERS) diff --git a/src/mesa/main/getstring.c b/src/mesa/main/getstring.c index 7961ad7e7d..5e4fcd599c 100644 --- a/src/mesa/main/getstring.c +++ b/src/mesa/main/getstring.c @@ -31,7 +31,7 @@ #include "extensions.h" static const GLubyte * -shading_laguage_version(GLcontext *ctx) +shading_language_version(GLcontext *ctx) { switch (ctx->API) { #if FEATURE_ARB_shading_language_100 @@ -98,7 +98,7 @@ _mesa_GetString( GLenum name ) return (const GLubyte *) ctx->Extensions.String; #if FEATURE_ARB_shading_language_100 || FEATURE_ES2 case GL_SHADING_LANGUAGE_VERSION: - return shading_laguage_version(ctx); + return shading_language_version(ctx); #endif #if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program || \ FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program diff --git a/src/mesa/main/imports.h b/src/mesa/main/imports.h index 9c2ffd66d6..751f206501 100644 --- a/src/mesa/main/imports.h +++ b/src/mesa/main/imports.h @@ -116,6 +116,42 @@ typedef union { GLfloat f; GLint i; } fi_type; #endif +/** + * \name Work-arounds for platforms that lack C99 math functions + */ +/*@{*/ +#if (!defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE < 600)) && !defined(_ISOC99_SOURCE) \ + && (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)) \ + && (!defined(_MSC_VER) || (_MSC_VER < 1400)) +#define acosf(f) ((float) acos(f)) +#define asinf(f) ((float) asin(f)) +#define atan2f(x,y) ((float) atan2(x,y)) +#define atanf(f) ((float) atan(f)) +#define cielf(f) ((float) ciel(f)) +#define cosf(f) ((float) cos(f)) +#define coshf(f) ((float) cosh(f)) +#define expf(f) ((float) exp(f)) +#define exp2f(f) ((float) exp2(f)) +#define floorf(f) ((float) floor(f)) +#define logf(f) ((float) log(f)) +#define log2f(f) ((float) log2(f)) +#define powf(x,y) ((float) pow(x,y)) +#define sinf(f) ((float) sin(f)) +#define sinhf(f) ((float) sinh(f)) +#define sqrtf(f) ((float) sqrt(f)) +#define tanf(f) ((float) tan(f)) +#define tanhf(f) ((float) tanh(f)) +#endif + +#if defined(_MSC_VER) +static INLINE float truncf(float x) { return x < 0.0f ? ceilf(x) : floorf(x); } +static INLINE float exp2f(float x) { return powf(2.0f, x); } +static INLINE float log2f(float x) { return logf(x) * 1.442695041f; } +static INLINE int isblank(int ch) { return ch == ' ' || ch == '\t'; } +#define strtoll(p, e, b) _strtoi64(p, e, b) +#endif +/*@}*/ + /*** *** LOG2: Log base 2 of float ***/ @@ -530,19 +566,25 @@ extern unsigned int _mesa_str_checksum(const char *str); extern int -_mesa_snprintf( char *str, size_t size, const char *fmt, ... ); +_mesa_snprintf( char *str, size_t size, const char *fmt, ... ) PRINTFLIKE(3, 4); extern void -_mesa_warning( __GLcontext *gc, const char *fmtString, ... ); +_mesa_warning( __GLcontext *gc, const char *fmtString, ... ) PRINTFLIKE(2, 3); extern void -_mesa_problem( const __GLcontext *ctx, const char *fmtString, ... ); +_mesa_problem( const __GLcontext *ctx, const char *fmtString, ... ) PRINTFLIKE(2, 3); extern void -_mesa_error( __GLcontext *ctx, GLenum error, const char *fmtString, ... ); +_mesa_error( __GLcontext *ctx, GLenum error, const char *fmtString, ... ) PRINTFLIKE(3, 4); extern void -_mesa_debug( const __GLcontext *ctx, const char *fmtString, ... ); +_mesa_debug( const __GLcontext *ctx, const char *fmtString, ... ) PRINTFLIKE(2, 3); + + +#if defined(_MSC_VER) && !defined(snprintf) +#define snprintf _snprintf +#endif + #ifdef __cplusplus } diff --git a/src/mesa/main/mipmap.c b/src/mesa/main/mipmap.c index c0c29f7889..678d17a2a3 100644 --- a/src/mesa/main/mipmap.c +++ b/src/mesa/main/mipmap.c @@ -1005,21 +1005,28 @@ make_2d_mipmap(GLenum datatype, GLuint comps, GLint border, const GLint dstRowBytes = bpt * dstRowStride; const GLubyte *srcA, *srcB; GLubyte *dst; - GLint row; + GLint row, srcRowStep; /* Compute src and dst pointers, skipping any border */ srcA = srcPtr + border * ((srcWidth + 1) * bpt); - if (srcHeight > 1) + if (srcHeight > 1 && srcHeight > dstHeight) { + /* sample from two source rows */ srcB = srcA + srcRowBytes; - else + srcRowStep = 2; + } + else { + /* sample from one source row */ srcB = srcA; + srcRowStep = 1; + } + dst = dstPtr + border * ((dstWidth + 1) * bpt); for (row = 0; row < dstHeightNB; row++) { do_row(datatype, comps, srcWidthNB, srcA, srcB, dstWidthNB, dst); - srcA += 2 * srcRowBytes; - srcB += 2 * srcRowBytes; + srcA += srcRowStep * srcRowBytes; + srcB += srcRowStep * srcRowBytes; dst += dstRowBytes; } diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 8d92892ad7..d44eff69cc 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1632,10 +1632,9 @@ struct gl_array_attrib GLbitfield NewState; /**< mask of _NEW_ARRAY_* values */ -#if FEATURE_ARB_vertex_buffer_object + /* GL_ARB_vertex_buffer_object */ struct gl_buffer_object *ArrayBufferObj; struct gl_buffer_object *ElementArrayBufferObj; -#endif }; @@ -2084,6 +2083,15 @@ struct gl_shader struct gl_program *Program; /**< Post-compile assembly code */ GLchar *InfoLog; struct gl_sl_pragmas Pragmas; + + unsigned Version; /**< GLSL version used for linking */ + + struct exec_list *ir; + struct glsl_symbol_table *symbols; + + /** Shaders containing built-in functions that are used for linking. */ + struct gl_shader *builtins_to_link[16]; + unsigned num_builtins_to_link; }; @@ -2129,6 +2137,16 @@ struct gl_shader_program GLboolean Validated; GLboolean _Used; /**< Ever used for drawing? */ GLchar *InfoLog; + + unsigned Version; /**< GLSL version used for linking */ + + /** + * Per-stage shaders resulting from the first stage of linking. + */ + /*@{*/ + GLuint _NumLinkedShaders; + struct gl_shader *_LinkedShaders[2]; + /*@}*/ }; @@ -2154,6 +2172,11 @@ struct gl_shader_state GLboolean EmitCondCodes; /**< Use condition codes? */ GLboolean EmitComments; /**< Annotated instructions */ GLboolean EmitNVTempInitialization; /**< 0-fill NV temp registers */ + /** + * Attempts to flatten all ir_if (OPCODE_IF) for GPUs that can't + * support control flow. + */ + GLboolean EmitNoIfs; void *MemPool; GLbitfield Flags; /**< Mask of GLSL_x flags */ struct gl_sl_pragmas DefaultPragmas; /**< Default #pragma settings */ @@ -2240,39 +2263,26 @@ struct gl_shared_state */ /*@{*/ struct _mesa_HashTable *Programs; /**< All vertex/fragment programs */ -#if FEATURE_ARB_vertex_program struct gl_vertex_program *DefaultVertexProgram; -#endif -#if FEATURE_ARB_fragment_program struct gl_fragment_program *DefaultFragmentProgram; -#endif -#if FEATURE_ARB_geometry_shader4 struct gl_geometry_program *DefaultGeometryProgram; -#endif /*@}*/ -#if FEATURE_ATI_fragment_shader + /* GL_ATI_fragment_shader */ struct _mesa_HashTable *ATIShaders; struct ati_fragment_shader *DefaultFragmentShader; -#endif -#if FEATURE_ARB_vertex_buffer_object || FEATURE_ARB_pixel_buffer_object struct _mesa_HashTable *BufferObjects; -#endif -#if FEATURE_ARB_shader_objects /** Table of both gl_shader and gl_shader_program objects */ struct _mesa_HashTable *ShaderObjects; -#endif -#if FEATURE_EXT_framebuffer_object + /* GL_EXT_framebuffer_object */ struct _mesa_HashTable *RenderBuffers; struct _mesa_HashTable *FrameBuffers; -#endif -#if FEATURE_ARB_sync + /* GL_ARB_sync */ struct simple_node SyncObjects; -#endif void *DriverData; /**< Device driver shared state */ }; @@ -2507,14 +2517,13 @@ struct gl_program_constants GLuint MaxNativeParameters; /* For shaders */ GLuint MaxUniformComponents; -#if FEATURE_ARB_geometry_shader4 + /* GL_ARB_geometry_shader4 */ GLuint MaxGeometryTextureImageUnits; GLuint MaxGeometryVaryingComponents; GLuint MaxVertexVaryingComponents; GLuint MaxGeometryUniformComponents; GLuint MaxGeometryOutputVertices; GLuint MaxGeometryTotalOutputComponents; -#endif }; @@ -2762,12 +2771,8 @@ struct gl_extensions GLboolean SGIS_texture_lod; GLboolean TDFX_texture_compression_FXT1; GLboolean S3_s3tc; -#if FEATURE_OES_EGL_image GLboolean OES_EGL_image; -#endif -#if FEATURE_OES_draw_texture GLboolean OES_draw_texture; -#endif /* FEATURE_OES_draw_texture */ /** The extension string */ const GLubyte *String; /** Number of supported extensions */ @@ -3208,9 +3213,8 @@ struct __GLcontextRec struct gl_meta_state *Meta; /**< for "meta" operations */ -#if FEATURE_EXT_framebuffer_object + /* GL_EXT_framebuffer_object */ struct gl_renderbuffer *CurrentRenderbuffer; -#endif GLenum ErrorValue; /**< Last error code */ diff --git a/src/mesa/main/querymatrix.c b/src/mesa/main/querymatrix.c index 32aaa79f7f..36236eb9a7 100644 --- a/src/mesa/main/querymatrix.c +++ b/src/mesa/main/querymatrix.c @@ -72,7 +72,8 @@ fpclassify(double x) #elif defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \ defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ - (defined(__sun) && defined(__C99FEATURES__)) || defined(__MINGW32__) + (defined(__sun) && defined(__C99FEATURES__)) || defined(__MINGW32__) || \ + (defined(__sun) && defined(__GNUC__)) /* fpclassify is available. */ diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index 9cb2391035..cc350c93b9 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -46,8 +46,7 @@ #include "program/program.h" #include "program/prog_parameter.h" #include "program/prog_uniform.h" -#include "slang/slang_compile.h" -#include "slang/slang_link.h" +#include "talloc.h" /** Define this to enable shader substitution (see below) */ @@ -99,6 +98,7 @@ _mesa_init_shader_state(GLcontext *ctx) ctx->Shader.EmitContReturn = GL_TRUE; ctx->Shader.EmitCondCodes = GL_FALSE; ctx->Shader.EmitComments = GL_FALSE; + ctx->Shader.EmitNoIfs = GL_FALSE; ctx->Shader.Flags = get_shader_flags(); /* Default pragma settings */ @@ -800,7 +800,7 @@ compile_shader(GLcontext *ctx, GLuint shaderObj) /* this call will set the sh->CompileStatus field to indicate if * compilation was successful. */ - (void) _slang_compile(ctx, sh); + _mesa_glsl_compile_shader(ctx, sh); } @@ -826,7 +826,7 @@ link_program(GLcontext *ctx, GLuint program) FLUSH_VERTICES(ctx, _NEW_PROGRAM); - _slang_link(ctx, program, shProg); + _mesa_glsl_link_shader(ctx, shProg); /* debug code */ if (0) { @@ -1051,9 +1051,9 @@ validate_program(GLcontext *ctx, GLuint program) if (!shProg->Validated) { /* update info log */ if (shProg->InfoLog) { - free(shProg->InfoLog); + talloc_free(shProg->InfoLog); } - shProg->InfoLog = _mesa_strdup(errMsg); + shProg->InfoLog = talloc_strdup(shProg, errMsg); } } diff --git a/src/mesa/main/shaderobj.c b/src/mesa/main/shaderobj.c index 14bbb2e4bc..59198d788b 100644 --- a/src/mesa/main/shaderobj.c +++ b/src/mesa/main/shaderobj.c @@ -36,7 +36,7 @@ #include "program/program.h" #include "program/prog_parameter.h" #include "program/prog_uniform.h" - +#include "talloc.h" /**********************************************************************/ /*** Shader object functions ***/ @@ -87,22 +87,27 @@ _mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr, } } +void +_mesa_init_shader(GLcontext *ctx, struct gl_shader *shader) +{ + shader->RefCount = 1; +} /** * Allocate a new gl_shader object, initialize it. * Called via ctx->Driver.NewShader() */ -static struct gl_shader * +struct gl_shader * _mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) { struct gl_shader *shader; assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER || type == GL_GEOMETRY_SHADER_ARB); - shader = CALLOC_STRUCT(gl_shader); + shader = talloc_zero(NULL, struct gl_shader); if (shader) { shader->Type = type; shader->Name = name; - shader->RefCount = 1; + _mesa_init_shader(ctx, shader); } return shader; } @@ -113,14 +118,12 @@ _mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) * Called via ctx->Driver.DeleteShader(). */ static void -__mesa_delete_shader(GLcontext *ctx, struct gl_shader *sh) +_mesa_delete_shader(GLcontext *ctx, struct gl_shader *sh) { if (sh->Source) free((void *) sh->Source); - if (sh->InfoLog) - free(sh->InfoLog); _mesa_reference_program(ctx, &sh->Program, NULL); - free(sh); + talloc_free(sh); } @@ -226,6 +229,18 @@ _mesa_reference_shader_program(GLcontext *ctx, } } +void +_mesa_init_shader_program(GLcontext *ctx, struct gl_shader_program *prog) +{ + prog->Type = GL_SHADER_PROGRAM_MESA; + prog->RefCount = 1; + prog->Attributes = _mesa_new_parameter_list(); +#if FEATURE_ARB_geometry_shader4 + prog->Geom.VerticesOut = 0; + prog->Geom.InputType = GL_TRIANGLES; + prog->Geom.OutputType = GL_TRIANGLE_STRIP; +#endif +} /** * Allocate a new gl_shader_program object, initialize it. @@ -235,17 +250,10 @@ static struct gl_shader_program * _mesa_new_shader_program(GLcontext *ctx, GLuint name) { struct gl_shader_program *shProg; - shProg = CALLOC_STRUCT(gl_shader_program); + shProg = talloc_zero(NULL, struct gl_shader_program); if (shProg) { - shProg->Type = GL_SHADER_PROGRAM_MESA; shProg->Name = name; - shProg->RefCount = 1; - shProg->Attributes = _mesa_new_parameter_list(); -#if FEATURE_ARB_geometry_shader4 - shProg->Geom.VerticesOut = 0; - shProg->Geom.InputType = GL_TRIANGLES; - shProg->Geom.OutputType = GL_TRIANGLE_STRIP; -#endif + _mesa_init_shader_program(ctx, shProg); } return shProg; } @@ -305,7 +313,7 @@ _mesa_free_shader_program_data(GLcontext *ctx, } if (shProg->InfoLog) { - free(shProg->InfoLog); + talloc_free(shProg->InfoLog); shProg->InfoLog = NULL; } @@ -316,6 +324,12 @@ _mesa_free_shader_program_data(GLcontext *ctx, free(shProg->TransformFeedback.VaryingNames); shProg->TransformFeedback.VaryingNames = NULL; shProg->TransformFeedback.NumVarying = 0; + + + for (i = 0; i < shProg->_NumLinkedShaders; i++) { + ctx->Driver.DeleteShader(ctx, shProg->_LinkedShaders[i]); + } + shProg->_NumLinkedShaders = 0; } @@ -324,11 +338,11 @@ _mesa_free_shader_program_data(GLcontext *ctx, * Called via ctx->Driver.DeleteShaderProgram(). */ static void -__mesa_delete_shader_program(GLcontext *ctx, struct gl_shader_program *shProg) +_mesa_delete_shader_program(GLcontext *ctx, struct gl_shader_program *shProg) { _mesa_free_shader_program_data(ctx, shProg); - free(shProg); + talloc_free(shProg); } @@ -386,7 +400,9 @@ void _mesa_init_shader_object_functions(struct dd_function_table *driver) { driver->NewShader = _mesa_new_shader; - driver->DeleteShader = __mesa_delete_shader; + driver->DeleteShader = _mesa_delete_shader; driver->NewShaderProgram = _mesa_new_shader_program; - driver->DeleteShaderProgram = __mesa_delete_shader_program; + driver->DeleteShaderProgram = _mesa_delete_shader_program; + driver->CompileShader = _mesa_ir_compile_shader; + driver->LinkShader = _mesa_ir_link_shader; } diff --git a/src/mesa/main/shaderobj.h b/src/mesa/main/shaderobj.h index d6b37b4596..4800046375 100644 --- a/src/mesa/main/shaderobj.h +++ b/src/mesa/main/shaderobj.h @@ -27,8 +27,22 @@ #define SHADEROBJ_H -#include "glheader.h" -#include "mtypes.h" +#include "main/glheader.h" +#include "main/mtypes.h" +#include "program/ir_to_mesa.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** + * Internal functions + */ + +extern void +_mesa_init_shader_state(GLcontext * ctx); + +extern void +_mesa_free_shader_state(GLcontext *ctx); extern void @@ -47,6 +61,14 @@ extern void _mesa_reference_shader_program(GLcontext *ctx, struct gl_shader_program **ptr, struct gl_shader_program *shProg); +extern void +_mesa_init_shader(GLcontext *ctx, struct gl_shader *shader); + +extern struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type); + +extern void +_mesa_init_shader_program(GLcontext *ctx, struct gl_shader_program *prog); extern struct gl_shader_program * _mesa_lookup_shader_program(GLcontext *ctx, GLuint name); @@ -74,5 +96,8 @@ _mesa_init_shader_state(GLcontext *ctx); extern void _mesa_free_shader_state(GLcontext *ctx); +#ifdef __cplusplus +} +#endif #endif /* SHADEROBJ_H */ diff --git a/src/mesa/main/shared.c b/src/mesa/main/shared.c index cbe004518a..ea7e503cf3 100644 --- a/src/mesa/main/shared.c +++ b/src/mesa/main/shared.c @@ -288,6 +288,10 @@ free_shared_state(GLcontext *ctx, struct gl_shared_state *shared) { GLuint i; + /* Free the dummy/fallback texture object */ + if (shared->FallbackTex) + ctx->Driver.DeleteTexture(ctx, shared->FallbackTex); + /* * Free display lists */ diff --git a/src/mesa/main/texcompress_s3tc.c b/src/mesa/main/texcompress_s3tc.c index c70792cab6..8e05980262 100644 --- a/src/mesa/main/texcompress_s3tc.c +++ b/src/mesa/main/texcompress_s3tc.c @@ -149,7 +149,6 @@ _mesa_init_texture_s3tc( GLcontext *ctx ) } if (dxtlibhandle) { ctx->Mesa_DXTn = GL_TRUE; - _mesa_warning(ctx, "software DXTn compression/decompression available"); } #else (void) ctx; diff --git a/src/mesa/main/transformfeedback.c b/src/mesa/main/transformfeedback.c index f86f1911d1..5c8c1fd225 100644 --- a/src/mesa/main/transformfeedback.c +++ b/src/mesa/main/transformfeedback.c @@ -455,14 +455,14 @@ _mesa_BindBufferRange(GLenum target, GLuint index, if ((size <= 0) || (size & 0x3)) { /* must be positive and multiple of four */ - _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size%d)", size); + _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size%d)", (int) size); return; } if (offset & 0x3) { /* must be multiple of four */ _mesa_error(ctx, GL_INVALID_VALUE, - "glBindBufferRange(offset=%d)", offset); + "glBindBufferRange(offset=%d)", (int) offset); return; } @@ -475,7 +475,8 @@ _mesa_BindBufferRange(GLenum target, GLuint index, if (offset + size >= bufObj->Size) { _mesa_error(ctx, GL_INVALID_VALUE, - "glBindBufferRange(offset + size > buffer size)", size); + "glBindBufferRange(offset + size %d > buffer size %d)", + (int) (offset + size), (int) (bufObj->Size)); return; } diff --git a/src/mesa/main/uniforms.c b/src/mesa/main/uniforms.c index d68a7768df..a5d7da51f0 100644 --- a/src/mesa/main/uniforms.c +++ b/src/mesa/main/uniforms.c @@ -454,17 +454,12 @@ _mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location, * The return value will encode two values, the uniform location and an * offset (used for arrays, structs). */ -static GLint -_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name) +GLint +_mesa_get_uniform_location(GLcontext *ctx, struct gl_shader_program *shProg, + const GLchar *name) { GLint offset = 0, location = -1; - struct gl_shader_program *shProg = - _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation"); - - if (!shProg) - return -1; - if (shProg->LinkStatus == GL_FALSE) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)"); return -1; @@ -751,11 +746,11 @@ set_program_uniform(GLcontext *ctx, struct gl_program *program, /** * Called via glUniform*() functions. */ -static void -_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, +void +_mesa_uniform(GLcontext *ctx, struct gl_shader_program *shProg, + GLint location, GLsizei count, const GLvoid *values, GLenum type) { - struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; struct gl_uniform *uniform; GLint elems, offset; @@ -923,12 +918,12 @@ set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program, * Called by glUniformMatrix*() functions. * Note: cols=2, rows=4 ==> array[2] of vec4 */ -static void -_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, +void +_mesa_uniform_matrix(GLcontext *ctx, struct gl_shader_program *shProg, + GLint cols, GLint rows, GLint location, GLsizei count, GLboolean transpose, const GLfloat *values) { - struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; struct gl_uniform *uniform; GLint offset; @@ -999,7 +994,7 @@ void GLAPIENTRY _mesa_Uniform1fARB(GLint location, GLfloat v0) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, 1, &v0, GL_FLOAT); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, &v0, GL_FLOAT); } void GLAPIENTRY @@ -1009,7 +1004,7 @@ _mesa_Uniform2fARB(GLint location, GLfloat v0, GLfloat v1) GLfloat v[2]; v[0] = v0; v[1] = v1; - _mesa_uniform(ctx, location, 1, v, GL_FLOAT_VEC2); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, v, GL_FLOAT_VEC2); } void GLAPIENTRY @@ -1020,7 +1015,7 @@ _mesa_Uniform3fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) v[0] = v0; v[1] = v1; v[2] = v2; - _mesa_uniform(ctx, location, 1, v, GL_FLOAT_VEC3); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, v, GL_FLOAT_VEC3); } void GLAPIENTRY @@ -1033,14 +1028,14 @@ _mesa_Uniform4fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, v[1] = v1; v[2] = v2; v[3] = v3; - _mesa_uniform(ctx, location, 1, v, GL_FLOAT_VEC4); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, v, GL_FLOAT_VEC4); } void GLAPIENTRY _mesa_Uniform1iARB(GLint location, GLint v0) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, 1, &v0, GL_INT); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, &v0, GL_INT); } void GLAPIENTRY @@ -1050,7 +1045,7 @@ _mesa_Uniform2iARB(GLint location, GLint v0, GLint v1) GLint v[2]; v[0] = v0; v[1] = v1; - _mesa_uniform(ctx, location, 1, v, GL_INT_VEC2); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, v, GL_INT_VEC2); } void GLAPIENTRY @@ -1061,7 +1056,7 @@ _mesa_Uniform3iARB(GLint location, GLint v0, GLint v1, GLint v2) v[0] = v0; v[1] = v1; v[2] = v2; - _mesa_uniform(ctx, location, 1, v, GL_INT_VEC3); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, v, GL_INT_VEC3); } void GLAPIENTRY @@ -1073,63 +1068,63 @@ _mesa_Uniform4iARB(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) v[1] = v1; v[2] = v2; v[3] = v3; - _mesa_uniform(ctx, location, 1, v, GL_INT_VEC4); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, v, GL_INT_VEC4); } void GLAPIENTRY _mesa_Uniform1fvARB(GLint location, GLsizei count, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_FLOAT); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_FLOAT); } void GLAPIENTRY _mesa_Uniform2fvARB(GLint location, GLsizei count, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_FLOAT_VEC2); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_FLOAT_VEC2); } void GLAPIENTRY _mesa_Uniform3fvARB(GLint location, GLsizei count, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_FLOAT_VEC3); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_FLOAT_VEC3); } void GLAPIENTRY _mesa_Uniform4fvARB(GLint location, GLsizei count, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_FLOAT_VEC4); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_FLOAT_VEC4); } void GLAPIENTRY _mesa_Uniform1ivARB(GLint location, GLsizei count, const GLint * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_INT); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_INT); } void GLAPIENTRY _mesa_Uniform2ivARB(GLint location, GLsizei count, const GLint * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_INT_VEC2); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_INT_VEC2); } void GLAPIENTRY _mesa_Uniform3ivARB(GLint location, GLsizei count, const GLint * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_INT_VEC3); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_INT_VEC3); } void GLAPIENTRY _mesa_Uniform4ivARB(GLint location, GLsizei count, const GLint * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_INT_VEC4); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_INT_VEC4); } @@ -1138,7 +1133,7 @@ void GLAPIENTRY _mesa_Uniform1ui(GLint location, GLuint v0) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, 1, &v0, GL_UNSIGNED_INT); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, &v0, GL_UNSIGNED_INT); } void GLAPIENTRY @@ -1148,7 +1143,7 @@ _mesa_Uniform2ui(GLint location, GLuint v0, GLuint v1) GLuint v[2]; v[0] = v0; v[1] = v1; - _mesa_uniform(ctx, location, 1, v, GL_UNSIGNED_INT_VEC2); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, v, GL_UNSIGNED_INT_VEC2); } void GLAPIENTRY @@ -1159,7 +1154,7 @@ _mesa_Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) v[0] = v0; v[1] = v1; v[2] = v2; - _mesa_uniform(ctx, location, 1, v, GL_UNSIGNED_INT_VEC3); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, v, GL_UNSIGNED_INT_VEC3); } void GLAPIENTRY @@ -1171,35 +1166,35 @@ _mesa_Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) v[1] = v1; v[2] = v2; v[3] = v3; - _mesa_uniform(ctx, location, 1, v, GL_UNSIGNED_INT_VEC4); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, 1, v, GL_UNSIGNED_INT_VEC4); } void GLAPIENTRY _mesa_Uniform1uiv(GLint location, GLsizei count, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_UNSIGNED_INT); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_UNSIGNED_INT); } void GLAPIENTRY _mesa_Uniform2uiv(GLint location, GLsizei count, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_UNSIGNED_INT_VEC2); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_UNSIGNED_INT_VEC2); } void GLAPIENTRY _mesa_Uniform3uiv(GLint location, GLsizei count, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_UNSIGNED_INT_VEC3); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_UNSIGNED_INT_VEC3); } void GLAPIENTRY _mesa_Uniform4uiv(GLint location, GLsizei count, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform(ctx, location, count, value, GL_UNSIGNED_INT_VEC4); + _mesa_uniform(ctx, ctx->Shader.CurrentProgram, location, count, value, GL_UNSIGNED_INT_VEC4); } @@ -1209,7 +1204,8 @@ _mesa_UniformMatrix2fvARB(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform_matrix(ctx, 2, 2, location, count, transpose, value); + _mesa_uniform_matrix(ctx, ctx->Shader.CurrentProgram, + 2, 2, location, count, transpose, value); } void GLAPIENTRY @@ -1217,7 +1213,8 @@ _mesa_UniformMatrix3fvARB(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform_matrix(ctx, 3, 3, location, count, transpose, value); + _mesa_uniform_matrix(ctx, ctx->Shader.CurrentProgram, + 3, 3, location, count, transpose, value); } void GLAPIENTRY @@ -1225,7 +1222,8 @@ _mesa_UniformMatrix4fvARB(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform_matrix(ctx, 4, 4, location, count, transpose, value); + _mesa_uniform_matrix(ctx, ctx->Shader.CurrentProgram, + 4, 4, location, count, transpose, value); } @@ -1237,7 +1235,8 @@ _mesa_UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform_matrix(ctx, 2, 3, location, count, transpose, value); + _mesa_uniform_matrix(ctx, ctx->Shader.CurrentProgram, + 2, 3, location, count, transpose, value); } void GLAPIENTRY @@ -1245,7 +1244,8 @@ _mesa_UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform_matrix(ctx, 3, 2, location, count, transpose, value); + _mesa_uniform_matrix(ctx, ctx->Shader.CurrentProgram, + 3, 2, location, count, transpose, value); } void GLAPIENTRY @@ -1253,7 +1253,8 @@ _mesa_UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform_matrix(ctx, 2, 4, location, count, transpose, value); + _mesa_uniform_matrix(ctx, ctx->Shader.CurrentProgram, + 2, 4, location, count, transpose, value); } void GLAPIENTRY @@ -1261,7 +1262,8 @@ _mesa_UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform_matrix(ctx, 4, 2, location, count, transpose, value); + _mesa_uniform_matrix(ctx, ctx->Shader.CurrentProgram, + 4, 2, location, count, transpose, value); } void GLAPIENTRY @@ -1269,7 +1271,8 @@ _mesa_UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform_matrix(ctx, 3, 4, location, count, transpose, value); + _mesa_uniform_matrix(ctx, ctx->Shader.CurrentProgram, + 3, 4, location, count, transpose, value); } void GLAPIENTRY @@ -1277,7 +1280,8 @@ _mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); - _mesa_uniform_matrix(ctx, 4, 3, location, count, transpose, value); + _mesa_uniform_matrix(ctx, ctx->Shader.CurrentProgram, + 4, 3, location, count, transpose, value); } @@ -1300,8 +1304,16 @@ _mesa_GetUniformivARB(GLhandleARB program, GLint location, GLint *params) GLint GLAPIENTRY _mesa_GetUniformLocationARB(GLhandleARB programObj, const GLcharARB *name) { + struct gl_shader_program *shProg; + GET_CURRENT_CONTEXT(ctx); - return _mesa_get_uniform_location(ctx, programObj, name); + + shProg = _mesa_lookup_shader_program_err(ctx, programObj, + "glGetUniformLocation"); + if (!shProg) + return -1; + + return _mesa_get_uniform_location(ctx, shProg, name); } diff --git a/src/mesa/main/uniforms.h b/src/mesa/main/uniforms.h index ef98fe16bb..f823c61444 100644 --- a/src/mesa/main/uniforms.h +++ b/src/mesa/main/uniforms.h @@ -150,7 +150,20 @@ _mesa_GetUniformivARB(GLhandleARB, GLint, GLint *); extern GLint GLAPIENTRY _mesa_GetUniformLocationARB(GLhandleARB, const GLcharARB *); - +GLint +_mesa_get_uniform_location(GLcontext *ctx, struct gl_shader_program *shProg, + const GLchar *name); + +void +_mesa_uniform(GLcontext *ctx, struct gl_shader_program *shader_program, + GLint location, GLsizei count, + const GLvoid *values, GLenum type); + +void +_mesa_uniform_matrix(GLcontext *ctx, struct gl_shader_program *shProg, + GLint cols, GLint rows, + GLint location, GLsizei count, + GLboolean transpose, const GLfloat *values); extern void _mesa_update_shader_textures_used(struct gl_program *prog); diff --git a/src/mesa/program/hash_table.c b/src/mesa/program/hash_table.c index fa6ba2bfdf..f7ef366c1a 100644 --- a/src/mesa/program/hash_table.c +++ b/src/mesa/program/hash_table.c @@ -142,6 +142,23 @@ hash_table_insert(struct hash_table *ht, void *data, const void *key) insert_at_head(& ht->buckets[bucket], & node->link); } +void +hash_table_remove(struct hash_table *ht, const void *key) +{ + const unsigned hash_value = (*ht->hash)(key); + const unsigned bucket = hash_value % ht->num_buckets; + struct node *node; + + foreach(node, & ht->buckets[bucket]) { + struct hash_node *hn = (struct hash_node *) node; + + if ((*ht->compare)(hn->key, key) == 0) { + remove_from_list(node); + free(node); + return; + } + } +} unsigned hash_table_string_hash(const void *key) @@ -157,3 +174,17 @@ hash_table_string_hash(const void *key) return hash; } + + +unsigned +hash_table_pointer_hash(const void *key) +{ + return (unsigned)((uintptr_t) key / sizeof(void *)); +} + + +int +hash_table_pointer_compare(const void *key1, const void *key2) +{ + return key1 == key2 ? 0 : 1; +} diff --git a/src/mesa/program/hash_table.h b/src/mesa/program/hash_table.h index e750906f96..f1c4fdcd1f 100644 --- a/src/mesa/program/hash_table.h +++ b/src/mesa/program/hash_table.h @@ -36,6 +36,10 @@ struct hash_table; typedef unsigned (*hash_func_t)(const void *key); typedef int (*hash_compare_func_t)(const void *key1, const void *key2); +#ifdef __cplusplus +extern "C" { +#endif + /** * Hash table constructor * @@ -88,6 +92,10 @@ extern void *hash_table_find(struct hash_table *ht, const void *key); extern void hash_table_insert(struct hash_table *ht, void *data, const void *key); +/** + * Remove a specific element from a hash table. + */ +extern void hash_table_remove(struct hash_table *ht, const void *key); /** * Compute hash value of a string @@ -112,4 +120,31 @@ extern unsigned hash_table_string_hash(const void *key); */ #define hash_table_string_compare ((hash_compare_func_t) strcmp) + +/** + * Compute hash value of a pointer + * + * \param key Pointer to be used as a hash key + * + * \note + * The memory pointed to by \c key is \b never accessed. The value of \c key + * itself is used as the hash key + * + * \sa hash_table_pointer_compare + */ +unsigned +hash_table_pointer_hash(const void *key); + + +/** + * Compare two pointers used as keys + * + * \sa hash_table_pointer_hash + */ +int +hash_table_pointer_compare(const void *key1, const void *key2); + +#ifdef __cplusplus +} +#endif #endif /* HASH_TABLE_H */ diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp new file mode 100644 index 0000000000..f0e14b8ece --- /dev/null +++ b/src/mesa/program/ir_to_mesa.cpp @@ -0,0 +1,2796 @@ +/* + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008 VMware, Inc. All Rights Reserved. + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_to_mesa.cpp + * + * Translates the IR to ARB_fragment_program text if possible, + * printing the result + */ + +#include <stdio.h> +#include "main/compiler.h" +#include "ir.h" +#include "ir_visitor.h" +#include "ir_print_visitor.h" +#include "ir_expression_flattening.h" +#include "glsl_types.h" +#include "glsl_parser_extras.h" +#include "../glsl/program.h" +#include "ir_optimization.h" +#include "ast.h" + +extern "C" { +#include "main/mtypes.h" +#include "main/shaderapi.h" +#include "main/shaderobj.h" +#include "main/uniforms.h" +#include "program/hash_table.h" +#include "program/prog_instruction.h" +#include "program/prog_optimize.h" +#include "program/prog_print.h" +#include "program/program.h" +#include "program/prog_uniform.h" +#include "program/prog_parameter.h" +} + +static int swizzle_for_size(int size); + +/** + * This struct is a corresponding struct to Mesa prog_src_register, with + * wider fields. + */ +typedef struct ir_to_mesa_src_reg { + ir_to_mesa_src_reg(int file, int index, const glsl_type *type) + { + this->file = file; + this->index = index; + if (type && (type->is_scalar() || type->is_vector() || type->is_matrix())) + this->swizzle = swizzle_for_size(type->vector_elements); + else + this->swizzle = SWIZZLE_XYZW; + this->negate = 0; + this->reladdr = NULL; + } + + ir_to_mesa_src_reg() + { + this->file = PROGRAM_UNDEFINED; + this->index = 0; + this->swizzle = 0; + this->negate = 0; + this->reladdr = NULL; + } + + int file; /**< PROGRAM_* from Mesa */ + int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ + GLuint swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */ + int negate; /**< NEGATE_XYZW mask from mesa */ + /** Register index should be offset by the integer in this reg. */ + ir_to_mesa_src_reg *reladdr; +} ir_to_mesa_src_reg; + +typedef struct ir_to_mesa_dst_reg { + int file; /**< PROGRAM_* from Mesa */ + int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ + int writemask; /**< Bitfield of WRITEMASK_[XYZW] */ + GLuint cond_mask:4; + /** Register index should be offset by the integer in this reg. */ + ir_to_mesa_src_reg *reladdr; +} ir_to_mesa_dst_reg; + +extern ir_to_mesa_src_reg ir_to_mesa_undef; + +class ir_to_mesa_instruction : public exec_node { +public: + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *node; + + node = talloc_zero_size(ctx, size); + assert(node != NULL); + + return node; + } + + enum prog_opcode op; + ir_to_mesa_dst_reg dst_reg; + ir_to_mesa_src_reg src_reg[3]; + /** Pointer to the ir source this tree came from for debugging */ + ir_instruction *ir; + GLboolean cond_update; + int sampler; /**< sampler index */ + int tex_target; /**< One of TEXTURE_*_INDEX */ + GLboolean tex_shadow; + + class function_entry *function; /* Set on OPCODE_CAL or OPCODE_BGNSUB */ +}; + +class variable_storage : public exec_node { +public: + variable_storage(ir_variable *var, int file, int index) + : file(file), index(index), var(var) + { + /* empty */ + } + + int file; + int index; + ir_variable *var; /* variable that maps to this, if any */ +}; + +class function_entry : public exec_node { +public: + ir_function_signature *sig; + + /** + * identifier of this function signature used by the program. + * + * At the point that Mesa instructions for function calls are + * generated, we don't know the address of the first instruction of + * the function body. So we make the BranchTarget that is called a + * small integer and rewrite them during set_branchtargets(). + */ + int sig_id; + + /** + * Pointer to first instruction of the function body. + * + * Set during function body emits after main() is processed. + */ + ir_to_mesa_instruction *bgn_inst; + + /** + * Index of the first instruction of the function body in actual + * Mesa IR. + * + * Set after convertion from ir_to_mesa_instruction to prog_instruction. + */ + int inst; + + /** Storage for the return value. */ + ir_to_mesa_src_reg return_reg; +}; + +class ir_to_mesa_visitor : public ir_visitor { +public: + ir_to_mesa_visitor(); + ~ir_to_mesa_visitor(); + + function_entry *current_function; + + GLcontext *ctx; + struct gl_program *prog; + struct gl_shader_program *shader_program; + + int next_temp; + + variable_storage *find_variable_storage(ir_variable *var); + + function_entry *get_function_signature(ir_function_signature *sig); + + ir_to_mesa_src_reg get_temp(const glsl_type *type); + void reladdr_to_temp(ir_instruction *ir, + ir_to_mesa_src_reg *reg, int *num_reladdr); + + struct ir_to_mesa_src_reg src_reg_for_float(float val); + + /** + * \name Visit methods + * + * As typical for the visitor pattern, there must be one \c visit method for + * each concrete subclass of \c ir_instruction. Virtual base classes within + * the hierarchy should not have \c visit methods. + */ + /*@{*/ + virtual void visit(ir_variable *); + virtual void visit(ir_loop *); + virtual void visit(ir_loop_jump *); + virtual void visit(ir_function_signature *); + virtual void visit(ir_function *); + virtual void visit(ir_expression *); + virtual void visit(ir_swizzle *); + virtual void visit(ir_dereference_variable *); + virtual void visit(ir_dereference_array *); + virtual void visit(ir_dereference_record *); + virtual void visit(ir_assignment *); + virtual void visit(ir_constant *); + virtual void visit(ir_call *); + virtual void visit(ir_return *); + virtual void visit(ir_discard *); + virtual void visit(ir_texture *); + virtual void visit(ir_if *); + /*@}*/ + + struct ir_to_mesa_src_reg result; + + /** List of variable_storage */ + exec_list variables; + + /** List of function_entry */ + exec_list function_signatures; + int next_signature_id; + + /** List of ir_to_mesa_instruction */ + exec_list instructions; + + ir_to_mesa_instruction *ir_to_mesa_emit_op0(ir_instruction *ir, + enum prog_opcode op); + + ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0); + + ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1); + + ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1, + ir_to_mesa_src_reg src2); + + void ir_to_mesa_emit_scalar_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0); + + void ir_to_mesa_emit_scalar_op2(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1); + + GLboolean try_emit_mad(ir_expression *ir, + int mul_operand); + + int get_sampler_uniform_value(ir_dereference *deref); + + void *mem_ctx; +}; + +ir_to_mesa_src_reg ir_to_mesa_undef = ir_to_mesa_src_reg(PROGRAM_UNDEFINED, 0, NULL); + +ir_to_mesa_dst_reg ir_to_mesa_undef_dst = { + PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR, NULL, +}; + +ir_to_mesa_dst_reg ir_to_mesa_address_reg = { + PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR, NULL +}; + +static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3); + +static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) + { + va_list args; + va_start(args, fmt); + prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, args); + va_end(args); + + prog->LinkStatus = GL_FALSE; + } + +static int swizzle_for_size(int size) +{ + int size_swizzles[4] = { + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z), + MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), + }; + + return size_swizzles[size - 1]; +} + +ir_to_mesa_instruction * +ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1, + ir_to_mesa_src_reg src2) +{ + ir_to_mesa_instruction *inst = new(mem_ctx) ir_to_mesa_instruction(); + int num_reladdr = 0; + + /* If we have to do relative addressing, we want to load the ARL + * reg directly for one of the regs, and preload the other reladdr + * sources into temps. + */ + num_reladdr += dst.reladdr != NULL; + num_reladdr += src0.reladdr != NULL; + num_reladdr += src1.reladdr != NULL; + num_reladdr += src2.reladdr != NULL; + + reladdr_to_temp(ir, &src2, &num_reladdr); + reladdr_to_temp(ir, &src1, &num_reladdr); + reladdr_to_temp(ir, &src0, &num_reladdr); + + if (dst.reladdr) { + ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, + *dst.reladdr); + + num_reladdr--; + } + assert(num_reladdr == 0); + + inst->op = op; + inst->dst_reg = dst; + inst->src_reg[0] = src0; + inst->src_reg[1] = src1; + inst->src_reg[2] = src2; + inst->ir = ir; + + inst->function = NULL; + + this->instructions.push_tail(inst); + + return inst; +} + + +ir_to_mesa_instruction * +ir_to_mesa_visitor::ir_to_mesa_emit_op2(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0, + ir_to_mesa_src_reg src1) +{ + return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef); +} + +ir_to_mesa_instruction * +ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0) +{ + assert(dst.writemask != 0); + return ir_to_mesa_emit_op3(ir, op, dst, + src0, ir_to_mesa_undef, ir_to_mesa_undef); +} + +ir_to_mesa_instruction * +ir_to_mesa_visitor::ir_to_mesa_emit_op0(ir_instruction *ir, + enum prog_opcode op) +{ + return ir_to_mesa_emit_op3(ir, op, ir_to_mesa_undef_dst, + ir_to_mesa_undef, + ir_to_mesa_undef, + ir_to_mesa_undef); +} + +inline ir_to_mesa_dst_reg +ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg) +{ + ir_to_mesa_dst_reg dst_reg; + + dst_reg.file = reg.file; + dst_reg.index = reg.index; + dst_reg.writemask = WRITEMASK_XYZW; + dst_reg.cond_mask = COND_TR; + dst_reg.reladdr = reg.reladdr; + + return dst_reg; +} + +inline ir_to_mesa_src_reg +ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg) +{ + return ir_to_mesa_src_reg(reg.file, reg.index, NULL); +} + +/** + * Emits Mesa scalar opcodes to produce unique answers across channels. + * + * Some Mesa opcodes are scalar-only, like ARB_fp/vp. The src X + * channel determines the result across all channels. So to do a vec4 + * of this operation, we want to emit a scalar per source channel used + * to produce dest channels. + */ +void +ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg orig_src0, + ir_to_mesa_src_reg orig_src1) +{ + int i, j; + int done_mask = ~dst.writemask; + + /* Mesa RCP is a scalar operation splatting results to all channels, + * like ARB_fp/vp. So emit as many RCPs as necessary to cover our + * dst channels. + */ + for (i = 0; i < 4; i++) { + GLuint this_mask = (1 << i); + ir_to_mesa_instruction *inst; + ir_to_mesa_src_reg src0 = orig_src0; + ir_to_mesa_src_reg src1 = orig_src1; + + if (done_mask & this_mask) + continue; + + GLuint src0_swiz = GET_SWZ(src0.swizzle, i); + GLuint src1_swiz = GET_SWZ(src1.swizzle, i); + for (j = i + 1; j < 4; j++) { + if (!(done_mask & (1 << j)) && + GET_SWZ(src0.swizzle, j) == src0_swiz && + GET_SWZ(src1.swizzle, j) == src1_swiz) { + this_mask |= (1 << j); + } + } + src0.swizzle = MAKE_SWIZZLE4(src0_swiz, src0_swiz, + src0_swiz, src0_swiz); + src1.swizzle = MAKE_SWIZZLE4(src1_swiz, src1_swiz, + src1_swiz, src1_swiz); + + inst = ir_to_mesa_emit_op2(ir, op, + dst, + src0, + src1); + inst->dst_reg.writemask = this_mask; + done_mask |= this_mask; + } +} + +void +ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir, + enum prog_opcode op, + ir_to_mesa_dst_reg dst, + ir_to_mesa_src_reg src0) +{ + ir_to_mesa_src_reg undef = ir_to_mesa_undef; + + undef.swizzle = SWIZZLE_XXXX; + + ir_to_mesa_emit_scalar_op2(ir, op, dst, src0, undef); +} + +struct ir_to_mesa_src_reg +ir_to_mesa_visitor::src_reg_for_float(float val) +{ + ir_to_mesa_src_reg src_reg(PROGRAM_CONSTANT, -1, NULL); + + src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters, + &val, 1, &src_reg.swizzle); + + return src_reg; +} + +static int +type_size(const struct glsl_type *type) +{ + unsigned int i; + int size; + + switch (type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + if (type->is_matrix()) { + return type->matrix_columns; + } else { + /* Regardless of size of vector, it gets a vec4. This is bad + * packing for things like floats, but otherwise arrays become a + * mess. Hopefully a later pass over the code can pack scalars + * down if appropriate. + */ + return 1; + } + case GLSL_TYPE_ARRAY: + return type_size(type->fields.array) * type->length; + case GLSL_TYPE_STRUCT: + size = 0; + for (i = 0; i < type->length; i++) { + size += type_size(type->fields.structure[i].type); + } + return size; + case GLSL_TYPE_SAMPLER: + /* Samplers take up one slot in UNIFORMS[], but they're baked in + * at link time. + */ + return 1; + default: + assert(0); + return 0; + } +} + +/** + * In the initial pass of codegen, we assign temporary numbers to + * intermediate results. (not SSA -- variable assignments will reuse + * storage). Actual register allocation for the Mesa VM occurs in a + * pass over the Mesa IR later. + */ +ir_to_mesa_src_reg +ir_to_mesa_visitor::get_temp(const glsl_type *type) +{ + ir_to_mesa_src_reg src_reg; + int swizzle[4]; + int i; + + src_reg.file = PROGRAM_TEMPORARY; + src_reg.index = next_temp; + src_reg.reladdr = NULL; + next_temp += type_size(type); + + if (type->is_array() || type->is_record()) { + src_reg.swizzle = SWIZZLE_NOOP; + } else { + for (i = 0; i < type->vector_elements; i++) + swizzle[i] = i; + for (; i < 4; i++) + swizzle[i] = type->vector_elements - 1; + src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], + swizzle[2], swizzle[3]); + } + src_reg.negate = 0; + + return src_reg; +} + +variable_storage * +ir_to_mesa_visitor::find_variable_storage(ir_variable *var) +{ + + variable_storage *entry; + + foreach_iter(exec_list_iterator, iter, this->variables) { + entry = (variable_storage *)iter.get(); + + if (entry->var == var) + return entry; + } + + return NULL; +} + +struct statevar_element { + const char *field; + int tokens[STATE_LENGTH]; + int swizzle; + bool array_indexed; +}; + +static struct statevar_element gl_DepthRange_elements[] = { + {"near", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_XXXX}, + {"far", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_YYYY}, + {"diff", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_ZZZZ}, +}; + +static struct statevar_element gl_ClipPlane_elements[] = { + {NULL, {STATE_CLIPPLANE, 0, 0}, SWIZZLE_XYZW} +}; + +static struct statevar_element gl_Point_elements[] = { + {"size", {STATE_POINT_SIZE}, SWIZZLE_XXXX}, + {"sizeMin", {STATE_POINT_SIZE}, SWIZZLE_YYYY}, + {"sizeMax", {STATE_POINT_SIZE}, SWIZZLE_ZZZZ}, + {"fadeThresholdSize", {STATE_POINT_SIZE}, SWIZZLE_WWWW}, + {"distanceConstantAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_XXXX}, + {"distanceLinearAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_YYYY}, + {"distanceQuadraticAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_ZZZZ}, +}; + +static struct statevar_element gl_FrontMaterial_elements[] = { + {"emission", {STATE_MATERIAL, 0, STATE_EMISSION}, SWIZZLE_XYZW}, + {"ambient", {STATE_MATERIAL, 0, STATE_AMBIENT}, SWIZZLE_XYZW}, + {"diffuse", {STATE_MATERIAL, 0, STATE_DIFFUSE}, SWIZZLE_XYZW}, + {"specular", {STATE_MATERIAL, 0, STATE_SPECULAR}, SWIZZLE_XYZW}, + {"shininess", {STATE_MATERIAL, 0, STATE_SHININESS}, SWIZZLE_XXXX}, +}; + +static struct statevar_element gl_BackMaterial_elements[] = { + {"emission", {STATE_MATERIAL, 1, STATE_EMISSION}, SWIZZLE_XYZW}, + {"ambient", {STATE_MATERIAL, 1, STATE_AMBIENT}, SWIZZLE_XYZW}, + {"diffuse", {STATE_MATERIAL, 1, STATE_DIFFUSE}, SWIZZLE_XYZW}, + {"specular", {STATE_MATERIAL, 1, STATE_SPECULAR}, SWIZZLE_XYZW}, + {"shininess", {STATE_MATERIAL, 1, STATE_SHININESS}, SWIZZLE_XXXX}, +}; + +static struct statevar_element gl_LightSource_elements[] = { + {"ambient", {STATE_LIGHT, 0, STATE_AMBIENT}, SWIZZLE_XYZW}, + {"diffuse", {STATE_LIGHT, 0, STATE_DIFFUSE}, SWIZZLE_XYZW}, + {"specular", {STATE_LIGHT, 0, STATE_SPECULAR}, SWIZZLE_XYZW}, + {"position", {STATE_LIGHT, 0, STATE_POSITION}, SWIZZLE_XYZW}, + {"halfVector", {STATE_LIGHT, 0, STATE_HALF_VECTOR}, SWIZZLE_XYZW}, + {"spotDirection", {STATE_LIGHT, 0, STATE_SPOT_DIRECTION}, SWIZZLE_XYZW}, + {"spotCosCutoff", {STATE_LIGHT, 0, STATE_SPOT_DIRECTION}, SWIZZLE_WWWW}, + {"spotCutoff", {STATE_LIGHT, 0, STATE_SPOT_CUTOFF}, SWIZZLE_XXXX}, + {"spotExponent", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_WWWW}, + {"constantAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_XXXX}, + {"linearAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_YYYY}, + {"quadraticAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_ZZZZ}, +}; + +static struct statevar_element gl_LightModel_elements[] = { + {"ambient", {STATE_LIGHTMODEL_AMBIENT, 0}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_FrontLightModelProduct_elements[] = { + {"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 0}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_BackLightModelProduct_elements[] = { + {"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 1}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_FrontLightProduct_elements[] = { + {"ambient", {STATE_LIGHTPROD, 0, 0, STATE_AMBIENT}, SWIZZLE_XYZW}, + {"diffuse", {STATE_LIGHTPROD, 0, 0, STATE_DIFFUSE}, SWIZZLE_XYZW}, + {"specular", {STATE_LIGHTPROD, 0, 0, STATE_SPECULAR}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_BackLightProduct_elements[] = { + {"ambient", {STATE_LIGHTPROD, 0, 1, STATE_AMBIENT}, SWIZZLE_XYZW}, + {"diffuse", {STATE_LIGHTPROD, 0, 1, STATE_DIFFUSE}, SWIZZLE_XYZW}, + {"specular", {STATE_LIGHTPROD, 0, 1, STATE_SPECULAR}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_TextureEnvColor_elements[] = { + {NULL, {STATE_TEXENV_COLOR, 0}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_EyePlaneS_elements[] = { + {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_S}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_EyePlaneT_elements[] = { + {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_T}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_EyePlaneR_elements[] = { + {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_R}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_EyePlaneQ_elements[] = { + {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_Q}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_ObjectPlaneS_elements[] = { + {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_S}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_ObjectPlaneT_elements[] = { + {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_T}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_ObjectPlaneR_elements[] = { + {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_R}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_ObjectPlaneQ_elements[] = { + {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_Q}, SWIZZLE_XYZW}, +}; + +static struct statevar_element gl_Fog_elements[] = { + {"color", {STATE_FOG_COLOR}, SWIZZLE_XYZW}, + {"density", {STATE_FOG_PARAMS}, SWIZZLE_XXXX}, + {"start", {STATE_FOG_PARAMS}, SWIZZLE_YYYY}, + {"end", {STATE_FOG_PARAMS}, SWIZZLE_ZZZZ}, + {"scale", {STATE_FOG_PARAMS}, SWIZZLE_WWWW}, +}; + +#define MATRIX(name, statevar, modifier) \ + static struct statevar_element name ## _elements[] = { \ + { NULL, { statevar, 0, 0, 0, modifier}, SWIZZLE_XYZW }, \ + { NULL, { statevar, 0, 1, 1, modifier}, SWIZZLE_XYZW }, \ + { NULL, { statevar, 0, 2, 2, modifier}, SWIZZLE_XYZW }, \ + { NULL, { statevar, 0, 3, 3, modifier}, SWIZZLE_XYZW }, \ + } + +MATRIX(gl_ModelViewMatrix, + STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE); +MATRIX(gl_ModelViewMatrixInverse, + STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVTRANS); +MATRIX(gl_ModelViewMatrixTranspose, + STATE_MODELVIEW_MATRIX, 0); +MATRIX(gl_ModelViewMatrixInverseTranspose, + STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE); + +MATRIX(gl_ProjectionMatrix, + STATE_PROJECTION_MATRIX, STATE_MATRIX_TRANSPOSE); +MATRIX(gl_ProjectionMatrixInverse, + STATE_PROJECTION_MATRIX, STATE_MATRIX_INVTRANS); +MATRIX(gl_ProjectionMatrixTranspose, + STATE_PROJECTION_MATRIX, 0); +MATRIX(gl_ProjectionMatrixInverseTranspose, + STATE_PROJECTION_MATRIX, STATE_MATRIX_INVERSE); + +MATRIX(gl_ModelViewProjectionMatrix, + STATE_MVP_MATRIX, STATE_MATRIX_TRANSPOSE); +MATRIX(gl_ModelViewProjectionMatrixInverse, + STATE_MVP_MATRIX, STATE_MATRIX_INVTRANS); +MATRIX(gl_ModelViewProjectionMatrixTranspose, + STATE_MVP_MATRIX, 0); +MATRIX(gl_ModelViewProjectionMatrixInverseTranspose, + STATE_MVP_MATRIX, STATE_MATRIX_INVERSE); + +MATRIX(gl_TextureMatrix, + STATE_TEXTURE_MATRIX, STATE_MATRIX_TRANSPOSE); +MATRIX(gl_TextureMatrixInverse, + STATE_TEXTURE_MATRIX, STATE_MATRIX_INVTRANS); +MATRIX(gl_TextureMatrixTranspose, + STATE_TEXTURE_MATRIX, 0); +MATRIX(gl_TextureMatrixInverseTranspose, + STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE); + +static struct statevar_element gl_NormalMatrix_elements[] = { + { NULL, { STATE_MODELVIEW_MATRIX, 0, 0, 0, STATE_MATRIX_INVERSE}, + SWIZZLE_XYZW }, + { NULL, { STATE_MODELVIEW_MATRIX, 0, 1, 1, STATE_MATRIX_INVERSE}, + SWIZZLE_XYZW }, + { NULL, { STATE_MODELVIEW_MATRIX, 0, 2, 2, STATE_MATRIX_INVERSE}, + SWIZZLE_XYZW }, +}; + +#undef MATRIX + +#define STATEVAR(name) {#name, name ## _elements, Elements(name ## _elements)} + +static struct { + const char *name; + struct statevar_element *elements; + int num_elements; +} statevars[] = { + STATEVAR(gl_DepthRange), + STATEVAR(gl_ClipPlane), + STATEVAR(gl_Point), + STATEVAR(gl_FrontMaterial), + STATEVAR(gl_BackMaterial), + STATEVAR(gl_LightSource), + STATEVAR(gl_LightModel), + STATEVAR(gl_FrontLightModelProduct), + STATEVAR(gl_BackLightModelProduct), + STATEVAR(gl_FrontLightProduct), + STATEVAR(gl_BackLightProduct), + STATEVAR(gl_TextureEnvColor), + STATEVAR(gl_EyePlaneS), + STATEVAR(gl_EyePlaneT), + STATEVAR(gl_EyePlaneR), + STATEVAR(gl_EyePlaneQ), + STATEVAR(gl_ObjectPlaneS), + STATEVAR(gl_ObjectPlaneT), + STATEVAR(gl_ObjectPlaneR), + STATEVAR(gl_ObjectPlaneQ), + STATEVAR(gl_Fog), + + STATEVAR(gl_ModelViewMatrix), + STATEVAR(gl_ModelViewMatrixInverse), + STATEVAR(gl_ModelViewMatrixTranspose), + STATEVAR(gl_ModelViewMatrixInverseTranspose), + + STATEVAR(gl_ProjectionMatrix), + STATEVAR(gl_ProjectionMatrixInverse), + STATEVAR(gl_ProjectionMatrixTranspose), + STATEVAR(gl_ProjectionMatrixInverseTranspose), + + STATEVAR(gl_ModelViewProjectionMatrix), + STATEVAR(gl_ModelViewProjectionMatrixInverse), + STATEVAR(gl_ModelViewProjectionMatrixTranspose), + STATEVAR(gl_ModelViewProjectionMatrixInverseTranspose), + + STATEVAR(gl_TextureMatrix), + STATEVAR(gl_TextureMatrixInverse), + STATEVAR(gl_TextureMatrixTranspose), + STATEVAR(gl_TextureMatrixInverseTranspose), + + STATEVAR(gl_NormalMatrix), +}; + +void +ir_to_mesa_visitor::visit(ir_variable *ir) +{ + if (strcmp(ir->name, "gl_FragCoord") == 0) { + struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog; + + fp->OriginUpperLeft = ir->origin_upper_left; + fp->PixelCenterInteger = ir->pixel_center_integer; + } + + if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) { + unsigned int i; + + struct variable_storage *entry; + entry = new(mem_ctx) variable_storage(ir, PROGRAM_TEMPORARY, + this->next_temp); + this->variables.push_tail(entry); + this->next_temp += type_size(ir->type); + + for (i = 0; i < Elements(statevars); i++) { + if (strcmp(ir->name, statevars[i].name) == 0) + break; + } + + if (i == Elements(statevars)) { + fail_link(this->shader_program, + "Failed to find builtin uniform `%s'\n", ir->name); + return; + } + + ir_to_mesa_dst_reg dst = + ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg(PROGRAM_TEMPORARY, + entry->index, NULL)); + + int array_count; + if (ir->type->is_array()) { + array_count = ir->type->length; + } else { + array_count = 1; + } + + for (int a = 0; a < array_count; a++) { + for (int j = 0; j < statevars[i].num_elements; j++) { + struct statevar_element *element = &statevars[i].elements[j]; + int tokens[STATE_LENGTH]; + + memcpy(tokens, element->tokens, sizeof(element->tokens)); + if (ir->type->is_array()) { + tokens[1] = a; + } + + int index = _mesa_add_state_reference(this->prog->Parameters, + (gl_state_index *)tokens); + ir_to_mesa_src_reg src(PROGRAM_STATE_VAR, index, NULL); + src.swizzle = element->swizzle; + ir_to_mesa_emit_op1(ir, OPCODE_MOV, dst, src); + /* even a float takes up a whole vec4 reg in a struct/array. */ + dst.index++; + } + } + if (dst.index != entry->index + type_size(ir->type)) { + fail_link(this->shader_program, + "failed to load builtin uniform `%s' (%d/%d regs loaded)\n", + ir->name, dst.index - entry->index, + type_size(ir->type)); + } + } +} + +void +ir_to_mesa_visitor::visit(ir_loop *ir) +{ + assert(!ir->from); + assert(!ir->to); + assert(!ir->increment); + assert(!ir->counter); + + ir_to_mesa_emit_op0(NULL, OPCODE_BGNLOOP); + visit_exec_list(&ir->body_instructions, this); + ir_to_mesa_emit_op0(NULL, OPCODE_ENDLOOP); +} + +void +ir_to_mesa_visitor::visit(ir_loop_jump *ir) +{ + switch (ir->mode) { + case ir_loop_jump::jump_break: + ir_to_mesa_emit_op0(NULL, OPCODE_BRK); + break; + case ir_loop_jump::jump_continue: + ir_to_mesa_emit_op0(NULL, OPCODE_CONT); + break; + } +} + + +void +ir_to_mesa_visitor::visit(ir_function_signature *ir) +{ + assert(0); + (void)ir; +} + +void +ir_to_mesa_visitor::visit(ir_function *ir) +{ + /* Ignore function bodies other than main() -- we shouldn't see calls to + * them since they should all be inlined before we get to ir_to_mesa. + */ + if (strcmp(ir->name, "main") == 0) { + const ir_function_signature *sig; + exec_list empty; + + sig = ir->matching_signature(&empty); + + assert(sig); + + foreach_iter(exec_list_iterator, iter, sig->body) { + ir_instruction *ir = (ir_instruction *)iter.get(); + + ir->accept(this); + } + } +} + +GLboolean +ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand) +{ + int nonmul_operand = 1 - mul_operand; + ir_to_mesa_src_reg a, b, c; + + ir_expression *expr = ir->operands[mul_operand]->as_expression(); + if (!expr || expr->operation != ir_binop_mul) + return false; + + expr->operands[0]->accept(this); + a = this->result; + expr->operands[1]->accept(this); + b = this->result; + ir->operands[nonmul_operand]->accept(this); + c = this->result; + + this->result = get_temp(ir->type); + ir_to_mesa_emit_op3(ir, OPCODE_MAD, + ir_to_mesa_dst_reg_from_src(this->result), a, b, c); + + return true; +} + +void +ir_to_mesa_visitor::reladdr_to_temp(ir_instruction *ir, + ir_to_mesa_src_reg *reg, int *num_reladdr) +{ + if (!reg->reladdr) + return; + + ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, *reg->reladdr); + + if (*num_reladdr != 1) { + ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type); + + ir_to_mesa_emit_op1(ir, OPCODE_MOV, + ir_to_mesa_dst_reg_from_src(temp), *reg); + *reg = temp; + } + + (*num_reladdr)--; +} + +void +ir_to_mesa_visitor::visit(ir_expression *ir) +{ + unsigned int operand; + struct ir_to_mesa_src_reg op[2]; + struct ir_to_mesa_src_reg result_src; + struct ir_to_mesa_dst_reg result_dst; + const glsl_type *vec4_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 4, 1); + const glsl_type *vec3_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 3, 1); + const glsl_type *vec2_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 2, 1); + + /* Quick peephole: Emit OPCODE_MAD(a, b, c) instead of ADD(MUL(a, b), c) + */ + if (ir->operation == ir_binop_add) { + if (try_emit_mad(ir, 1)) + return; + if (try_emit_mad(ir, 0)) + return; + } + + for (operand = 0; operand < ir->get_num_operands(); operand++) { + this->result.file = PROGRAM_UNDEFINED; + ir->operands[operand]->accept(this); + if (this->result.file == PROGRAM_UNDEFINED) { + ir_print_visitor v; + printf("Failed to get tree for expression operand:\n"); + ir->operands[operand]->accept(&v); + exit(1); + } + op[operand] = this->result; + + /* Matrix expression operands should have been broken down to vector + * operations already. + */ + assert(!ir->operands[operand]->type->is_matrix()); + } + + this->result.file = PROGRAM_UNDEFINED; + + /* Storage for our result. Ideally for an assignment we'd be using + * the actual storage for the result here, instead. + */ + result_src = get_temp(ir->type); + /* convenience for the emit functions below. */ + result_dst = ir_to_mesa_dst_reg_from_src(result_src); + /* Limit writes to the channels that will be used by result_src later. + * This does limit this temp's use as a temporary for multi-instruction + * sequences. + */ + result_dst.writemask = (1 << ir->type->vector_elements) - 1; + + switch (ir->operation) { + case ir_unop_logic_not: + ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, + op[0], src_reg_for_float(0.0)); + break; + case ir_unop_neg: + op[0].negate = ~op[0].negate; + result_src = op[0]; + break; + case ir_unop_abs: + ir_to_mesa_emit_op1(ir, OPCODE_ABS, result_dst, op[0]); + break; + case ir_unop_sign: + ir_to_mesa_emit_op1(ir, OPCODE_SSG, result_dst, op[0]); + break; + case ir_unop_rcp: + ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[0]); + break; + + case ir_unop_exp2: + ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]); + break; + case ir_unop_exp: + case ir_unop_log: + assert(!"not reached: should be handled by ir_explog_to_explog2"); + break; + case ir_unop_log2: + ir_to_mesa_emit_scalar_op1(ir, OPCODE_LG2, result_dst, op[0]); + break; + case ir_unop_sin: + ir_to_mesa_emit_scalar_op1(ir, OPCODE_SIN, result_dst, op[0]); + break; + case ir_unop_cos: + ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]); + break; + + case ir_unop_dFdx: + ir_to_mesa_emit_op1(ir, OPCODE_DDX, result_dst, op[0]); + break; + case ir_unop_dFdy: + ir_to_mesa_emit_op1(ir, OPCODE_DDY, result_dst, op[0]); + break; + + case ir_binop_add: + ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]); + break; + case ir_binop_sub: + ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]); + break; + + case ir_binop_mul: + ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]); + break; + case ir_binop_div: + assert(!"not reached: should be handled by ir_div_to_mul_rcp"); + case ir_binop_mod: + assert(!"ir_binop_mod should have been converted to b * fract(a/b)"); + break; + + case ir_binop_less: + ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], op[1]); + break; + case ir_binop_greater: + ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], op[1]); + break; + case ir_binop_lequal: + ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], op[1]); + break; + case ir_binop_gequal: + ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], op[1]); + break; + case ir_binop_equal: + /* "==" operator producing a scalar boolean. */ + if (ir->operands[0]->type->is_vector() || + ir->operands[1]->type->is_vector()) { + ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type); + ir_to_mesa_emit_op2(ir, OPCODE_SNE, + ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_DP4, result_dst, temp, temp); + ir_to_mesa_emit_op2(ir, OPCODE_SEQ, + result_dst, result_src, src_reg_for_float(0.0)); + } else { + ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]); + } + break; + case ir_binop_nequal: + /* "!=" operator producing a scalar boolean. */ + if (ir->operands[0]->type->is_vector() || + ir->operands[1]->type->is_vector()) { + ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type); + ir_to_mesa_emit_op2(ir, OPCODE_SNE, + ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]); + ir_to_mesa_emit_op2(ir, OPCODE_DP4, result_dst, temp, temp); + ir_to_mesa_emit_op2(ir, OPCODE_SNE, + result_dst, result_src, src_reg_for_float(0.0)); + } else { + ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]); + } + break; + + case ir_unop_any: + switch (ir->operands[0]->type->vector_elements) { + case 4: + ir_to_mesa_emit_op2(ir, OPCODE_DP4, result_dst, op[0], op[0]); + break; + case 3: + ir_to_mesa_emit_op2(ir, OPCODE_DP3, result_dst, op[0], op[0]); + break; + case 2: + ir_to_mesa_emit_op2(ir, OPCODE_DP2, result_dst, op[0], op[0]); + break; + default: + assert(!"unreached: ir_unop_any of non-bvec"); + break; + } + ir_to_mesa_emit_op2(ir, OPCODE_SNE, + result_dst, result_src, src_reg_for_float(0.0)); + break; + + case ir_binop_logic_xor: + ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]); + break; + + case ir_binop_logic_or: + /* This could be a saturated add and skip the SNE. */ + ir_to_mesa_emit_op2(ir, OPCODE_ADD, + result_dst, + op[0], op[1]); + + ir_to_mesa_emit_op2(ir, OPCODE_SNE, + result_dst, + result_src, src_reg_for_float(0.0)); + break; + + case ir_binop_logic_and: + /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */ + ir_to_mesa_emit_op2(ir, OPCODE_MUL, + result_dst, + op[0], op[1]); + break; + + case ir_binop_dot: + if (ir->operands[0]->type == vec4_type) { + assert(ir->operands[1]->type == vec4_type); + ir_to_mesa_emit_op2(ir, OPCODE_DP4, + result_dst, + op[0], op[1]); + } else if (ir->operands[0]->type == vec3_type) { + assert(ir->operands[1]->type == vec3_type); + ir_to_mesa_emit_op2(ir, OPCODE_DP3, + result_dst, + op[0], op[1]); + } else if (ir->operands[0]->type == vec2_type) { + assert(ir->operands[1]->type == vec2_type); + ir_to_mesa_emit_op2(ir, OPCODE_DP2, + result_dst, + op[0], op[1]); + } + break; + + case ir_binop_cross: + ir_to_mesa_emit_op2(ir, OPCODE_XPD, result_dst, op[0], op[1]); + break; + + case ir_unop_sqrt: + /* sqrt(x) = x * rsq(x). */ + ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]); + ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, result_src, op[0]); + /* For incoming channels <= 0, set the result to 0. */ + op[0].negate = ~op[0].negate; + ir_to_mesa_emit_op3(ir, OPCODE_CMP, result_dst, + op[0], result_src, src_reg_for_float(0.0)); + break; + case ir_unop_rsq: + ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]); + break; + case ir_unop_i2f: + case ir_unop_b2f: + case ir_unop_b2i: + /* Mesa IR lacks types, ints are stored as truncated floats. */ + result_src = op[0]; + break; + case ir_unop_f2i: + ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]); + break; + case ir_unop_f2b: + case ir_unop_i2b: + ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, + op[0], src_reg_for_float(0.0)); + break; + case ir_unop_trunc: + ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]); + break; + case ir_unop_ceil: + op[0].negate = ~op[0].negate; + ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]); + result_src.negate = ~result_src.negate; + break; + case ir_unop_floor: + ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]); + break; + case ir_unop_fract: + ir_to_mesa_emit_op1(ir, OPCODE_FRC, result_dst, op[0]); + break; + + case ir_binop_min: + ir_to_mesa_emit_op2(ir, OPCODE_MIN, result_dst, op[0], op[1]); + break; + case ir_binop_max: + ir_to_mesa_emit_op2(ir, OPCODE_MAX, result_dst, op[0], op[1]); + break; + case ir_binop_pow: + ir_to_mesa_emit_scalar_op2(ir, OPCODE_POW, result_dst, op[0], op[1]); + break; + + case ir_unop_bit_not: + case ir_unop_u2f: + case ir_binop_lshift: + case ir_binop_rshift: + case ir_binop_bit_and: + case ir_binop_bit_xor: + case ir_binop_bit_or: + assert(!"GLSL 1.30 features unsupported"); + break; + } + + this->result = result_src; +} + + +void +ir_to_mesa_visitor::visit(ir_swizzle *ir) +{ + ir_to_mesa_src_reg src_reg; + int i; + int swizzle[4]; + + /* Note that this is only swizzles in expressions, not those on the left + * hand side of an assignment, which do write masking. See ir_assignment + * for that. + */ + + ir->val->accept(this); + src_reg = this->result; + assert(src_reg.file != PROGRAM_UNDEFINED); + + for (i = 0; i < 4; i++) { + if (i < ir->type->vector_elements) { + switch (i) { + case 0: + swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.x); + break; + case 1: + swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.y); + break; + case 2: + swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.z); + break; + case 3: + swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.w); + break; + } + } else { + /* If the type is smaller than a vec4, replicate the last + * channel out. + */ + swizzle[i] = swizzle[ir->type->vector_elements - 1]; + } + } + + src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], + swizzle[1], + swizzle[2], + swizzle[3]); + + this->result = src_reg; +} + +void +ir_to_mesa_visitor::visit(ir_dereference_variable *ir) +{ + variable_storage *entry = find_variable_storage(ir->var); + + if (!entry) { + switch (ir->var->mode) { + case ir_var_uniform: + entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_UNIFORM, + ir->var->location); + this->variables.push_tail(entry); + break; + case ir_var_in: + case ir_var_out: + case ir_var_inout: + /* The linker assigns locations for varyings and attributes, + * including deprecated builtins (like gl_Color), user-assign + * generic attributes (glBindVertexLocation), and + * user-defined varyings. + * + * FINISHME: We would hit this path for function arguments. Fix! + */ + assert(ir->var->location != -1); + if (ir->var->mode == ir_var_in || + ir->var->mode == ir_var_inout) { + entry = new(mem_ctx) variable_storage(ir->var, + PROGRAM_INPUT, + ir->var->location); + + if (this->prog->Target == GL_VERTEX_PROGRAM_ARB && + ir->var->location >= VERT_ATTRIB_GENERIC0) { + _mesa_add_attribute(prog->Attributes, + ir->var->name, + _mesa_sizeof_glsl_type(ir->var->type->gl_type), + ir->var->type->gl_type, + ir->var->location - VERT_ATTRIB_GENERIC0); + } + } else { + entry = new(mem_ctx) variable_storage(ir->var, + PROGRAM_OUTPUT, + ir->var->location); + } + + break; + case ir_var_auto: + case ir_var_temporary: + entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_TEMPORARY, + this->next_temp); + this->variables.push_tail(entry); + + next_temp += type_size(ir->var->type); + break; + } + + if (!entry) { + printf("Failed to make storage for %s\n", ir->var->name); + exit(1); + } + } + + this->result = ir_to_mesa_src_reg(entry->file, entry->index, ir->var->type); +} + +void +ir_to_mesa_visitor::visit(ir_dereference_array *ir) +{ + ir_constant *index; + ir_to_mesa_src_reg src_reg; + int element_size = type_size(ir->type); + + index = ir->array_index->constant_expression_value(); + + ir->array->accept(this); + src_reg = this->result; + + if (index) { + src_reg.index += index->value.i[0] * element_size; + } else { + ir_to_mesa_src_reg array_base = this->result; + /* Variable index array dereference. It eats the "vec4" of the + * base of the array and an index that offsets the Mesa register + * index. + */ + ir->array_index->accept(this); + + ir_to_mesa_src_reg index_reg; + + if (element_size == 1) { + index_reg = this->result; + } else { + index_reg = get_temp(glsl_type::float_type); + + ir_to_mesa_emit_op2(ir, OPCODE_MUL, + ir_to_mesa_dst_reg_from_src(index_reg), + this->result, src_reg_for_float(element_size)); + } + + src_reg.reladdr = talloc(mem_ctx, ir_to_mesa_src_reg); + memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg)); + } + + /* If the type is smaller than a vec4, replicate the last channel out. */ + if (ir->type->is_scalar() || ir->type->is_vector()) + src_reg.swizzle = swizzle_for_size(ir->type->vector_elements); + else + src_reg.swizzle = SWIZZLE_NOOP; + + this->result = src_reg; +} + +void +ir_to_mesa_visitor::visit(ir_dereference_record *ir) +{ + unsigned int i; + const glsl_type *struct_type = ir->record->type; + int offset = 0; + + ir->record->accept(this); + + for (i = 0; i < struct_type->length; i++) { + if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0) + break; + offset += type_size(struct_type->fields.structure[i].type); + } + this->result.swizzle = swizzle_for_size(ir->type->vector_elements); + this->result.index += offset; +} + +/** + * We want to be careful in assignment setup to hit the actual storage + * instead of potentially using a temporary like we might with the + * ir_dereference handler. + */ +static struct ir_to_mesa_dst_reg +get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v) +{ + /* The LHS must be a dereference. If the LHS is a variable indexed array + * access of a vector, it must be separated into a series conditional moves + * before reaching this point (see ir_vec_index_to_cond_assign). + */ + assert(ir->as_dereference()); + ir_dereference_array *deref_array = ir->as_dereference_array(); + if (deref_array) { + assert(!deref_array->array->type->is_vector()); + } + + /* Use the rvalue deref handler for the most part. We'll ignore + * swizzles in it and write swizzles using writemask, though. + */ + ir->accept(v); + return ir_to_mesa_dst_reg_from_src(v->result); +} + +void +ir_to_mesa_visitor::visit(ir_assignment *ir) +{ + struct ir_to_mesa_dst_reg l; + struct ir_to_mesa_src_reg r; + int i; + + ir->rhs->accept(this); + r = this->result; + + l = get_assignment_lhs(ir->lhs, this); + + /* FINISHME: This should really set to the correct maximal writemask for each + * FINISHME: component written (in the loops below). This case can only + * FINISHME: occur for matrices, arrays, and structures. + */ + if (ir->write_mask == 0) { + assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector()); + l.writemask = WRITEMASK_XYZW; + } else if (ir->lhs->type->is_scalar()) { + /* FINISHME: This hack makes writing to gl_FragData, which lives in the + * FINISHME: W component of fragment shader output zero, work correctly. + */ + l.writemask = WRITEMASK_XYZW; + } else { + assert(ir->lhs->type->is_vector()); + l.writemask = ir->write_mask; + } + + assert(l.file != PROGRAM_UNDEFINED); + assert(r.file != PROGRAM_UNDEFINED); + + if (ir->condition) { + ir_to_mesa_src_reg condition; + + ir->condition->accept(this); + condition = this->result; + + /* We use the OPCODE_CMP (a < 0 ? b : c) for conditional moves, + * and the condition we produced is 0.0 or 1.0. By flipping the + * sign, we can choose which value OPCODE_CMP produces without + * an extra computing the condition. + */ + condition.negate = ~condition.negate; + for (i = 0; i < type_size(ir->lhs->type); i++) { + ir_to_mesa_emit_op3(ir, OPCODE_CMP, l, + condition, r, ir_to_mesa_src_reg_from_dst(l)); + l.index++; + r.index++; + } + } else { + for (i = 0; i < type_size(ir->lhs->type); i++) { + ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r); + l.index++; + r.index++; + } + } +} + + +void +ir_to_mesa_visitor::visit(ir_constant *ir) +{ + ir_to_mesa_src_reg src_reg; + GLfloat stack_vals[4] = { 0 }; + GLfloat *values = stack_vals; + unsigned int i; + + /* Unfortunately, 4 floats is all we can get into + * _mesa_add_unnamed_constant. So, make a temp to store an + * aggregate constant and move each constant value into it. If we + * get lucky, copy propagation will eliminate the extra moves. + */ + + if (ir->type->base_type == GLSL_TYPE_STRUCT) { + ir_to_mesa_src_reg temp_base = get_temp(ir->type); + ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base); + + foreach_iter(exec_list_iterator, iter, ir->components) { + ir_constant *field_value = (ir_constant *)iter.get(); + int size = type_size(field_value->type); + + assert(size > 0); + + field_value->accept(this); + src_reg = this->result; + + for (i = 0; i < (unsigned int)size; i++) { + ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg); + + src_reg.index++; + temp.index++; + } + } + this->result = temp_base; + return; + } + + if (ir->type->is_array()) { + ir_to_mesa_src_reg temp_base = get_temp(ir->type); + ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base); + int size = type_size(ir->type->fields.array); + + assert(size > 0); + + for (i = 0; i < ir->type->length; i++) { + ir->array_elements[i]->accept(this); + src_reg = this->result; + for (int j = 0; j < size; j++) { + ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg); + + src_reg.index++; + temp.index++; + } + } + this->result = temp_base; + return; + } + + if (ir->type->is_matrix()) { + ir_to_mesa_src_reg mat = get_temp(ir->type); + ir_to_mesa_dst_reg mat_column = ir_to_mesa_dst_reg_from_src(mat); + + for (i = 0; i < ir->type->matrix_columns; i++) { + assert(ir->type->base_type == GLSL_TYPE_FLOAT); + values = &ir->value.f[i * ir->type->vector_elements]; + + src_reg = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, NULL); + src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters, + values, + ir->type->vector_elements, + &src_reg.swizzle); + ir_to_mesa_emit_op1(ir, OPCODE_MOV, mat_column, src_reg); + + mat_column.index++; + } + + this->result = mat; + return; + } + + src_reg.file = PROGRAM_CONSTANT; + switch (ir->type->base_type) { + case GLSL_TYPE_FLOAT: + values = &ir->value.f[0]; + break; + case GLSL_TYPE_UINT: + for (i = 0; i < ir->type->vector_elements; i++) { + values[i] = ir->value.u[i]; + } + break; + case GLSL_TYPE_INT: + for (i = 0; i < ir->type->vector_elements; i++) { + values[i] = ir->value.i[i]; + } + break; + case GLSL_TYPE_BOOL: + for (i = 0; i < ir->type->vector_elements; i++) { + values[i] = ir->value.b[i]; + } + break; + default: + assert(!"Non-float/uint/int/bool constant"); + } + + this->result = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, ir->type); + this->result.index = _mesa_add_unnamed_constant(this->prog->Parameters, + values, + ir->type->vector_elements, + &this->result.swizzle); +} + +function_entry * +ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig) +{ + function_entry *entry; + + foreach_iter(exec_list_iterator, iter, this->function_signatures) { + entry = (function_entry *)iter.get(); + + if (entry->sig == sig) + return entry; + } + + entry = talloc(mem_ctx, function_entry); + entry->sig = sig; + entry->sig_id = this->next_signature_id++; + entry->bgn_inst = NULL; + + /* Allocate storage for all the parameters. */ + foreach_iter(exec_list_iterator, iter, sig->parameters) { + ir_variable *param = (ir_variable *)iter.get(); + variable_storage *storage; + + storage = find_variable_storage(param); + assert(!storage); + + storage = new(mem_ctx) variable_storage(param, PROGRAM_TEMPORARY, + this->next_temp); + this->variables.push_tail(storage); + + this->next_temp += type_size(param->type); + } + + if (!sig->return_type->is_void()) { + entry->return_reg = get_temp(sig->return_type); + } else { + entry->return_reg = ir_to_mesa_undef; + } + + this->function_signatures.push_tail(entry); + return entry; +} + +void +ir_to_mesa_visitor::visit(ir_call *ir) +{ + ir_to_mesa_instruction *call_inst; + ir_function_signature *sig = ir->get_callee(); + function_entry *entry = get_function_signature(sig); + int i; + + /* Process in parameters. */ + exec_list_iterator sig_iter = sig->parameters.iterator(); + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param_rval = (ir_rvalue *)iter.get(); + ir_variable *param = (ir_variable *)sig_iter.get(); + + if (param->mode == ir_var_in || + param->mode == ir_var_inout) { + variable_storage *storage = find_variable_storage(param); + assert(storage); + + param_rval->accept(this); + ir_to_mesa_src_reg r = this->result; + + ir_to_mesa_dst_reg l; + l.file = storage->file; + l.index = storage->index; + l.reladdr = NULL; + l.writemask = WRITEMASK_XYZW; + l.cond_mask = COND_TR; + + for (i = 0; i < type_size(param->type); i++) { + ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r); + l.index++; + r.index++; + } + } + + sig_iter.next(); + } + assert(!sig_iter.has_next()); + + /* Emit call instruction */ + call_inst = ir_to_mesa_emit_op1(ir, OPCODE_CAL, + ir_to_mesa_undef_dst, ir_to_mesa_undef); + call_inst->function = entry; + + /* Process out parameters. */ + sig_iter = sig->parameters.iterator(); + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param_rval = (ir_rvalue *)iter.get(); + ir_variable *param = (ir_variable *)sig_iter.get(); + + if (param->mode == ir_var_out || + param->mode == ir_var_inout) { + variable_storage *storage = find_variable_storage(param); + assert(storage); + + ir_to_mesa_src_reg r; + r.file = storage->file; + r.index = storage->index; + r.reladdr = NULL; + r.swizzle = SWIZZLE_NOOP; + r.negate = 0; + + param_rval->accept(this); + ir_to_mesa_dst_reg l = ir_to_mesa_dst_reg_from_src(this->result); + + for (i = 0; i < type_size(param->type); i++) { + ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r); + l.index++; + r.index++; + } + } + + sig_iter.next(); + } + assert(!sig_iter.has_next()); + + /* Process return value. */ + this->result = entry->return_reg; +} + +class get_sampler_name : public ir_hierarchical_visitor +{ +public: + get_sampler_name(ir_to_mesa_visitor *mesa, ir_dereference *last) + { + this->mem_ctx = mesa->mem_ctx; + this->mesa = mesa; + this->name = NULL; + this->offset = 0; + this->last = last; + } + + virtual ir_visitor_status visit(ir_dereference_variable *ir) + { + this->name = ir->var->name; + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_dereference_record *ir) + { + this->name = talloc_asprintf(mem_ctx, "%s.%s", name, ir->field); + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_dereference_array *ir) + { + ir_constant *index = ir->array_index->as_constant(); + int i; + + if (index) { + i = index->value.i[0]; + } else { + /* GLSL 1.10 and 1.20 allowed variable sampler array indices, + * while GLSL 1.30 requires that the array indices be + * constant integer expressions. We don't expect any driver + * to actually work with a really variable array index, so + * all that would work would be an unrolled loop counter that ends + * up being constant above. + */ + mesa->shader_program->InfoLog = + talloc_asprintf_append(mesa->shader_program->InfoLog, + "warning: Variable sampler array index " + "unsupported.\nThis feature of the language " + "was removed in GLSL 1.20 and is unlikely " + "to be supported for 1.10 in Mesa.\n"); + i = 0; + } + if (ir != last) { + this->name = talloc_asprintf(mem_ctx, "%s[%d]", name, i); + } else { + offset = i; + } + return visit_continue; + } + + ir_to_mesa_visitor *mesa; + const char *name; + void *mem_ctx; + int offset; + ir_dereference *last; +}; + +int +ir_to_mesa_visitor::get_sampler_uniform_value(ir_dereference *sampler) +{ + get_sampler_name getname(this, sampler); + + sampler->accept(&getname); + + GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1, + getname.name); + + if (index < 0) { + fail_link(this->shader_program, + "failed to find sampler named %s.\n", getname.name); + return 0; + } + + index += getname.offset; + + return this->prog->Parameters->ParameterValues[index][0]; +} + +void +ir_to_mesa_visitor::visit(ir_texture *ir) +{ + ir_to_mesa_src_reg result_src, coord, lod_info, projector; + ir_to_mesa_dst_reg result_dst, coord_dst; + ir_to_mesa_instruction *inst = NULL; + prog_opcode opcode = OPCODE_NOP; + + ir->coordinate->accept(this); + + /* Put our coords in a temp. We'll need to modify them for shadow, + * projection, or LOD, so the only case we'd use it as is is if + * we're doing plain old texturing. Mesa IR optimization should + * handle cleaning up our mess in that case. + */ + coord = get_temp(glsl_type::vec4_type); + coord_dst = ir_to_mesa_dst_reg_from_src(coord); + ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, + this->result); + + if (ir->projector) { + ir->projector->accept(this); + projector = this->result; + } + + /* Storage for our result. Ideally for an assignment we'd be using + * the actual storage for the result here, instead. + */ + result_src = get_temp(glsl_type::vec4_type); + result_dst = ir_to_mesa_dst_reg_from_src(result_src); + + switch (ir->op) { + case ir_tex: + opcode = OPCODE_TEX; + break; + case ir_txb: + opcode = OPCODE_TXB; + ir->lod_info.bias->accept(this); + lod_info = this->result; + break; + case ir_txl: + opcode = OPCODE_TXL; + ir->lod_info.lod->accept(this); + lod_info = this->result; + break; + case ir_txd: + case ir_txf: + assert(!"GLSL 1.30 features unsupported"); + break; + } + + if (ir->projector) { + if (opcode == OPCODE_TEX) { + /* Slot the projector in as the last component of the coord. */ + coord_dst.writemask = WRITEMASK_W; + ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, projector); + coord_dst.writemask = WRITEMASK_XYZW; + opcode = OPCODE_TXP; + } else { + ir_to_mesa_src_reg coord_w = coord; + coord_w.swizzle = SWIZZLE_WWWW; + + /* For the other TEX opcodes there's no projective version + * since the last slot is taken up by lod info. Do the + * projective divide now. + */ + coord_dst.writemask = WRITEMASK_W; + ir_to_mesa_emit_op1(ir, OPCODE_RCP, coord_dst, projector); + + coord_dst.writemask = WRITEMASK_XYZ; + ir_to_mesa_emit_op2(ir, OPCODE_MUL, coord_dst, coord, coord_w); + + coord_dst.writemask = WRITEMASK_XYZW; + coord.swizzle = SWIZZLE_XYZW; + } + } + + if (ir->shadow_comparitor) { + /* Slot the shadow value in as the second to last component of the + * coord. + */ + ir->shadow_comparitor->accept(this); + coord_dst.writemask = WRITEMASK_Z; + ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, this->result); + coord_dst.writemask = WRITEMASK_XYZW; + } + + if (opcode == OPCODE_TXL || opcode == OPCODE_TXB) { + /* Mesa IR stores lod or lod bias in the last channel of the coords. */ + coord_dst.writemask = WRITEMASK_W; + ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, lod_info); + coord_dst.writemask = WRITEMASK_XYZW; + } + + inst = ir_to_mesa_emit_op1(ir, opcode, result_dst, coord); + + if (ir->shadow_comparitor) + inst->tex_shadow = GL_TRUE; + + inst->sampler = get_sampler_uniform_value(ir->sampler); + + const glsl_type *sampler_type = ir->sampler->type; + + switch (sampler_type->sampler_dimensionality) { + case GLSL_SAMPLER_DIM_1D: + inst->tex_target = (sampler_type->sampler_array) + ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX; + break; + case GLSL_SAMPLER_DIM_2D: + inst->tex_target = (sampler_type->sampler_array) + ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX; + break; + case GLSL_SAMPLER_DIM_3D: + inst->tex_target = TEXTURE_3D_INDEX; + break; + case GLSL_SAMPLER_DIM_CUBE: + inst->tex_target = TEXTURE_CUBE_INDEX; + break; + case GLSL_SAMPLER_DIM_RECT: + inst->tex_target = TEXTURE_RECT_INDEX; + break; + case GLSL_SAMPLER_DIM_BUF: + assert(!"FINISHME: Implement ARB_texture_buffer_object"); + break; + default: + assert(!"Should not get here."); + } + + this->result = result_src; +} + +void +ir_to_mesa_visitor::visit(ir_return *ir) +{ + if (ir->get_value()) { + ir_to_mesa_dst_reg l; + int i; + + assert(current_function); + + ir->get_value()->accept(this); + ir_to_mesa_src_reg r = this->result; + + l = ir_to_mesa_dst_reg_from_src(current_function->return_reg); + + for (i = 0; i < type_size(current_function->sig->return_type); i++) { + ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r); + l.index++; + r.index++; + } + } + + ir_to_mesa_emit_op0(ir, OPCODE_RET); +} + +void +ir_to_mesa_visitor::visit(ir_discard *ir) +{ + struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog; + + assert(ir->condition == NULL); /* FINISHME */ + + ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV); + fp->UsesKill = GL_TRUE; +} + +void +ir_to_mesa_visitor::visit(ir_if *ir) +{ + ir_to_mesa_instruction *cond_inst, *if_inst, *else_inst = NULL; + ir_to_mesa_instruction *prev_inst; + + prev_inst = (ir_to_mesa_instruction *)this->instructions.get_tail(); + + ir->condition->accept(this); + assert(this->result.file != PROGRAM_UNDEFINED); + + if (ctx->Shader.EmitCondCodes) { + cond_inst = (ir_to_mesa_instruction *)this->instructions.get_tail(); + + /* See if we actually generated any instruction for generating + * the condition. If not, then cook up a move to a temp so we + * have something to set cond_update on. + */ + if (cond_inst == prev_inst) { + ir_to_mesa_src_reg temp = get_temp(glsl_type::bool_type); + cond_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_MOV, + ir_to_mesa_dst_reg_from_src(temp), + result); + } + cond_inst->cond_update = GL_TRUE; + + if_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_IF); + if_inst->dst_reg.cond_mask = COND_NE; + } else { + if_inst = ir_to_mesa_emit_op1(ir->condition, + OPCODE_IF, ir_to_mesa_undef_dst, + this->result); + } + + this->instructions.push_tail(if_inst); + + visit_exec_list(&ir->then_instructions, this); + + if (!ir->else_instructions.is_empty()) { + else_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_ELSE); + visit_exec_list(&ir->else_instructions, this); + } + + if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF, + ir_to_mesa_undef_dst, ir_to_mesa_undef); +} + +ir_to_mesa_visitor::ir_to_mesa_visitor() +{ + result.file = PROGRAM_UNDEFINED; + next_temp = 1; + next_signature_id = 1; + current_function = NULL; + mem_ctx = talloc_new(NULL); +} + +ir_to_mesa_visitor::~ir_to_mesa_visitor() +{ + talloc_free(mem_ctx); +} + +static struct prog_src_register +mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg) +{ + struct prog_src_register mesa_reg; + + mesa_reg.File = reg.file; + assert(reg.index < (1 << INST_INDEX_BITS) - 1); + mesa_reg.Index = reg.index; + mesa_reg.Swizzle = reg.swizzle; + mesa_reg.RelAddr = reg.reladdr != NULL; + mesa_reg.Negate = reg.negate; + mesa_reg.Abs = 0; + mesa_reg.HasIndex2 = GL_FALSE; + mesa_reg.RelAddr2 = 0; + mesa_reg.Index2 = 0; + + return mesa_reg; +} + +static void +set_branchtargets(ir_to_mesa_visitor *v, + struct prog_instruction *mesa_instructions, + int num_instructions) +{ + int if_count = 0, loop_count = 0; + int *if_stack, *loop_stack; + int if_stack_pos = 0, loop_stack_pos = 0; + int i, j; + + for (i = 0; i < num_instructions; i++) { + switch (mesa_instructions[i].Opcode) { + case OPCODE_IF: + if_count++; + break; + case OPCODE_BGNLOOP: + loop_count++; + break; + case OPCODE_BRK: + case OPCODE_CONT: + mesa_instructions[i].BranchTarget = -1; + break; + default: + break; + } + } + + if_stack = talloc_zero_array(v->mem_ctx, int, if_count); + loop_stack = talloc_zero_array(v->mem_ctx, int, loop_count); + + for (i = 0; i < num_instructions; i++) { + switch (mesa_instructions[i].Opcode) { + case OPCODE_IF: + if_stack[if_stack_pos] = i; + if_stack_pos++; + break; + case OPCODE_ELSE: + mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i; + if_stack[if_stack_pos - 1] = i; + break; + case OPCODE_ENDIF: + mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i; + if_stack_pos--; + break; + case OPCODE_BGNLOOP: + loop_stack[loop_stack_pos] = i; + loop_stack_pos++; + break; + case OPCODE_ENDLOOP: + loop_stack_pos--; + /* Rewrite any breaks/conts at this nesting level (haven't + * already had a BranchTarget assigned) to point to the end + * of the loop. + */ + for (j = loop_stack[loop_stack_pos]; j < i; j++) { + if (mesa_instructions[j].Opcode == OPCODE_BRK || + mesa_instructions[j].Opcode == OPCODE_CONT) { + if (mesa_instructions[j].BranchTarget == -1) { + mesa_instructions[j].BranchTarget = i; + } + } + } + /* The loop ends point at each other. */ + mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos]; + mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i; + break; + case OPCODE_CAL: + foreach_iter(exec_list_iterator, iter, v->function_signatures) { + function_entry *entry = (function_entry *)iter.get(); + + if (entry->sig_id == mesa_instructions[i].BranchTarget) { + mesa_instructions[i].BranchTarget = entry->inst; + break; + } + } + break; + default: + break; + } + } +} + +static void +print_program(struct prog_instruction *mesa_instructions, + ir_instruction **mesa_instruction_annotation, + int num_instructions) +{ + ir_instruction *last_ir = NULL; + int i; + int indent = 0; + + for (i = 0; i < num_instructions; i++) { + struct prog_instruction *mesa_inst = mesa_instructions + i; + ir_instruction *ir = mesa_instruction_annotation[i]; + + fprintf(stdout, "%3d: ", i); + + if (last_ir != ir && ir) { + int j; + + for (j = 0; j < indent; j++) { + fprintf(stdout, " "); + } + ir->print(); + printf("\n"); + last_ir = ir; + + fprintf(stdout, " "); /* line number spacing. */ + } + + indent = _mesa_fprint_instruction_opt(stdout, mesa_inst, indent, + PROG_PRINT_DEBUG, NULL); + } +} + +static void +count_resources(struct gl_program *prog) +{ + unsigned int i; + + prog->SamplersUsed = 0; + + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = &prog->Instructions[i]; + + if (_mesa_is_tex_instruction(inst->Opcode)) { + prog->SamplerTargets[inst->TexSrcUnit] = + (gl_texture_index)inst->TexSrcTarget; + prog->SamplersUsed |= 1 << inst->TexSrcUnit; + if (inst->TexShadow) { + prog->ShadowSamplers |= 1 << inst->TexSrcUnit; + } + } + } + + _mesa_update_shader_textures_used(prog); +} + +struct uniform_sort { + struct gl_uniform *u; + int pos; +}; + +/* The shader_program->Uniforms list is almost sorted in increasing + * uniform->{Frag,Vert}Pos locations, but not quite when there are + * uniforms shared between targets. We need to add parameters in + * increasing order for the targets. + */ +static int +sort_uniforms(const void *a, const void *b) +{ + struct uniform_sort *u1 = (struct uniform_sort *)a; + struct uniform_sort *u2 = (struct uniform_sort *)b; + + return u1->pos - u2->pos; +} + +/* Add the uniforms to the parameters. The linker chose locations + * in our parameters lists (which weren't created yet), which the + * uniforms code will use to poke values into our parameters list + * when uniforms are updated. + */ +static void +add_uniforms_to_parameters_list(struct gl_shader_program *shader_program, + struct gl_shader *shader, + struct gl_program *prog) +{ + unsigned int i; + unsigned int next_sampler = 0, num_uniforms = 0; + struct uniform_sort *sorted_uniforms; + + sorted_uniforms = talloc_array(NULL, struct uniform_sort, + shader_program->Uniforms->NumUniforms); + + for (i = 0; i < shader_program->Uniforms->NumUniforms; i++) { + struct gl_uniform *uniform = shader_program->Uniforms->Uniforms + i; + int parameter_index = -1; + + switch (shader->Type) { + case GL_VERTEX_SHADER: + parameter_index = uniform->VertPos; + break; + case GL_FRAGMENT_SHADER: + parameter_index = uniform->FragPos; + break; + case GL_GEOMETRY_SHADER: + parameter_index = uniform->GeomPos; + break; + } + + /* Only add uniforms used in our target. */ + if (parameter_index != -1) { + sorted_uniforms[num_uniforms].pos = parameter_index; + sorted_uniforms[num_uniforms].u = uniform; + num_uniforms++; + } + } + + qsort(sorted_uniforms, num_uniforms, sizeof(struct uniform_sort), + sort_uniforms); + + for (i = 0; i < num_uniforms; i++) { + struct gl_uniform *uniform = sorted_uniforms[i].u; + int parameter_index = sorted_uniforms[i].pos; + const glsl_type *type = uniform->Type; + unsigned int size; + + if (type->is_vector() || + type->is_scalar()) { + size = type->vector_elements; + } else { + size = type_size(type) * 4; + } + + gl_register_file file; + if (type->is_sampler() || + (type->is_array() && type->fields.array->is_sampler())) { + file = PROGRAM_SAMPLER; + } else { + file = PROGRAM_UNIFORM; + } + + GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1, + uniform->Name); + + if (index < 0) { + index = _mesa_add_parameter(prog->Parameters, file, + uniform->Name, size, type->gl_type, + NULL, NULL, 0x0); + + /* Sampler uniform values are stored in prog->SamplerUnits, + * and the entry in that array is selected by this index we + * store in ParameterValues[]. + */ + if (file == PROGRAM_SAMPLER) { + for (unsigned int j = 0; j < size / 4; j++) + prog->Parameters->ParameterValues[index + j][0] = next_sampler++; + } + + /* The location chosen in the Parameters list here (returned + * from _mesa_add_uniform) has to match what the linker chose. + */ + if (index != parameter_index) { + fail_link(shader_program, "Allocation of uniform `%s' to target " + "failed (%d vs %d)\n", + uniform->Name, index, parameter_index); + } + } + } + + talloc_free(sorted_uniforms); +} + +static void +set_uniform_initializer(GLcontext *ctx, void *mem_ctx, + struct gl_shader_program *shader_program, + const char *name, const glsl_type *type, + ir_constant *val) +{ + if (type->is_record()) { + ir_constant *field_constant; + + field_constant = (ir_constant *)val->components.get_head(); + + for (unsigned int i = 0; i < type->length; i++) { + const glsl_type *field_type = type->fields.structure[i].type; + const char *field_name = talloc_asprintf(mem_ctx, "%s.%s", name, + type->fields.structure[i].name); + set_uniform_initializer(ctx, mem_ctx, shader_program, field_name, + field_type, field_constant); + field_constant = (ir_constant *)field_constant->next; + } + return; + } + + int loc = _mesa_get_uniform_location(ctx, shader_program, name); + + if (loc == -1) { + fail_link(shader_program, + "Couldn't find uniform for initializer %s\n", name); + return; + } + + for (unsigned int i = 0; i < (type->is_array() ? type->length : 1); i++) { + ir_constant *element; + const glsl_type *element_type; + if (type->is_array()) { + element = val->array_elements[i]; + element_type = type->fields.array; + } else { + element = val; + element_type = type; + } + + void *values; + + if (element_type->base_type == GLSL_TYPE_BOOL) { + int *conv = talloc_array(mem_ctx, int, element_type->components()); + for (unsigned int j = 0; j < element_type->components(); j++) { + conv[j] = element->value.b[j]; + } + values = (void *)conv; + element_type = glsl_type::get_instance(GLSL_TYPE_INT, + element_type->vector_elements, + 1); + } else { + values = &element->value; + } + + if (element_type->is_matrix()) { + _mesa_uniform_matrix(ctx, shader_program, + element_type->matrix_columns, + element_type->vector_elements, + loc, 1, GL_FALSE, (GLfloat *)values); + loc += element_type->matrix_columns; + } else { + _mesa_uniform(ctx, shader_program, loc, element_type->matrix_columns, + values, element_type->gl_type); + loc += type_size(element_type); + } + } +} + +static void +set_uniform_initializers(GLcontext *ctx, + struct gl_shader_program *shader_program) +{ + void *mem_ctx = NULL; + + for (unsigned int i = 0; i < shader_program->_NumLinkedShaders; i++) { + struct gl_shader *shader = shader_program->_LinkedShaders[i]; + foreach_iter(exec_list_iterator, iter, *shader->ir) { + ir_instruction *ir = (ir_instruction *)iter.get(); + ir_variable *var = ir->as_variable(); + + if (!var || var->mode != ir_var_uniform || !var->constant_value) + continue; + + if (!mem_ctx) + mem_ctx = talloc_new(NULL); + + set_uniform_initializer(ctx, mem_ctx, shader_program, var->name, + var->type, var->constant_value); + } + } + + talloc_free(mem_ctx); +} + +struct gl_program * +get_mesa_program(GLcontext *ctx, struct gl_shader_program *shader_program, + struct gl_shader *shader) +{ + ir_to_mesa_visitor v; + struct prog_instruction *mesa_instructions, *mesa_inst; + ir_instruction **mesa_instruction_annotation; + int i; + struct gl_program *prog; + GLenum target; + const char *target_string; + GLboolean progress; + + switch (shader->Type) { + case GL_VERTEX_SHADER: + target = GL_VERTEX_PROGRAM_ARB; + target_string = "vertex"; + break; + case GL_FRAGMENT_SHADER: + target = GL_FRAGMENT_PROGRAM_ARB; + target_string = "fragment"; + break; + default: + assert(!"should not be reached"); + return NULL; + } + + validate_ir_tree(shader->ir); + + prog = ctx->Driver.NewProgram(ctx, target, shader_program->Name); + if (!prog) + return NULL; + prog->Parameters = _mesa_new_parameter_list(); + prog->Varying = _mesa_new_parameter_list(); + prog->Attributes = _mesa_new_parameter_list(); + v.ctx = ctx; + v.prog = prog; + v.shader_program = shader_program; + + add_uniforms_to_parameters_list(shader_program, shader, prog); + + /* Emit Mesa IR for main(). */ + visit_exec_list(shader->ir, &v); + v.ir_to_mesa_emit_op0(NULL, OPCODE_END); + + /* Now emit bodies for any functions that were used. */ + do { + progress = GL_FALSE; + + foreach_iter(exec_list_iterator, iter, v.function_signatures) { + function_entry *entry = (function_entry *)iter.get(); + + if (!entry->bgn_inst) { + v.current_function = entry; + + entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_BGNSUB); + entry->bgn_inst->function = entry; + + visit_exec_list(&entry->sig->body, &v); + + ir_to_mesa_instruction *last; + last = (ir_to_mesa_instruction *)v.instructions.get_tail(); + if (last->op != OPCODE_RET) + v.ir_to_mesa_emit_op0(NULL, OPCODE_RET); + + ir_to_mesa_instruction *end; + end = v.ir_to_mesa_emit_op0(NULL, OPCODE_ENDSUB); + end->function = entry; + + progress = GL_TRUE; + } + } + } while (progress); + + prog->NumTemporaries = v.next_temp; + + int num_instructions = 0; + foreach_iter(exec_list_iterator, iter, v.instructions) { + num_instructions++; + } + + mesa_instructions = + (struct prog_instruction *)calloc(num_instructions, + sizeof(*mesa_instructions)); + mesa_instruction_annotation = talloc_array(v.mem_ctx, ir_instruction *, + num_instructions); + + mesa_inst = mesa_instructions; + i = 0; + foreach_iter(exec_list_iterator, iter, v.instructions) { + ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get(); + + mesa_inst->Opcode = inst->op; + mesa_inst->CondUpdate = inst->cond_update; + mesa_inst->DstReg.File = inst->dst_reg.file; + mesa_inst->DstReg.Index = inst->dst_reg.index; + mesa_inst->DstReg.CondMask = inst->dst_reg.cond_mask; + mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask; + mesa_inst->DstReg.RelAddr = inst->dst_reg.reladdr != NULL; + mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]); + mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]); + mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]); + mesa_inst->TexSrcUnit = inst->sampler; + mesa_inst->TexSrcTarget = inst->tex_target; + mesa_inst->TexShadow = inst->tex_shadow; + mesa_instruction_annotation[i] = inst->ir; + + /* Set IndirectRegisterFiles. */ + if (mesa_inst->DstReg.RelAddr) + prog->IndirectRegisterFiles |= 1 << mesa_inst->DstReg.File; + + for (unsigned src = 0; src < 3; src++) + if (mesa_inst->SrcReg[src].RelAddr) + prog->IndirectRegisterFiles |= 1 << mesa_inst->SrcReg[src].File; + + if (ctx->Shader.EmitNoIfs && mesa_inst->Opcode == OPCODE_IF) { + fail_link(shader_program, "Couldn't flatten if statement\n"); + } + + switch (mesa_inst->Opcode) { + case OPCODE_BGNSUB: + inst->function->inst = i; + mesa_inst->Comment = strdup(inst->function->sig->function_name()); + break; + case OPCODE_ENDSUB: + mesa_inst->Comment = strdup(inst->function->sig->function_name()); + break; + case OPCODE_CAL: + mesa_inst->BranchTarget = inst->function->sig_id; /* rewritten later */ + break; + case OPCODE_ARL: + prog->NumAddressRegs = 1; + break; + default: + break; + } + + mesa_inst++; + i++; + } + + set_branchtargets(&v, mesa_instructions, num_instructions); + + if (ctx->Shader.Flags & GLSL_DUMP) { + printf("\n"); + printf("GLSL IR for linked %s program %d:\n", target_string, + shader_program->Name); + _mesa_print_ir(shader->ir, NULL); + printf("\n"); + printf("\n"); + printf("Mesa IR for linked %s program %d:\n", target_string, + shader_program->Name); + print_program(mesa_instructions, mesa_instruction_annotation, + num_instructions); + } + + prog->Instructions = mesa_instructions; + prog->NumInstructions = num_instructions; + + do_set_program_inouts(shader->ir, prog); + count_resources(prog); + + _mesa_reference_program(ctx, &shader->Program, prog); + + if ((ctx->Shader.Flags & GLSL_NO_OPT) == 0) { + _mesa_optimize_program(ctx, prog); + } + + return prog; +} + +extern "C" { +GLboolean +_mesa_ir_compile_shader(GLcontext *ctx, struct gl_shader *shader) +{ + assert(shader->CompileStatus); + (void) ctx; + + return GL_TRUE; +} + +GLboolean +_mesa_ir_link_shader(GLcontext *ctx, struct gl_shader_program *prog) +{ + assert(prog->LinkStatus); + + for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { + bool progress; + exec_list *ir = prog->_LinkedShaders[i]->ir; + + do { + progress = false; + + /* Lowering */ + do_mat_op_to_vec(ir); + do_mod_to_fract(ir); + do_div_to_mul_rcp(ir); + do_explog_to_explog2(ir); + + progress = do_common_optimization(ir, true) || progress; + + if (ctx->Shader.EmitNoIfs) + progress = do_if_to_cond_assign(ir) || progress; + + progress = do_vec_index_to_cond_assign(ir) || progress; + } while (progress); + + validate_ir_tree(ir); + } + + for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { + struct gl_program *linked_prog; + bool ok = true; + + linked_prog = get_mesa_program(ctx, prog, prog->_LinkedShaders[i]); + + switch (prog->_LinkedShaders[i]->Type) { + case GL_VERTEX_SHADER: + _mesa_reference_vertprog(ctx, &prog->VertexProgram, + (struct gl_vertex_program *)linked_prog); + ok = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, + linked_prog); + break; + case GL_FRAGMENT_SHADER: + _mesa_reference_fragprog(ctx, &prog->FragmentProgram, + (struct gl_fragment_program *)linked_prog); + ok = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, + linked_prog); + break; + } + if (!ok) { + return GL_FALSE; + } + _mesa_reference_program(ctx, &linked_prog, NULL); + } + + return GL_TRUE; +} + +void +_mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) +{ + struct _mesa_glsl_parse_state *state = + new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader); + + const char *source = shader->Source; + state->error = preprocess(state, &source, &state->info_log, + &ctx->Extensions); + + if (ctx->Shader.Flags & GLSL_DUMP) { + printf("GLSL source for shader %d:\n", shader->Name); + printf("%s\n", shader->Source); + } + + if (!state->error) { + _mesa_glsl_lexer_ctor(state, source); + _mesa_glsl_parse(state); + _mesa_glsl_lexer_dtor(state); + } + + talloc_free(shader->ir); + shader->ir = new(shader) exec_list; + if (!state->error && !state->translation_unit.is_empty()) + _mesa_ast_to_hir(shader->ir, state); + + if (!state->error && !shader->ir->is_empty()) { + validate_ir_tree(shader->ir); + + /* Do some optimization at compile time to reduce shader IR size + * and reduce later work if the same shader is linked multiple times + */ + while (do_common_optimization(shader->ir, false)) + ; + + validate_ir_tree(shader->ir); + } + + shader->symbols = state->symbols; + + shader->CompileStatus = !state->error; + shader->InfoLog = state->info_log; + shader->Version = state->language_version; + memcpy(shader->builtins_to_link, state->builtins_to_link, + sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link); + shader->num_builtins_to_link = state->num_builtins_to_link; + + if (ctx->Shader.Flags & GLSL_LOG) { + _mesa_write_shader_to_file(shader); + } + + if (ctx->Shader.Flags & GLSL_DUMP) { + if (shader->CompileStatus) { + printf("GLSL IR for shader %d:\n", shader->Name); + _mesa_print_ir(shader->ir, NULL); + printf("\n\n"); + } else { + printf("GLSL shader %d failed to compile.\n", shader->Name); + } + if (shader->InfoLog && shader->InfoLog[0] != 0) { + printf("GLSL shader %d info log:\n", shader->Name); + printf("%s\n", shader->InfoLog); + } + } + + /* Retain any live IR, but trash the rest. */ + reparent_ir(shader->ir, shader->ir); + + talloc_free(state); + + if (shader->CompileStatus) { + if (!ctx->Driver.CompileShader(ctx, shader)) + shader->CompileStatus = GL_FALSE; + } +} + +void +_mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog) +{ + unsigned int i; + + _mesa_clear_shader_program_data(ctx, prog); + + prog->LinkStatus = GL_TRUE; + + for (i = 0; i < prog->NumShaders; i++) { + if (!prog->Shaders[i]->CompileStatus) { + fail_link(prog, "linking with uncompiled shader"); + prog->LinkStatus = GL_FALSE; + } + } + + prog->Varying = _mesa_new_parameter_list(); + _mesa_reference_vertprog(ctx, &prog->VertexProgram, NULL); + _mesa_reference_fragprog(ctx, &prog->FragmentProgram, NULL); + + if (prog->LinkStatus) { + link_shaders(ctx, prog); + } + + if (prog->LinkStatus) { + if (!ctx->Driver.LinkShader(ctx, prog)) { + prog->LinkStatus = GL_FALSE; + } + } + + set_uniform_initializers(ctx, prog); + + if (ctx->Shader.Flags & GLSL_DUMP) { + if (!prog->LinkStatus) { + printf("GLSL shader program %d failed to link\n", prog->Name); + } + + if (prog->InfoLog && prog->InfoLog[0] != 0) { + printf("GLSL shader program %d info log:\n", prog->Name); + printf("%s\n", prog->InfoLog); + } + } +} + +} /* extern "C" */ diff --git a/src/mesa/program/ir_to_mesa.h b/src/mesa/program/ir_to_mesa.h new file mode 100644 index 0000000000..ecaacde4bb --- /dev/null +++ b/src/mesa/program/ir_to_mesa.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "main/config.h" +#include "main/mtypes.h" + +void _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *sh); +void _mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog); +GLboolean _mesa_ir_compile_shader(GLcontext *ctx, struct gl_shader *shader); +GLboolean _mesa_ir_link_shader(GLcontext *ctx, struct gl_shader_program *prog); + +#ifdef __cplusplus +} +#endif diff --git a/src/mesa/program/prog_execute.c b/src/mesa/program/prog_execute.c index 1670c91b6a..2ae5bc572a 100644 --- a/src/mesa/program/prog_execute.c +++ b/src/mesa/program/prog_execute.c @@ -771,6 +771,13 @@ _mesa_execute_program(GLcontext * ctx, result[2] = a[2] < 0.0F ? b[2] : c[2]; result[3] = a[3] < 0.0F ? b[3] : c[3]; store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("CMP (%g %g %g %g) = (%g %g %g %g) < 0 ? (%g %g %g %g) : (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3], + c[0], c[1], c[2], c[3]); + } } break; case OPCODE_COS: @@ -1679,6 +1686,22 @@ _mesa_execute_program(GLcontext * ctx, store_vector4(inst, machine, color); } break; + case OPCODE_TXL: + /* Texel lookup with explicit LOD */ + { + GLfloat texcoord[4], color[4], lod; + + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + + /* texcoord[3] is the LOD */ + lod = texcoord[3]; + + machine->FetchTexelLod(ctx, texcoord, lod, + machine->Samplers[inst->TexSrcUnit], color); + + store_vector4(inst, machine, color); + } + break; case OPCODE_TXP: /* GL_ARB_fragment_program only */ /* Texture lookup w/ projective divide */ { @@ -1842,7 +1865,11 @@ _mesa_execute_program(GLcontext * ctx, numExec++; if (numExec > maxExec) { - _mesa_problem(ctx, "Infinite loop detected in fragment program"); + static GLboolean reported = GL_FALSE; + if (!reported) { + _mesa_problem(ctx, "Infinite loop detected in fragment program"); + reported = GL_TRUE; + } return GL_TRUE; } diff --git a/src/mesa/program/prog_instruction.h b/src/mesa/program/prog_instruction.h index 098b366ab5..ca90de7ce1 100644 --- a/src/mesa/program/prog_instruction.h +++ b/src/mesa/program/prog_instruction.h @@ -401,7 +401,7 @@ struct prog_instruction /** * For BRA and CAL instructions, the location to jump to. * For BGNLOOP, points to ENDLOOP (and vice-versa). - * For BRK, points to BGNLOOP (which points to ENDLOOP). + * For BRK, points to ENDLOOP * For IF, points to ELSE or ENDIF. * For ELSE, points to ENDIF. */ diff --git a/src/mesa/program/prog_optimize.c b/src/mesa/program/prog_optimize.c index c78187c983..0dc779073d 100644 --- a/src/mesa/program/prog_optimize.c +++ b/src/mesa/program/prog_optimize.c @@ -34,7 +34,12 @@ #define MAX_LOOP_NESTING 50 - +/* MAX_PROGRAM_TEMPS is a low number (256), and we want to be able to + * register allocate many temporary values into that small number of + * temps. So allow large temporary indices coming into the register + * allocator. + */ +#define REG_ALLOCATE_MAX_PROGRAM_TEMPS ((1 << INST_INDEX_BITS) - 1) static GLboolean dbg = GL_FALSE; @@ -233,7 +238,7 @@ replace_regs(struct gl_program *prog, gl_register_file file, const GLint map[]) static GLboolean _mesa_remove_dead_code_global(struct gl_program *prog) { - GLboolean tempRead[MAX_PROGRAM_TEMPS][4]; + GLboolean tempRead[REG_ALLOCATE_MAX_PROGRAM_TEMPS][4]; GLboolean *removeInst; /* per-instruction removal flag */ GLuint i, rem = 0, comp; @@ -258,7 +263,7 @@ _mesa_remove_dead_code_global(struct gl_program *prog) if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { const GLuint index = inst->SrcReg[j].Index; GLuint read_mask; - ASSERT(index < MAX_PROGRAM_TEMPS); + ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); read_mask = get_src_arg_mask(inst, j, NO_MASK); if (inst->SrcReg[j].RelAddr) { @@ -281,7 +286,7 @@ _mesa_remove_dead_code_global(struct gl_program *prog) /* check dst reg */ if (inst->DstReg.File == PROGRAM_TEMPORARY) { const GLuint index = inst->DstReg.Index; - ASSERT(index < MAX_PROGRAM_TEMPS); + ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); if (inst->DstReg.RelAddr) { if (dbg) @@ -753,7 +758,11 @@ _mesa_remove_extra_moves(struct gl_program *prog) nesting--; break; case OPCODE_MOV: - if (i > 0 && can_downward_mov_be_modifed(mov) && nesting == 0) { + if (i > 0 && + can_downward_mov_be_modifed(mov) && + mov->SrcReg[0].File == PROGRAM_TEMPORARY && + nesting == 0) + { /* see if this MOV can be removed */ const GLuint id = mov->SrcReg[0].Index; @@ -826,7 +835,7 @@ struct interval struct interval_list { GLuint Num; - struct interval Intervals[MAX_PROGRAM_TEMPS]; + struct interval Intervals[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; }; @@ -913,15 +922,33 @@ sort_interval_list_by_start(struct interval_list *list) #endif } +struct loop_info +{ + GLuint Start, End; /**< Start, end instructions of loop */ +}; /** * Update the intermediate interval info for register 'index' and * instruction 'ic'. */ static void -update_interval(GLint intBegin[], GLint intEnd[], GLuint index, GLuint ic) +update_interval(GLint intBegin[], GLint intEnd[], + struct loop_info *loopStack, GLuint loopStackDepth, + GLuint index, GLuint ic) { - ASSERT(index < MAX_PROGRAM_TEMPS); + int i; + + /* If the register is used in a loop, extend its lifetime through the end + * of the outermost loop that doesn't contain its definition. + */ + for (i = 0; i < loopStackDepth; i++) { + if (intBegin[index] < loopStack[i].Start) { + ic = loopStack[i].End; + break; + } + } + + ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); if (intBegin[index] == -1) { ASSERT(intEnd[index] == -1); intBegin[index] = intEnd[index] = ic; @@ -938,18 +965,14 @@ update_interval(GLint intBegin[], GLint intEnd[], GLuint index, GLuint ic) GLboolean _mesa_find_temp_intervals(const struct prog_instruction *instructions, GLuint numInstructions, - GLint intBegin[MAX_PROGRAM_TEMPS], - GLint intEnd[MAX_PROGRAM_TEMPS]) + GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS], + GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS]) { - struct loop_info - { - GLuint Start, End; /**< Start, end instructions of loop */ - }; struct loop_info loopStack[MAX_LOOP_NESTING]; GLuint loopStackDepth = 0; GLuint i; - for (i = 0; i < MAX_PROGRAM_TEMPS; i++){ + for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){ intBegin[i] = intEnd[i] = -1; } @@ -975,24 +998,16 @@ _mesa_find_temp_intervals(const struct prog_instruction *instructions, const GLuint index = inst->SrcReg[j].Index; if (inst->SrcReg[j].RelAddr) return GL_FALSE; - update_interval(intBegin, intEnd, index, i); - if (loopStackDepth > 0) { - /* extend temp register's interval to end of loop */ - GLuint loopEnd = loopStack[loopStackDepth - 1].End; - update_interval(intBegin, intEnd, index, loopEnd); - } + update_interval(intBegin, intEnd, loopStack, loopStackDepth, + index, i); } } if (inst->DstReg.File == PROGRAM_TEMPORARY) { const GLuint index = inst->DstReg.Index; if (inst->DstReg.RelAddr) return GL_FALSE; - update_interval(intBegin, intEnd, index, i); - if (loopStackDepth > 0) { - /* extend temp register's interval to end of loop */ - GLuint loopEnd = loopStack[loopStackDepth - 1].End; - update_interval(intBegin, intEnd, index, loopEnd); - } + update_interval(intBegin, intEnd, loopStack, loopStackDepth, + index, i); } } } @@ -1012,7 +1027,8 @@ static GLboolean find_live_intervals(struct gl_program *prog, struct interval_list *liveIntervals) { - GLint intBegin[MAX_PROGRAM_TEMPS], intEnd[MAX_PROGRAM_TEMPS]; + GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; + GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; GLuint i; /* @@ -1032,7 +1048,7 @@ find_live_intervals(struct gl_program *prog, /* Build live intervals list from intermediate arrays */ liveIntervals->Num = 0; - for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { + for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) { if (intBegin[i] >= 0) { struct interval inv; inv.Reg = i; @@ -1068,10 +1084,10 @@ find_live_intervals(struct gl_program *prog, /** Scan the array of used register flags to find free entry */ static GLint -alloc_register(GLboolean usedRegs[MAX_PROGRAM_TEMPS]) +alloc_register(GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS]) { GLuint k; - for (k = 0; k < MAX_PROGRAM_TEMPS; k++) { + for (k = 0; k < REG_ALLOCATE_MAX_PROGRAM_TEMPS; k++) { if (!usedRegs[k]) { usedRegs[k] = GL_TRUE; return k; @@ -1093,8 +1109,8 @@ static void _mesa_reallocate_registers(struct gl_program *prog) { struct interval_list liveIntervals; - GLint registerMap[MAX_PROGRAM_TEMPS]; - GLboolean usedRegs[MAX_PROGRAM_TEMPS]; + GLint registerMap[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; + GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; GLuint i; GLint maxTemp = -1; @@ -1103,7 +1119,7 @@ _mesa_reallocate_registers(struct gl_program *prog) _mesa_print_program(prog); } - for (i = 0; i < MAX_PROGRAM_TEMPS; i++){ + for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){ registerMap[i] = -1; usedRegs[i] = GL_FALSE; } diff --git a/src/mesa/program/prog_parameter.c b/src/mesa/program/prog_parameter.c index aac488c79a..6bf8a081b0 100644 --- a/src/mesa/program/prog_parameter.c +++ b/src/mesa/program/prog_parameter.c @@ -284,93 +284,6 @@ _mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, return pos; } - -/** - * Add a uniform to the parameter list. - * Note that if the uniform is an array, size may be greater than - * what's implied by the datatype. - * \param name uniform's name - * \param size number of floats to allocate - * \param datatype GL_FLOAT_VEC3, GL_FLOAT_MAT4, etc. - */ -GLint -_mesa_add_uniform(struct gl_program_parameter_list *paramList, - const char *name, GLuint size, GLenum datatype, - const GLfloat *values) -{ - GLint i = _mesa_lookup_parameter_index(paramList, -1, name); - ASSERT(datatype != GL_NONE); - if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_UNIFORM) { - ASSERT(paramList->Parameters[i].Size == size); - ASSERT(paramList->Parameters[i].DataType == datatype); - /* already in list */ - return i; - } - else { - i = _mesa_add_parameter(paramList, PROGRAM_UNIFORM, name, - size, datatype, values, NULL, 0x0); - return i; - } -} - - -/** - * Mark the named uniform as 'used'. - */ -void -_mesa_use_uniform(struct gl_program_parameter_list *paramList, - const char *name) -{ - GLuint i; - for (i = 0; i < paramList->NumParameters; i++) { - struct gl_program_parameter *p = paramList->Parameters + i; - if ((p->Type == PROGRAM_UNIFORM || p->Type == PROGRAM_SAMPLER) && - strcmp(p->Name, name) == 0) { - p->Used = GL_TRUE; - /* Note that large uniforms may occupy several slots so we're - * not done searching yet. - */ - } - } -} - - -/** - * Add a sampler to the parameter list. - * \param name uniform's name - * \param datatype GL_SAMPLER_2D, GL_SAMPLER_2D_RECT_ARB, etc. - * \param index the sampler number (as seen in TEX instructions) - * \return sampler index (starting at zero) or -1 if error - */ -GLint -_mesa_add_sampler(struct gl_program_parameter_list *paramList, - const char *name, GLenum datatype) -{ - GLint i = _mesa_lookup_parameter_index(paramList, -1, name); - if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_SAMPLER) { - ASSERT(paramList->Parameters[i].Size == 1); - ASSERT(paramList->Parameters[i].DataType == datatype); - /* already in list */ - return (GLint) paramList->ParameterValues[i][0]; - } - else { - GLuint i; - const GLint size = 1; /* a sampler is basically a texture unit number */ - GLfloat value[4]; - GLint numSamplers = 0; - for (i = 0; i < paramList->NumParameters; i++) { - if (paramList->Parameters[i].Type == PROGRAM_SAMPLER) - numSamplers++; - } - value[0] = (GLfloat) numSamplers; - value[1] = value[2] = value[3] = 0.0F; - (void) _mesa_add_parameter(paramList, PROGRAM_SAMPLER, name, - size, datatype, value, NULL, 0x0); - return numSamplers; - } -} - - /** * Add parameter representing a varying variable. */ @@ -569,8 +482,10 @@ _mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list, assert(vSize >= 1); assert(vSize <= 4); - if (!list) - return -1; + if (!list) { + *posOut = -1; + return GL_FALSE; + } for (i = 0; i < list->NumParameters; i++) { if (list->Parameters[i].Type == PROGRAM_CONSTANT) { @@ -591,7 +506,7 @@ _mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list, if (vSize == 1) { /* look for v[0] anywhere within float[4] value */ GLuint j; - for (j = 0; j < 4; j++) { + for (j = 0; j < list->Parameters[i].Size; j++) { if (list->ParameterValues[i][j] == v[0]) { /* found it */ *posOut = i; @@ -657,7 +572,6 @@ _mesa_clone_parameter_list(const struct gl_program_parameter_list *list) list->ParameterValues[i], NULL, 0x0); ASSERT(j >= 0); pCopy = clone->Parameters + j; - pCopy->Used = p->Used; pCopy->Flags = p->Flags; /* copy state indexes */ if (p->Type == PROGRAM_STATE_VAR) { diff --git a/src/mesa/program/prog_parameter.h b/src/mesa/program/prog_parameter.h index cc3378ae20..10cbbe57a6 100644 --- a/src/mesa/program/prog_parameter.h +++ b/src/mesa/program/prog_parameter.h @@ -64,8 +64,7 @@ struct gl_program_parameter * The next program parameter's Size will be Size-4 of this parameter. */ GLuint Size; - GLboolean Used; /**< Helper flag for GLSL uniform tracking */ - GLboolean Initialized; /**< Has the ParameterValue[] been set? */ + GLboolean Initialized; /**< debug: Has the ParameterValue[] been set? */ GLbitfield Flags; /**< Bitmask of PROG_PARAM_*_BIT */ /** * A sequence of STATE_* tokens and integers to identify GL state. @@ -132,19 +131,6 @@ _mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, GLuint *swizzleOut); extern GLint -_mesa_add_uniform(struct gl_program_parameter_list *paramList, - const char *name, GLuint size, GLenum datatype, - const GLfloat *values); - -extern void -_mesa_use_uniform(struct gl_program_parameter_list *paramList, - const char *name); - -extern GLint -_mesa_add_sampler(struct gl_program_parameter_list *paramList, - const char *name, GLenum datatype); - -extern GLint _mesa_add_varying(struct gl_program_parameter_list *paramList, const char *name, GLuint size, GLenum datatype, GLbitfield flags); diff --git a/src/mesa/program/prog_print.c b/src/mesa/program/prog_print.c index 6056c459e4..00aa6de963 100644 --- a/src/mesa/program/prog_print.c +++ b/src/mesa/program/prog_print.c @@ -540,12 +540,12 @@ fprint_comment(FILE *f, const struct prog_instruction *inst) } -static void -fprint_alu_instruction(FILE *f, - const struct prog_instruction *inst, - const char *opcode_string, GLuint numRegs, - gl_prog_print_mode mode, - const struct gl_program *prog) +void +_mesa_fprint_alu_instruction(FILE *f, + const struct prog_instruction *inst, + const char *opcode_string, GLuint numRegs, + gl_prog_print_mode mode, + const struct gl_program *prog) { GLuint j; @@ -582,8 +582,8 @@ void _mesa_print_alu_instruction(const struct prog_instruction *inst, const char *opcode_string, GLuint numRegs) { - fprint_alu_instruction(stderr, inst, opcode_string, - numRegs, PROG_PRINT_DEBUG, NULL); + _mesa_fprint_alu_instruction(stderr, inst, opcode_string, + numRegs, PROG_PRINT_DEBUG, NULL); } @@ -791,16 +791,16 @@ _mesa_fprint_instruction_opt(FILE *f, default: if (inst->Opcode < MAX_OPCODE) { /* typical alu instruction */ - fprint_alu_instruction(f, inst, - _mesa_opcode_string(inst->Opcode), - _mesa_num_inst_src_regs(inst->Opcode), - mode, prog); + _mesa_fprint_alu_instruction(f, inst, + _mesa_opcode_string(inst->Opcode), + _mesa_num_inst_src_regs(inst->Opcode), + mode, prog); } else { - fprint_alu_instruction(f, inst, - _mesa_opcode_string(inst->Opcode), - 3/*_mesa_num_inst_src_regs(inst->Opcode)*/, - mode, prog); + _mesa_fprint_alu_instruction(f, inst, + _mesa_opcode_string(inst->Opcode), + 3/*_mesa_num_inst_src_regs(inst->Opcode)*/, + mode, prog); } break; } @@ -1033,11 +1033,11 @@ _mesa_write_shader_to_file(const struct gl_shader *shader) fprintf(f, "/* Compile status: %s */\n", shader->CompileStatus ? "ok" : "fail"); - if (!shader->CompileStatus) { - fprintf(f, "/* Log Info: */\n"); + fprintf(f, "/* Log Info: */\n"); + if (shader->InfoLog) { fputs(shader->InfoLog, f); } - else { + if (shader->CompileStatus && shader->Program) { fprintf(f, "/* GPU code */\n"); fprintf(f, "/*\n"); _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE); diff --git a/src/mesa/program/prog_print.h b/src/mesa/program/prog_print.h index 4667373f37..78b90aeb4d 100644 --- a/src/mesa/program/prog_print.h +++ b/src/mesa/program/prog_print.h @@ -66,6 +66,13 @@ extern void _mesa_print_swizzle(GLuint swizzle); extern void +_mesa_fprint_alu_instruction(FILE *f, + const struct prog_instruction *inst, + const char *opcode_string, GLuint numRegs, + gl_prog_print_mode mode, + const struct gl_program *prog); + +extern void _mesa_print_alu_instruction(const struct prog_instruction *inst, const char *opcode_string, GLuint numRegs); diff --git a/src/mesa/program/prog_uniform.c b/src/mesa/program/prog_uniform.c index 5aa9878d43..28acb8871a 100644 --- a/src/mesa/program/prog_uniform.c +++ b/src/mesa/program/prog_uniform.c @@ -44,6 +44,10 @@ void _mesa_free_uniform_list(struct gl_uniform_list *list) { GLuint i; + + if (!list) + return; + for (i = 0; i < list->NumUniforms; i++) { free((void *) list->Uniforms[i].Name); } diff --git a/src/mesa/program/prog_uniform.h b/src/mesa/program/prog_uniform.h index 7988d534a7..67f78006ea 100644 --- a/src/mesa/program/prog_uniform.h +++ b/src/mesa/program/prog_uniform.h @@ -51,10 +51,7 @@ struct gl_uniform GLint FragPos; GLint GeomPos; GLboolean Initialized; /**< For debug. Has this uniform been set? */ -#if 0 - GLenum DataType; /**< GL_FLOAT, GL_FLOAT_VEC2, etc */ - GLuint Size; /**< Number of components (1..4) */ -#endif + const struct glsl_type *Type; }; diff --git a/src/mesa/program/symbol_table.c b/src/mesa/program/symbol_table.c index 6a5d686897..09e7cb44ef 100644 --- a/src/mesa/program/symbol_table.c +++ b/src/mesa/program/symbol_table.c @@ -58,7 +58,9 @@ struct symbol { */ int name_space; - + /** Scope depth where this symbol was defined. */ + unsigned depth; + /** * Arbitrary user supplied data. */ @@ -73,7 +75,7 @@ struct symbol_header { struct symbol_header *next; /** Symbol name. */ - const char *name; + char *name; /** Linked list of symbols with the same name. */ struct symbol *symbols; @@ -104,6 +106,9 @@ struct _mesa_symbol_table { /** List of all symbol headers in the table. */ struct symbol_header *hdr; + + /** Current scope depth. */ + unsigned depth; }; @@ -157,6 +162,7 @@ _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table) struct symbol *sym = scope->symbols; table->current_scope = scope->next; + table->depth--; free(scope); @@ -184,6 +190,7 @@ _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table) scope->next = table->current_scope; table->current_scope = scope; + table->depth++; } @@ -261,6 +268,36 @@ _mesa_symbol_table_iterator_next(struct _mesa_symbol_table_iterator *iter) } +/** + * Determine the scope "distance" of a symbol from the current scope + * + * \return + * A non-negative number for the number of scopes between the current scope + * and the scope where a symbol was defined. A value of zero means the current + * scope. A negative number if the symbol does not exist. + */ +int +_mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table, + int name_space, const char *name) +{ + struct symbol_header *const hdr = find_symbol(table, name); + struct symbol *sym; + + if (hdr != NULL) { + for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { + assert(sym->hdr == hdr); + + if ((name_space == -1) || (sym->name_space == name_space)) { + assert(sym->depth <= table->depth); + return sym->depth - table->depth; + } + } + } + + return -1; +} + + void * _mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table, int name_space, const char *name) @@ -300,21 +337,34 @@ _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table, if (hdr == NULL) { hdr = calloc(1, sizeof(*hdr)); - hdr->name = name; + hdr->name = strdup(name); - hash_table_insert(table->ht, hdr, name); + hash_table_insert(table->ht, hdr, hdr->name); hdr->next = table->hdr; table->hdr = hdr; } check_symbol_table(table); + /* If the symbol already exists in this namespace at this scope, it cannot + * be added to the table. + */ + for (sym = hdr->symbols + ; (sym != NULL) && (sym->name_space != name_space) + ; sym = sym->next_with_same_name) { + /* empty */ + } + + if (sym && (sym->depth == table->depth)) + return -1; + sym = calloc(1, sizeof(*sym)); sym->next_with_same_name = hdr->symbols; sym->next_with_same_scope = table->current_scope->symbols; sym->hdr = hdr; sym->name_space = name_space; sym->data = declaration; + sym->depth = table->depth; assert(sym->hdr == hdr); @@ -354,6 +404,7 @@ _mesa_symbol_table_dtor(struct _mesa_symbol_table *table) for (hdr = table->hdr; hdr != NULL; hdr = next) { next = hdr->next; + free(hdr->name); free(hdr); } diff --git a/src/mesa/program/symbol_table.h b/src/mesa/program/symbol_table.h index 0c054ef139..1d570fc1a0 100644 --- a/src/mesa/program/symbol_table.h +++ b/src/mesa/program/symbol_table.h @@ -33,6 +33,9 @@ extern void _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table); extern int _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *symtab, int name_space, const char *name, void *declaration); +extern int _mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table, + int name_space, const char *name); + extern void *_mesa_symbol_table_find_symbol( struct _mesa_symbol_table *symtab, int name_space, const char *name); diff --git a/src/mesa/slang/descrip.mms b/src/mesa/slang/descrip.mms deleted file mode 100644 index 674b786ac0..0000000000 --- a/src/mesa/slang/descrip.mms +++ /dev/null @@ -1,67 +0,0 @@ -# Makefile for core library for VMS -# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl -# Last revision : 3 October 2007 - -.first - define gl [----.include.gl] - define math [--.math] - define swrast [--.swrast] - define array_cache [--.array_cache] - define main [--.main] - define glapi [--.glapi] - define shader [--.shader] - -.include [----]mms-config. - -##### MACROS ##### - -VPATH = RCS - -INCDIR = [----.include],[--.main],[--.glapi],[-.slang],[-] -LIBDIR = [----.lib] -CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm - -SOURCES = \ - slang_compile.c - -OBJECTS = slang_builtin.obj,slang_codegen.obj,slang_compile.obj,\ - slang_compile_function.obj,slang_compile_operation.obj,\ - slang_compile_struct.obj,slang_compile_variable.obj,slang_emit.obj,\ - slang_ir.obj,slang_label.obj,slang_library_noise.obj,slang_link.obj,\ - slang_log.obj,slang_mem.obj,slang_preprocess.obj,slang_print.obj,\ - slang_simplify.obj,slang_storage.obj,slang_typeinfo.obj,\ - slang_utility.obj,slang_vartable.obj - -##### RULES ##### - -VERSION=Mesa V3.4 - -##### TARGETS ##### -# Make the library -$(LIBDIR)$(GL_LIB) : $(OBJECTS) - @ library $(LIBDIR)$(GL_LIB) $(OBJECTS) - -clean : - purge - delete *.obj;* - -slang_builtin.obj : slang_builtin.c -slang_codegen.obj : slang_codegen.c -slang_compile.obj : slang_compile.c -slang_compile_function.obj : slang_compile_function.c -slang_compile_operation.obj : slang_compile_operation.c -slang_compile_struct.obj : slang_compile_struct.c -slang_compile_variable.obj : slang_compile_variable.c -slang_emit.obj : slang_emit.c -slang_ir.obj : slang_ir.c -slang_label.obj : slang_label.c -slang_library_noise.obj : slang_library_noise.c -slang_link.obj : slang_link.c -slang_log.obj : slang_log.c -slang_mem.obj : slang_mem.c -slang_print.obj : slang_print.c -slang_simplify.obj : slang_simplify.c -slang_storage.obj : slang_storage.c -slang_typeinfo.obj : slang_typeinfo.c -slang_utility.obj : slang_utility.c -slang_vartable.obj : slang_vartable.c diff --git a/src/mesa/slang/library/.gitignore b/src/mesa/slang/library/.gitignore deleted file mode 100644 index 02a89fc7df..0000000000 --- a/src/mesa/slang/library/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*_gc.h diff --git a/src/mesa/slang/library/Makefile b/src/mesa/slang/library/Makefile deleted file mode 100644 index f546a03907..0000000000 --- a/src/mesa/slang/library/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -# src/mesa/slang/library/Makefile - -TOP = ../../../.. - -include $(TOP)/configs/current - -GLSL_CL = $(TOP)/src/glsl/apps/compile - -# -# targets -# - -.PHONY: default clean - -default: builtin - -clean: - -rm -f *_gc.h - -builtin: builtin_110 builtin_120 - -# -# builtin library sources -# - -builtin_110: slang_common_builtin_gc.h slang_core_gc.h slang_fragment_builtin_gc.h slang_vertex_builtin_gc.h slang_geometry_builtin_gc.h - -builtin_120: slang_120_core_gc.h slang_builtin_120_common_gc.h slang_builtin_120_fragment_gc.h - - -slang_120_core_gc.h: slang_120_core.gc - $(GLSL_CL) fragment slang_120_core.gc slang_120_core_gc.h - -slang_builtin_120_common_gc.h: slang_builtin_120_common.gc - $(GLSL_CL) fragment slang_builtin_120_common.gc slang_builtin_120_common_gc.h - -slang_builtin_120_fragment_gc.h: slang_builtin_120_fragment.gc - $(GLSL_CL) fragment slang_builtin_120_fragment.gc slang_builtin_120_fragment_gc.h - -slang_common_builtin_gc.h: slang_common_builtin.gc - $(GLSL_CL) fragment slang_common_builtin.gc slang_common_builtin_gc.h - -slang_core_gc.h: slang_core.gc - $(GLSL_CL) fragment slang_core.gc slang_core_gc.h - -slang_fragment_builtin_gc.h: slang_fragment_builtin.gc - $(GLSL_CL) fragment slang_fragment_builtin.gc slang_fragment_builtin_gc.h - -slang_vertex_builtin_gc.h: slang_vertex_builtin.gc - $(GLSL_CL) vertex slang_vertex_builtin.gc slang_vertex_builtin_gc.h - -slang_geometry_builtin_gc.h: slang_geometry_builtin.gc - $(GLSL_CL) geometry slang_geometry_builtin.gc slang_geometry_builtin_gc.h - diff --git a/src/mesa/slang/library/SConscript b/src/mesa/slang/library/SConscript deleted file mode 100644 index 5112cefb3e..0000000000 --- a/src/mesa/slang/library/SConscript +++ /dev/null @@ -1,62 +0,0 @@ -####################################################################### -# SConscript for GLSL builtin library - -Import('*') - -env = env.Clone() - -# See also http://www.scons.org/wiki/UsingCodeGenerators - -def glsl_compile_emitter(target, source, env): - env.Depends(target, glsl_compile) - return (target, source) - -bld_frag = Builder( - action = Action(glsl_compile[0].abspath + ' fragment $SOURCE $TARGET', '$CODEGENCODESTR'), - emitter = glsl_compile_emitter, - suffix = '.gc', - src_suffix = '_gc.h') - -bld_vert = Builder( - action = Action(glsl_compile[0].abspath + ' vertex $SOURCE $TARGET', '$CODEGENCODESTR'), - emitter = glsl_compile_emitter, - suffix = '.gc', - src_suffix = '_gc.h') - -bld_geom = Builder( - action = Action(glsl_compile[0].abspath + ' geometry $SOURCE $TARGET', '$CODEGENCODESTR'), - emitter = glsl_compile_emitter, - suffix = '.gc', - src_suffix = '_gc.h') - -env['BUILDERS']['bld_frag'] = bld_frag -env['BUILDERS']['bld_vert'] = bld_vert -env['BUILDERS']['bld_geom'] = bld_geom - -# Generate GLSL builtin library binaries -env.bld_frag( - '#src/mesa/slang/library/slang_core_gc.h', - '#src/mesa/slang/library/slang_core.gc') -env.bld_frag( - '#src/mesa/slang/library/slang_common_builtin_gc.h', - '#src/mesa/slang/library/slang_common_builtin.gc') -env.bld_frag( - '#src/mesa/slang/library/slang_fragment_builtin_gc.h', - '#src/mesa/slang/library/slang_fragment_builtin.gc') -env.bld_vert( - '#src/mesa/slang/library/slang_vertex_builtin_gc.h', - '#src/mesa/slang/library/slang_vertex_builtin.gc') -env.bld_geom( - '#src/mesa/slang/library/slang_geometry_builtin_gc.h', - '#src/mesa/slang/library/slang_geometry_builtin.gc') - -# Generate GLSL 1.20 builtin library binaries -env.bld_frag( - '#src/mesa/slang/library/slang_120_core_gc.h', - '#src/mesa/slang/library/slang_120_core.gc') -env.bld_frag( - '#src/mesa/slang/library/slang_builtin_120_common_gc.h', - '#src/mesa/slang/library/slang_builtin_120_common.gc') -env.bld_frag( - '#src/mesa/slang/library/slang_builtin_120_fragment_gc.h', - '#src/mesa/slang/library/slang_builtin_120_fragment.gc') diff --git a/src/mesa/slang/library/slang_120_core.gc b/src/mesa/slang/library/slang_120_core.gc deleted file mode 100644 index 04c5ec2ec5..0000000000 --- a/src/mesa/slang/library/slang_120_core.gc +++ /dev/null @@ -1,1978 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -// -// Constructors and operators introduced in GLSL 1.20 - mostly on new -// (non-square) types of matrices. -// -// One important change in the language is that when a matrix is used -// as an argument to a matrix constructor, it must be the only argument -// for the constructor. The compiler takes care of it by itself and -// here we only care to re-introduce constructors for old (square) -// types of matrices. -// - -// -// From Shader Spec, ver. 1.20, rev. 6 -// - -//// mat2x3: 2 columns of vec3 - -mat2x3 __constructor(const float f00, const float f10, const float f20, - const float f01, const float f11, const float f21) -{ - __retVal[0].x = f00; - __retVal[0].y = f10; - __retVal[0].z = f20; - __retVal[1].x = f01; - __retVal[1].y = f11; - __retVal[1].z = f21; -} - -mat2x3 __constructor(const float f) -{ - __retVal = mat2x3( f, 0.0, 0.0, - 0.0, f, 0.0); -} - -mat2x3 __constructor(const int i) -{ - const float f = float(i); - __retVal = mat2x3(f); -} - -mat2x3 __constructor(const bool b) -{ - const float f = float(b); - __retVal = mat2x3(f); -} - -mat2x3 __constructor(const vec3 c0, const vec3 c1) -{ - __retVal[0] = c0; - __retVal[1] = c1; -} - - - -//// mat2x4: 2 columns of vec4 - -mat2x4 __constructor(const float f00, const float f10, const float f20, const float f30, - const float f01, const float f11, const float f21, const float f31) -{ - __retVal[0].x = f00; - __retVal[0].y = f10; - __retVal[0].z = f20; - __retVal[0].w = f30; - __retVal[1].x = f01; - __retVal[1].y = f11; - __retVal[1].z = f21; - __retVal[1].w = f31; -} - -mat2x4 __constructor(const float f) -{ - __retVal = mat2x4( f, 0.0, 0.0, 0.0, - 0.0, f, 0.0, 0.0); -} - -mat2x4 __constructor(const int i) -{ - const float f = float(i); - __retVal = mat2x4(f); -} - -mat2x4 __constructor(const bool b) -{ - const float f = float(b); - __retVal = mat2x4(f); -} - -mat2x4 __constructor(const vec4 c0, const vec4 c1) -{ - __retVal[0] = c0; - __retVal[1] = c1; -} - - - -//// mat3x2: 3 columns of vec2 - -mat3x2 __constructor(const float f00, const float f10, - const float f01, const float f11, - const float f02, const float f12) -{ - __retVal[0].x = f00; - __retVal[0].y = f10; - __retVal[1].x = f01; - __retVal[1].y = f11; - __retVal[2].x = f02; - __retVal[2].y = f12; -} - -mat3x2 __constructor(const float f) -{ - __retVal = mat3x2( f, 0.0, - 0.0, f, - 0.0, 0.0); -} - -mat3x2 __constructor(const int i) -{ - const float f = float(i); - __retVal = mat3x2(f); -} - -mat3x2 __constructor(const bool b) -{ - const float f = float(b); - __retVal = mat3x2(f); -} - -mat3x2 __constructor(const vec2 c0, const vec2 c1, const vec2 c2) -{ - __retVal[0] = c0; - __retVal[1] = c1; - __retVal[2] = c2; -} - - - -//// mat3x4: 3 columns of vec4 - -mat3x4 __constructor(const float f00, const float f10, const float f20, const float f30, - const float f01, const float f11, const float f21, const float f31, - const float f02, const float f12, const float f22, const float f32) -{ - __retVal[0].x = f00; - __retVal[0].y = f10; - __retVal[0].z = f20; - __retVal[0].w = f30; - __retVal[1].x = f01; - __retVal[1].y = f11; - __retVal[1].z = f21; - __retVal[1].w = f31; - __retVal[2].x = f02; - __retVal[2].y = f12; - __retVal[2].z = f22; - __retVal[2].w = f32; -} - -mat3x4 __constructor(const float f) -{ - __retVal = mat3x4( f, 0.0, 0.0, 0.0, - 0.0, f, 0.0, 0.0, - 0.0, 0.0, f, 0.0); -} - -mat3x4 __constructor(const int i) -{ - const float f = float(i); - __retVal = mat3x4(f); -} - -mat3x4 __constructor(const bool b) -{ - const float f = float(b); - __retVal = mat3x4(f); -} - -mat3x4 __constructor(const vec4 c0, const vec4 c1, const vec4 c2) -{ - __retVal[0] = c0; - __retVal[1] = c1; - __retVal[2] = c2; -} - - - -//// mat4x2: 4 columns of vec2 - -mat4x2 __constructor(const float f00, const float f10, - const float f01, const float f11, - const float f02, const float f12, - const float f03, const float f13) -{ - __retVal[0].x = f00; - __retVal[0].y = f10; - __retVal[1].x = f01; - __retVal[1].y = f11; - __retVal[2].x = f02; - __retVal[2].y = f12; - __retVal[3].x = f03; - __retVal[3].y = f13; -} - -mat4x2 __constructor(const float f) -{ - __retVal = mat4x2( f, 0.0, - 0.0, 4, - 0.0, 0.0, - 0.0, 0.0); -} - -mat4x2 __constructor(const int i) -{ - const float f = float(i); - __retVal = mat4x2(f); -} - -mat4x2 __constructor(const bool b) -{ - const float f = float(b); - __retVal = mat4x2(f); -} - -mat4x2 __constructor(const vec2 c0, const vec2 c1, const vec2 c2, const vec2 c3) -{ - __retVal[0] = c0; - __retVal[1] = c1; - __retVal[2] = c2; - __retVal[3] = c3; -} - - - -//// mat4x3: 4 columns of vec3 - -mat4x3 __constructor(const float f00, const float f10, const float f20, - const float f01, const float f11, const float f21, - const float f02, const float f12, const float f22, - const float f03, const float f13, const float f23) -{ - __retVal[0].x = f00; - __retVal[0].y = f10; - __retVal[0].z = f20; - __retVal[1].x = f01; - __retVal[1].y = f11; - __retVal[1].z = f21; - __retVal[2].x = f02; - __retVal[2].y = f12; - __retVal[2].z = f22; - __retVal[3].x = f03; - __retVal[3].y = f13; - __retVal[3].z = f23; -} - -mat4x3 __constructor(const float f) -{ - __retVal = mat4x3( f, 0.0, 0.0, - 0.0, f, 0.0, - 0.0, 0.0, f, - 0.0, 0.0, 0.0); -} - -mat4x3 __constructor(const int i) -{ - const float f = float(i); - __retVal = mat4x3(f); -} - -mat4x3 __constructor(const bool b) -{ - const float f = float(b); - __retVal = mat4x3(f); -} - -mat4x3 __constructor(const vec3 c0, const vec3 c1, const vec3 c2, const vec3 c3) -{ - __retVal[0] = c0; - __retVal[1] = c1; - __retVal[2] = c2; - __retVal[3] = c3; -} - - - -//// misc assorted matrix constructors - -mat2 __constructor(const mat2 m) -{ - __retVal = m; -} - -mat2 __constructor(const mat3x2 m) -{ - __retVal = mat2(m[0], m[1]); -} - -mat2 __constructor(const mat4x2 m) -{ - __retVal = mat2(m[0], m[1]); -} - -mat2 __constructor(const mat2x3 m) -{ - __retVal = mat2(m[0].xy, m[1].xy); -} - -mat2 __constructor(const mat2x4 m) -{ - __retVal = mat2(m[0].xy, m[1].xy); -} - -mat2 __constructor(const mat3 m) -{ - __retVal = mat2(m[0].xy, m[1].xy); -} - -mat2 __constructor(const mat3x4 m) -{ - __retVal = mat2(m[0].xy, m[1].xy); -} - -mat2 __constructor(const mat4x3 m) -{ - __retVal = mat2(m[0].xy, m[1].xy); -} - -mat2 __constructor(const mat4 m) -{ - __retVal = mat2(m[0].xy, m[1].xy); -} - - - -mat2x3 __constructor(const mat2x3 m) -{ - __retVal = m; -} - -mat2x3 __constructor(const mat3 m) -{ - __retVal = mat2x3(m[0], m[1]); -} - -mat2x3 __constructor(const mat4x3 m) -{ - __retVal = mat2x3(m[0], m[1]); -} - -mat2x3 __constructor(const mat2x4 m) -{ - __retVal = mat2x3(m[0].xyz, m[1].xyz); -} - -mat2x3 __constructor(const mat3x4 m) -{ - __retVal = mat2x3(m[0].xyz, m[1].xyz); -} - -mat2x3 __constructor(const mat4 m) -{ - __retVal = mat2x3(m[0].xyz, m[1].xyz); -} - -mat2x3 __constructor(const mat2 m) -{ - __retVal = mat2x3(m[0].x, m[0].y, 0.0, - m[1].x, m[1].y, 0.0); -} - -mat2x3 __constructor(const mat3x2 m) -{ - __retVal = mat2x3(m[0].x, m[0].y, 0.0, - m[1].x, m[1].y, 0.0); -} - -mat2x3 __constructor(const mat4x2 m) -{ - __retVal = mat2x3(m[0].x, m[0].y, 0.0, - m[1].x, m[1].y, 0.0); -} - - - -mat2x4 __constructor(const mat2x4 m) -{ - __retVal = m; -} - -mat2x4 __constructor(const mat3x4 m) -{ - __retVal = mat2x4(m[0], m[1]); -} - -mat2x4 __constructor(const mat4 m) -{ - __retVal = mat2x4(m[0], m[1]); -} - -mat2x4 __constructor(const mat2x3 m) -{ - __retVal = mat2x4(m[0].x, m[0].y, m[0].z, 0.0, - m[1].x, m[1].y, m[1].z, 0.0); -} - -mat2x4 __constructor(const mat3 m) -{ - __retVal = mat2x4(m[0].x, m[0].y, m[0].z, 0.0, - m[1].x, m[1].y, m[1].z, 0.0); -} - -mat2x4 __constructor(const mat4x3 m) -{ - __retVal = mat2x4(m[0].x, m[0].y, m[0].z, 0.0, - m[1].x, m[1].y, m[1].z, 0.0); -} - -mat2x4 __constructor(const mat2 m) -{ - __retVal = mat2x4(m[0].x, m[1].y, 0.0, 0.0, - m[1].x, m[1].y, 0.0, 0.0); -} - -mat2x4 __constructor(const mat3x2 m) -{ - __retVal = mat2x4(m[0].x, m[0].y, 0.0, 0.0, - m[1].x, m[1].y, 0.0, 0.0); -} - -mat2x4 __constructor(const mat4x2 m) -{ - __retVal = mat2x4(m[0].x, m[0].y, 0.0, 0.0, - m[1].x, m[1].y, 0.0, 0.0); -} - - - -mat3x2 __constructor(const mat3x2 m) -{ - __retVal = m; -} - -mat3x2 __constructor(const mat4x2 m) -{ - __retVal = mat3x2(m[0], m[1], m[2]); -} - -mat3x2 __constructor(const mat3 m) -{ - __retVal = mat3x2(m[0], m[1], m[2]); -} - -mat3x2 __constructor(const mat3x4 m) -{ - __retVal = mat3x2(m[0].x, m[0].y, - m[1].x, m[1].y, - m[2].x, m[2].y); -} - -mat3x2 __constructor(const mat4x3 m) -{ - __retVal = mat3x2(m[0].x, m[0].y, - m[1].x, m[1].y, - m[2].x, m[2].y); -} - -mat3x2 __constructor(const mat4 m) -{ - __retVal = mat3x2(m[0].x, m[0].y, - m[1].x, m[1].y, - 0.0, 0.0); -} - -mat3x2 __constructor(const mat2 m) -{ - __retVal = mat3x2(m[0], m[1], vec2(0.0)); -} - -mat3x2 __constructor(const mat2x3 m) -{ - __retVal = mat3x2(m[0].x, m[0].y, - m[1].x, m[1].y, - 0.0, 0.0); -} - -mat3x2 __constructor(const mat2x4 m) -{ - __retVal = mat3x2(m[0].x, m[0].y, - m[1].x, m[1].y, - 0.0, 0.0); -} - - - - -mat3 __constructor(const mat3 m) -{ - __retVal = m; -} - -mat3 __constructor(const mat4x3 m) -{ - __retVal = mat3 ( - m[0], - m[1], - m[2] - ); -} - -mat3 __constructor(const mat3x4 m) -{ - __retVal = mat3 ( - m[0].xyz, - m[1].xyz, - m[2].xyz - ); -} - -mat3 __constructor(const mat4 m) -{ - __retVal = mat3 ( - m[0].xyz, - m[1].xyz, - m[2].xyz - ); -} - -mat3 __constructor(const mat2x3 m) -{ - __retVal = mat3 ( - m[0], - m[1], - 0., 0., 1. - ); -} - -mat3 __constructor(const mat2x4 m) -{ - __retVal = mat3 ( - m[0].xyz, - m[1].xyz, - 0., 0., 1. - ); -} - -mat3 __constructor(const mat3x2 m) -{ - __retVal = mat3 ( - m[0], 0., - m[1], 0., - m[2], 1. - ); -} - -mat3 __constructor(const mat4x2 m) -{ - __retVal = mat3 ( - m[0], 0., - m[1], 0., - m[2], 1. - ); -} - -mat3 __constructor(const mat2 m) -{ - __retVal = mat3 ( - m[0], 0., - m[1], 0., - 0., 0., 1. - ); -} - - -mat3x4 __constructor(const mat3x4 m) -{ - __retVal = m; -} - -mat3x4 __constructor(const mat4 m) -{ - __retVal = mat3x4 ( - m[0], - m[1], - m[2] - ); -} - -mat3x4 __constructor(const mat3 m) -{ - __retVal = mat3x4 ( - m[0], 0., - m[1], 0., - m[2], 0. - ); -} - -mat3x4 __constructor(const mat4x3 m) -{ - __retVal = mat3x4 ( - m[0], 0., - m[1], 0., - m[2], 0. - ); -} - -mat3x4 __constructor(const mat2x4 m) -{ - __retVal = mat3x4 ( - m[0], - m[1], - 0., 0., 1., 0. - ); -} - -mat3x4 __constructor(const mat2x3 m) -{ - __retVal = mat3x4 ( - m[0], 0., - m[1], 0., - 0., 0., 1., 0. - ); -} - -mat3x4 __constructor(const mat3x2 m) -{ - __retVal = mat3x4 ( - m[0], 0., 0., - m[1], 0., 0., - m[2], 1., 0. - ); -} - -mat3x4 __constructor(const mat4x2 m) -{ - __retVal = mat3x4 ( - m[0], 0., 0., - m[1], 0., 0., - m[2], 1., 0. - ); -} - -mat3x4 __constructor(const mat2 m) -{ - __retVal = mat3x4 ( - m[0], 0., 0., - m[1], 0., 0., - 0., 0., 1., 0. - ); -} - - -mat4x2 __constructor(const mat4x2 m) -{ - __retVal = m; -} - -mat4x2 __constructor(const mat4x3 m) -{ - __retVal = mat4x2 ( - m[0].xy, - m[1].xy, - m[2].xy, - m[3].xy - ); -} - -mat4x2 __constructor(const mat4 m) -{ - __retVal = mat4x2 ( - m[0].xy, - m[1].xy, - m[2].xy, - m[3].xy - ); -} - -mat4x2 __constructor(const mat3x2 m) -{ - __retVal = mat4x2 ( - m[0], - m[1], - 0., 0. - ); -} - -mat4x2 __constructor(const mat3 m) -{ - __retVal = mat4x2 ( - m[0].xy, - m[1].xy, - m[2].xy, - 0., 0. - ); -} - -mat4x2 __constructor(const mat3x4 m) -{ - __retVal = mat4x2 ( - m[0].xy, - m[1].xy, - m[2].xy, - 0., 0. - ); -} - -mat4x2 __constructor(const mat2 m) -{ - __retVal = mat4x2 ( - m[0], - m[1], - 0., 0., - 0., 0. - ); -} - -mat4x2 __constructor(const mat2x3 m) -{ - __retVal = mat4x2 ( - m[0].xy, - m[1].xy, - 0., 0., - 0., 0. - ); -} - -mat4x2 __constructor(const mat2x4 m) -{ - __retVal = mat4x2 ( - m[0].xy, - m[1].xy, - 0., 0., - 0., 0. - ); -} - - -mat4x3 __constructor(const mat4x3 m) -{ - __retVal = m; -} - -mat4x3 __constructor(const mat4 m) -{ - __retVal = mat4x3 ( - m[0].xyz, - m[1].xyz, - m[2].xyz, - m[3].xyz - ); -} - -mat4x3 __constructor(const mat3 m) -{ - __retVal = mat4x3 ( - m[0], - m[1], - m[2], - 0., 0., 0. - ); -} - -mat4x3 __constructor(const mat3x4 m) -{ - __retVal = mat4x3 ( - m[0].xyz, - m[1].xyz, - m[2].xyz, - 0., 0., 0. - ); -} - -mat4x3 __constructor(const mat4x2 m) -{ - __retVal = mat4x3 ( - m[0], 0., - m[1], 0., - m[2], 1., - m[3], 0. - ); -} - -mat4x3 __constructor(const mat2x3 m) -{ - __retVal = mat4x3 ( - m[0], - m[1], - 0., 0., 1., - 0., 0., 0. - ); -} - -mat4x3 __constructor(const mat3x2 m) -{ - __retVal = mat4x3 ( - m[0], 0., - m[1], 0., - m[2], 1., - 0., 0., 0. - ); -} - -mat4x3 __constructor(const mat2x4 m) -{ - __retVal = mat4x3 ( - m[0].xyz, - m[1].xyz, - 0., 0., 1., - 0., 0., 0. - ); -} - -mat4x3 __constructor(const mat2 m) -{ - __retVal = mat4x3 ( - m[0], 0., - m[1], 0., - 0., 0., 1., - 0., 0., 0. - ); -} - - -mat4 __constructor(const mat4 m) -{ - __retVal = m; -} - -mat4 __constructor(const mat3x4 m) -{ - __retVal = mat4 ( - m[0], - m[1], - m[2], - 0., 0., 0., 1. - ); -} - -mat4 __constructor(const mat4x3 m) -{ - __retVal = mat4 ( - m[0], 0., - m[1], 0., - m[2], 0., - m[3], 1. - ); -} - -mat4 __constructor(const mat2x4 m) -{ - __retVal = mat4 ( - m[0], - m[1], - 0., 0., 1., 0., - 0., 0., 0., 1. - ); -} - -mat4 __constructor(const mat4x2 m) -{ - __retVal = mat4 ( - m[0], 0., 0., - m[1], 0., 0., - m[2], 1., 0., - m[3], 0., 1. - ); -} - -mat4 __constructor(const mat3 m) -{ - __retVal = mat4 ( - m[0], 0., - m[1], 0., - m[2], 0., - 0., 0., 0., 1. - ); -} - -mat4 __constructor(const mat2x3 m) -{ - __retVal = mat4 ( - m[0], 0., - m[1], 0., - 0., 0., 1., 0., - 0., 0., 0., 1. - ); -} - -mat4 __constructor(const mat3x2 m) -{ - __retVal = mat4 ( - m[0], 0., 0., - m[1], 0., 0., - m[2], 1., 0., - 0., 0., 0., 1. - ); -} - -mat4 __constructor(const mat2 m) -{ - __retVal = mat4 ( - m[0], 0., 0., - m[1], 0., 0., - 0., 0., 1., 0., - 0., 0., 0., 1. - ); -} - - -void __operator += (inout mat2x3 m, const mat2x3 n) { - m[0] += n[0]; - m[1] += n[1]; -} - -void __operator += (inout mat2x4 m, const mat2x4 n) { - m[0] += n[0]; - m[1] += n[1]; -} - -void __operator += (inout mat3x2 m, const mat3x2 n) { - m[0] += n[0]; - m[1] += n[1]; - m[2] += n[2]; -} - -void __operator += (inout mat3x4 m, const mat3x4 n) { - m[0] += n[0]; - m[1] += n[1]; - m[2] += n[2]; -} - -void __operator += (inout mat4x2 m, const mat4x2 n) { - m[0] += n[0]; - m[1] += n[1]; - m[2] += n[2]; - m[3] += n[3]; -} - -void __operator += (inout mat4x3 m, const mat4x3 n) { - m[0] += n[0]; - m[1] += n[1]; - m[2] += n[2]; - m[3] += n[3]; -} - - -void __operator -= (inout mat2x3 m, const mat2x3 n) { - m[0] -= n[0]; - m[1] -= n[1]; -} - -void __operator -= (inout mat2x4 m, const mat2x4 n) { - m[0] -= n[0]; - m[1] -= n[1]; -} - -void __operator -= (inout mat3x2 m, const mat3x2 n) { - m[0] -= n[0]; - m[1] -= n[1]; - m[2] -= n[2]; -} - -void __operator -= (inout mat3x4 m, const mat3x4 n) { - m[0] -= n[0]; - m[1] -= n[1]; - m[2] -= n[2]; -} - -void __operator -= (inout mat4x2 m, const mat4x2 n) { - m[0] -= n[0]; - m[1] -= n[1]; - m[2] -= n[2]; - m[3] -= n[3]; -} - -void __operator -= (inout mat4x3 m, const mat4x3 n) { - m[0] -= n[0]; - m[1] -= n[1]; - m[2] -= n[2]; - m[3] -= n[3]; -} - - -void __operator /= (inout mat2x3 m, const mat2x3 n) { - m[0] /= n[0]; - m[1] /= n[1]; -} - -void __operator /= (inout mat2x4 m, const mat2x4 n) { - m[0] /= n[0]; - m[1] /= n[1]; -} - -void __operator /= (inout mat3x2 m, const mat3x2 n) { - m[0] /= n[0]; - m[1] /= n[1]; - m[2] /= n[2]; -} - -void __operator /= (inout mat3x4 m, const mat3x4 n) { - m[0] /= n[0]; - m[1] /= n[1]; - m[2] /= n[2]; -} - -void __operator /= (inout mat4x2 m, const mat4x2 n) { - m[0] /= n[0]; - m[1] /= n[1]; - m[2] /= n[2]; - m[3] /= n[3]; -} - -void __operator /= (inout mat4x3 m, const mat4x3 n) { - m[0] /= n[0]; - m[1] /= n[1]; - m[2] /= n[2]; - m[3] /= n[3]; -} - - -vec3 __operator * (const mat2x3 m, const vec2 v) -{ - __retVal.x = v.x * m[0].x + v.y * m[1].x; - __retVal.y = v.x * m[0].y + v.y * m[1].y; - __retVal.z = v.x * m[0].z + v.y * m[1].z; -} - -vec4 __operator * (const mat2x4 m, const vec2 v) -{ - __retVal.x = v.x * m[0].x + v.y * m[1].x; - __retVal.y = v.x * m[0].y + v.y * m[1].y; - __retVal.z = v.x * m[0].z + v.y * m[1].z; - __retVal.w = v.x * m[0].w + v.y * m[1].w; -} - -vec2 __operator * (const mat3x2 m, const vec3 v) -{ - __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x; - __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y; -} - -vec4 __operator * (const mat3x4 m, const vec3 v) -{ - __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x; - __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y; - __retVal.z = v.x * m[0].z + v.y * m[1].z + v.z * m[2].z; - __retVal.w = v.x * m[0].w + v.y * m[1].w + v.z * m[2].w; -} - -vec2 __operator * (const mat4x2 m, const vec4 v) -{ - __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x + v.w * m[3].x; - __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y + v.w * m[3].y; -} - -vec3 __operator * (const mat4x3 m, const vec4 v) -{ - __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x + v.w * m[3].x; - __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y + v.w * m[3].y; - __retVal.z = v.x * m[0].z + v.y * m[1].z + v.z * m[2].z + v.w * m[3].z; -} - - -mat3x2 __operator * (const mat2 m, const mat3x2 n) -{ - //return mat3x2 (m * n[0], m * n[1], m * n[2]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; -} - -mat4x2 __operator * (const mat2 m, const mat4x2 n) -{ - //return mat4x2 (m * n[0], m * n[1], m * n[2], m * n[3]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; - __retVal[3] = m * n[3]; -} - - -mat2x3 __operator * (const mat2x3 m, const mat2 n) -{ - //return mat2x3 (m * n[0], m * n[1]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; -} - -mat3 __operator * (const mat2x3 m, const mat3x2 n) -{ - //return mat3 (m * n[0], m * n[1], m * n[2]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; -} - -mat4x3 __operator * (const mat2x3 m, const mat4x2 n) -{ - //return mat4x3 (m * n[0], m * n[1], m * n[2], m * n[3]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; - __retVal[3] = m * n[3]; -} - - -mat2x4 __operator * (const mat2x4 m, const mat2 n) -{ - //return mat2x4 (m * n[0], m * n[1]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; -} - -mat3x4 __operator * (const mat2x4 m, const mat3x2 n) -{ - //return mat3x4 (m * n[0], m * n[1], m * n[2]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; -} - -mat4 __operator * (const mat2x4 m, const mat4x2 n) -{ - //return mat4 (m * n[0], m * n[1], m * n[2], m * n[3]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; - __retVal[3] = m * n[3]; -} - - -mat2 __operator * (const mat3x2 m, const mat2x3 n) -{ - //return mat2 (m * n[0], m * n[1]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; -} - -mat3x2 __operator * (const mat3x2 m, const mat3 n) -{ - //return mat3x2 (m * n[0], m * n[1], m * n[2]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; -} - -mat4x2 __operator * (const mat3x2 m, const mat4x3 n) -{ - //return mat4x2 (m * n[0], m * n[1], m * n[2], m * n[3]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; - __retVal[3] = m * n[3]; -} - - -mat2x3 __operator * (const mat3 m, const mat2x3 n) -{ - //return mat2x3 (m * n[0], m * n[1]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; -} - -mat4x3 __operator * (const mat3 m, const mat4x3 n) -{ - //return mat4x3 (m * n[0], m * n[1], m * n[2], m * n[3]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; - __retVal[3] = m * n[3]; -} - - -mat2x4 __operator * (const mat3x4 m, const mat2x3 n) -{ - //return mat2x4 (m * n[0], m * n[1]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; -} - -mat3x4 __operator * (const mat3x4 m, const mat3 n) -{ - //return mat3x4 (m * n[0], m * n[1], m * n[2]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; -} - -mat4 __operator * (const mat3x4 m, const mat4x3 n) -{ - //return mat4 (m * n[0], m * n[1], m * n[2], m * n[3]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; - __retVal[3] = m * n[3]; -} - - -mat2 __operator * (const mat4x2 m, const mat2x4 n) -{ - //return = mat2 (m * n[0], m * n[1]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; -} - -mat3x2 __operator * (const mat4x2 m, const mat3x4 n) -{ - //return mat3x2 (m * n[0], m * n[1], m * n[2]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; -} - -mat4x2 __operator * (const mat4x2 m, const mat4 n) -{ - //return mat4x2 (m * n[0], m * n[1], m * n[2], m * n[3]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; - __retVal[3] = m * n[3]; -} - - -mat2x3 __operator * (const mat4x3 m, const mat2x4 n) -{ - //return mat2x3 (m * n[0], m * n[1]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; -} - -mat3 __operator * (const mat4x3 m, const mat3x4 n) -{ - //return mat3 (m * n[0], m * n[1], m * n[2]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; -} - -mat4x3 __operator * (const mat4x3 m, const mat4 n) -{ - //return mat4x3 (m * n[0], m * n[1], m * n[2], m * n[3]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; - __retVal[3] = m * n[3]; -} - - -mat2x4 __operator * (const mat4 m, const mat2x4 n) -{ - //return mat2x4 (m * n[0], m * n[1]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; -} - -mat3x4 __operator * (const mat4 m, const mat3x4 n) -{ - //return mat3x4 (m * n[0], m * n[1], m * n[2]); - __retVal[0] = m * n[0]; - __retVal[1] = m * n[1]; - __retVal[2] = m * n[2]; -} - - -void __operator *= (inout mat2x3 m, const mat2 n) { - m = m * n; -} - -void __operator *= (inout mat2x4 m, const mat2 n) { - m = m * n; -} - -void __operator *= (inout mat3x2 m, const mat3 n) { - m = m * n; -} - -void __operator *= (inout mat3x4 m, const mat3 n) { - m = m * n; -} - -void __operator *= (inout mat4x2 m, const mat4 n) { - m = m * n; -} - -void __operator *= (inout mat4x3 m, const mat4 n) { - m = m * n; -} - - -vec3 __operator * (const vec2 v, const mat3x2 m) -{ - __retVal.x = dot(v, m[0]); - __retVal.y = dot(v, m[1]); - __retVal.z = dot(v, m[2]); -} - -vec4 __operator * (const vec2 v, const mat4x2 m) -{ - __retVal.x = dot(v, m[0]); - __retVal.y = dot(v, m[1]); - __retVal.z = dot(v, m[2]); - __retVal.w = dot(v, m[3]); -} - -vec2 __operator * (const vec3 v, const mat2x3 m) -{ - __retVal.x = dot(v, m[0]); - __retVal.y = dot(v, m[1]); -} - -vec4 __operator * (const vec3 v, const mat4x3 m) -{ - __retVal.x = dot(v, m[0]); - __retVal.y = dot(v, m[1]); - __retVal.z = dot(v, m[2]); - __retVal.w = dot(v, m[3]); -} - -vec2 __operator * (const vec4 v, const mat2x4 m) -{ - __retVal.x = dot(v, m[0]); - __retVal.y = dot(v, m[1]); -} - -vec3 __operator * (const vec4 v, const mat3x4 m) -{ - __retVal.x = dot(v, m[0]); - __retVal.y = dot(v, m[1]); - __retVal.z = dot(v, m[2]); -} - - -void __operator += (inout mat2x3 m, const float a) { - m[0] += a; - m[1] += a; -} - -void __operator += (inout mat2x4 m, const float a) { - m[0] += a; - m[1] += a; -} - -void __operator += (inout mat3x2 m, const float a) { - m[0] += a; - m[1] += a; - m[2] += a; -} - -void __operator += (inout mat3x4 m, const float a) { - m[0] += a; - m[1] += a; - m[2] += a; -} - -void __operator += (inout mat4x2 m, const float a) { - m[0] += a; - m[1] += a; - m[2] += a; - m[3] += a; -} - -void __operator += (inout mat4x3 m, const float a) { - m[0] += a; - m[1] += a; - m[2] += a; - m[3] += a; -} - - -void __operator -= (inout mat2x3 m, const float a) { - m[0] -= a; - m[1] -= a; -} - -void __operator -= (inout mat2x4 m, const float a) { - m[0] -= a; - m[1] -= a; -} - -void __operator -= (inout mat3x2 m, const float a) { - m[0] -= a; - m[1] -= a; - m[2] -= a; -} - -void __operator -= (inout mat3x4 m, const float a) { - m[0] -= a; - m[1] -= a; - m[2] -= a; -} - -void __operator -= (inout mat4x2 m, const float a) { - m[0] -= a; - m[1] -= a; - m[2] -= a; - m[3] -= a; -} - -void __operator -= (inout mat4x3 m, const float a) { - m[0] -= a; - m[1] -= a; - m[2] -= a; - m[3] -= a; -} - - -void __operator *= (inout mat2x3 m, const float a) { - m[0] *= a; - m[1] *= a; -} - -void __operator *= (inout mat2x4 m, const float a) { - m[0] *= a; - m[1] *= a; -} - -void __operator *= (inout mat3x2 m, const float a) { - m[0] *= a; - m[1] *= a; - m[2] *= a; -} - -void __operator *= (inout mat3x4 m, const float a) { - m[0] *= a; - m[1] *= a; - m[2] *= a; -} - -void __operator *= (inout mat4x2 m, const float a) { - m[0] *= a; - m[1] *= a; - m[2] *= a; - m[3] *= a; -} - -void __operator *= (inout mat4x3 m, const float a) { - m[0] *= a; - m[1] *= a; - m[2] *= a; - m[3] *= a; -} - - -void __operator /= (inout mat2x3 m, const float a) { - m[0] /= a; - m[1] /= a; -} - -void __operator /= (inout mat2x4 m, const float a) { - m[0] /= a; - m[1] /= a; -} - -void __operator /= (inout mat3x2 m, const float a) { - m[0] /= a; - m[1] /= a; - m[2] /= a; -} - -void __operator /= (inout mat3x4 m, const float a) { - m[0] /= a; - m[1] /= a; - m[2] /= a; -} - -void __operator /= (inout mat4x2 m, const float a) { - m[0] /= a; - m[1] /= a; - m[2] /= a; - m[3] /= a; -} - -void __operator /= (inout mat4x3 m, const float a) { - m[0] /= a; - m[1] /= a; - m[2] /= a; - m[3] /= a; -} - - -mat2x3 __operator + (const mat2x3 m, const mat2x3 n) { - return mat2x3 (m[0] + n[0], m[1] + n[1]); -} - -mat2x4 __operator + (const mat2x4 m, const mat2x4 n) { - return mat2x4 (m[0] + n[0], m[1] + n[1]); -} - -mat3x2 __operator + (const mat3x2 m, const mat3x2 n) { - return mat3x2 (m[0] + n[0], m[1] + n[1], m[2] + n[2]); -} - -mat3x4 __operator + (const mat3x4 m, const mat3x4 n) { - return mat3x4 (m[0] + n[0], m[1] + n[1], m[2] + n[2]); -} - -mat4x2 __operator + (const mat4x2 m, const mat4x2 n) { - return mat4x2 (m[0] + n[0], m[1] + n[1], m[2] + n[2], m[3] + n[3]); -} - -mat4x3 __operator + (const mat4x3 m, const mat4x3 n) { - return mat4x3 (m[0] + n[0], m[1] + n[1], m[2] + n[2], m[3] + n[3]); -} - - -mat2x3 __operator - (const mat2x3 m, const mat2x3 n) { - return mat2x3 (m[0] - n[0], m[1] - n[1]); -} - -mat2x4 __operator - (const mat2x4 m, const mat2x4 n) { - return mat2x4 (m[0] - n[0], m[1] - n[1]); -} - -mat3x2 __operator - (const mat3x2 m, const mat3x2 n) { - return mat3x2 (m[0] - n[0], m[1] - n[1], m[2] - n[2]); -} - -mat3x4 __operator - (const mat3x4 m, const mat3x4 n) { - return mat3x4 (m[0] - n[0], m[1] - n[1], m[2] - n[2]); -} - -mat4x2 __operator - (const mat4x2 m, const mat4x2 n) { - return mat4x2 (m[0] - n[0], m[1] - n[1], m[2] - n[2], m[3] - n[3]); -} - -mat4x3 __operator - (const mat4x3 m, const mat4x3 n) { - return mat4x3 (m[0] - n[0], m[1] - n[1], m[2] - n[2], m[3] - n[3]); -} - - -mat2x3 __operator / (const mat2x3 m, const mat2x3 n) { - return mat2x3 (m[0] / n[0], m[1] / n[1]); -} - -mat2x4 __operator / (const mat2x4 m, const mat2x4 n) { - return mat2x4 (m[0] / n[0], m[1] / n[1]); -} - -mat3x2 __operator / (const mat3x2 m, const mat3x2 n) { - return mat3x2 (m[0] / n[0], m[1] / n[1], m[2] / n[2]); -} - -mat3x4 __operator / (const mat3x4 m, const mat3x4 n) { - return mat3x4 (m[0] / n[0], m[1] / n[1], m[2] / n[2]); -} - -mat4x2 __operator / (const mat4x2 m, const mat4x2 n) { - return mat4x2 (m[0] / n[0], m[1] / n[1], m[2] / n[2], m[3] / n[3]); -} - -mat4x3 __operator / (const mat4x3 m, const mat4x3 n) { - return mat4x3 (m[0] / n[0], m[1] / n[1], m[2] / n[2], m[3] / n[3]); -} - - -mat2x3 __operator + (const float a, const mat2x3 n) { - return mat2x3 (a + n[0], a + n[1]); -} - -mat2x3 __operator + (const mat2x3 m, const float b) { - return mat2x3 (m[0] + b, m[1] + b); -} - -mat2x4 __operator + (const float a, const mat2x4 n) { - return mat2x4 (a + n[0], a + n[1]); -} - -mat2x4 __operator + (const mat2x4 m, const float b) { - return mat2x4 (m[0] + b, m[1] + b); -} - -mat3x2 __operator + (const float a, const mat3x2 n) { - return mat3x2 (a + n[0], a + n[1], a + n[2]); -} - -mat3x2 __operator + (const mat3x2 m, const float b) { - return mat3x2 (m[0] + b, m[1] + b, m[2] + b); -} - -mat3x4 __operator + (const float a, const mat3x4 n) { - return mat3x4 (a + n[0], a + n[1], a + n[2]); -} - -mat3x4 __operator + (const mat3x4 m, const float b) { - return mat3x4 (m[0] + b, m[1] + b, m[2] + b); -} - -mat4x2 __operator + (const mat4x2 m, const float b) { - return mat4x2 (m[0] + b, m[1] + b, m[2] + b, m[3] + b); -} - -mat4x2 __operator + (const float a, const mat4x2 n) { - return mat4x2 (a + n[0], a + n[1], a + n[2], a + n[3]); -} - -mat4x3 __operator + (const mat4x3 m, const float b) { - return mat4x3 (m[0] + b, m[1] + b, m[2] + b, m[3] + b); -} - -mat4x3 __operator + (const float a, const mat4x3 n) { - return mat4x3 (a + n[0], a + n[1], a + n[2], a + n[3]); -} - - -mat2x3 __operator - (const float a, const mat2x3 n) { - return mat2x3 (a - n[0], a - n[1]); -} - -mat2x3 __operator - (const mat2x3 m, const float b) { - return mat2x3 (m[0] - b, m[1] - b); -} - -mat2x4 __operator - (const float a, const mat2x4 n) { - return mat2x4 (a - n[0], a - n[1]); -} - -mat2x4 __operator - (const mat2x4 m, const float b) { - return mat2x4 (m[0] - b, m[1] - b); -} - -mat3x2 __operator - (const float a, const mat3x2 n) { - return mat3x2 (a - n[0], a - n[1], a - n[2]); -} - -mat3x2 __operator - (const mat3x2 m, const float b) { - return mat3x2 (m[0] - b, m[1] - b, m[2] - b); -} - -mat3x4 __operator - (const float a, const mat3x4 n) { - return mat3x4 (a - n[0], a - n[1], a - n[2]); -} - -mat3x4 __operator - (const mat3x4 m, const float b) { - return mat3x4 (m[0] - b, m[1] - b, m[2] - b); -} - -mat4x2 __operator - (const mat4x2 m, const float b) { - return mat4x2 (m[0] - b, m[1] - b, m[2] - b, m[3] - b); -} - -mat4x2 __operator - (const float a, const mat4x2 n) { - return mat4x2 (a - n[0], a - n[1], a - n[2], a - n[3]); -} - -mat4x3 __operator - (const mat4x3 m, const float b) { - return mat4x3 (m[0] - b, m[1] - b, m[2] - b, m[3] - b); -} - -mat4x3 __operator - (const float a, const mat4x3 n) { - return mat4x3 (a - n[0], a - n[1], a - n[2], a - n[3]); -} - - -mat2x3 __operator * (const float a, const mat2x3 n) -{ - //return mat2x3 (a * n[0], a * n[1]); - __retVal[0] = a * n[0]; - __retVal[1] = a * n[1]; -} - -mat2x3 __operator * (const mat2x3 m, const float b) -{ - //return mat2x3 (m[0] * b, m[1] * b); - __retVal[0] = m[0] * b; - __retVal[1] = m[1] * b; -} - -mat2x4 __operator * (const float a, const mat2x4 n) -{ - //return mat2x4 (a * n[0], a * n[1]); - __retVal[0] = a * n[0]; - __retVal[1] = a * n[1]; -} - -mat2x4 __operator * (const mat2x4 m, const float b) -{ - //return mat2x4 (m[0] * b, m[1] * b); - __retVal[0] = m[0] * b; - __retVal[1] = m[1] * b; -} - -mat3x2 __operator * (const float a, const mat3x2 n) -{ - //return mat3x2 (a * n[0], a * n[1], a * n[2]); - __retVal[0] = a * n[0]; - __retVal[1] = a * n[1]; - __retVal[2] = a * n[2]; -} - -mat3x2 __operator * (const mat3x2 m, const float b) -{ - //return mat3x2 (m[0] * b, m[1] * b, m[2] * b); - __retVal[0] = m[0] * b; - __retVal[1] = m[1] * b; - __retVal[2] = m[2] * b; -} - -mat3x4 __operator * (const float a, const mat3x4 n) -{ - //return mat3x4 (a * n[0], a * n[1], a * n[2]); - __retVal[0] = a * n[0]; - __retVal[1] = a * n[1]; - __retVal[2] = a * n[2]; -} - -mat3x4 __operator * (const mat3x4 m, const float b) -{ - //return mat3x4 (m[0] * b, m[1] * b, m[2] * b); - __retVal[0] = m[0] * b; - __retVal[1] = m[1] * b; - __retVal[2] = m[2] * b; -} - -mat4x2 __operator * (const mat4x2 m, const float b) -{ - //return mat4x2 (m[0] * b, m[1] * b, m[2] * b, m[3] * b); - __retVal[0] = m[0] * b; - __retVal[1] = m[1] * b; - __retVal[2] = m[2] * b; - __retVal[3] = m[3] * b; -} - -mat4x2 __operator * (const float a, const mat4x2 n) -{ - //return mat4x2 (a * n[0], a * n[1], a * n[2], a * n[3]); - __retVal[0] = a * n[0]; - __retVal[1] = a * n[1]; - __retVal[2] = a * n[2]; - __retVal[3] = a * n[3]; -} - -mat4x3 __operator * (const mat4x3 m, const float b) -{ - //return mat4x3 (m[0] * b, m[1] * b, m[2] * b, m[3] * b); - __retVal[0] = m[0] * b; - __retVal[1] = m[1] * b; - __retVal[2] = m[2] * b; - __retVal[3] = m[3] * b; -} - -mat4x3 __operator * (const float a, const mat4x3 n) -{ - //return mat4x3 (a * n[0], a * n[1], a * n[2], a * n[3]); - __retVal[0] = a * n[0]; - __retVal[1] = a * n[1]; - __retVal[2] = a * n[2]; - __retVal[3] = a * n[3]; -} - - -mat2x3 __operator / (const float a, const mat2x3 n) -{ - //return mat2x3 (a / n[0], a / n[1]); - const float inv = 1.0 / a; - __retVal[0] = inv * n[0]; - __retVal[1] = inv * n[1]; -} - -mat2x3 __operator / (const mat2x3 m, const float b) -{ - //return mat2x3 (m[0] / b, m[1] / b); - const float inv = 1.0 / b; - __retVal[0] = m[0] * inv; - __retVal[1] = m[1] * inv; -} - -mat2x4 __operator / (const float a, const mat2x4 n) -{ - //return mat2x4 (a / n[0], a / n[1]); - const float inv = 1.0 / a; - __retVal[0] = inv * n[0]; - __retVal[1] = inv * n[1]; -} - -mat2x4 __operator / (const mat2x4 m, const float b) -{ - //return mat2x4 (m[0] / b, m[1] / b); - const float inv = 1.0 / b; - __retVal[0] = m[0] * inv; - __retVal[1] = m[1] * inv; -} - -mat3x2 __operator / (const float a, const mat3x2 n) -{ - //return mat3x2 (a / n[0], a / n[1], a / n[2]); - const float inv = 1.0 / a; - __retVal[0] = inv * n[0]; - __retVal[1] = inv * n[1]; - __retVal[2] = inv * n[2]; -} - -mat3x2 __operator / (const mat3x2 m, const float b) -{ - //return mat3x2 (m[0] / b, m[1] / b, m[2] / b); - const float inv = 1.0 / b; - __retVal[0] = m[0] * inv; - __retVal[1] = m[1] * inv; - __retVal[2] = m[2] * inv; -} - -mat3x4 __operator / (const float a, const mat3x4 n) -{ - //return mat3x4 (a / n[0], a / n[1], a / n[2]); - const float inv = 1.0 / a; - __retVal[0] = inv * n[0]; - __retVal[1] = inv * n[1]; - __retVal[2] = inv * n[2]; -} - -mat3x4 __operator / (const mat3x4 m, const float b) -{ - //return mat3x4 (m[0] / b, m[1] / b, m[2] / b); - const float inv = 1.0 / b; - __retVal[0] = m[0] * inv; - __retVal[1] = m[1] * inv; - __retVal[2] = m[2] * inv; -} - -mat4x2 __operator / (const mat4x2 m, const float b) -{ - //return mat4x2 (m[0] / b, m[1] / b, m[2] / b, m[3] / b); - const float inv = 1.0 / b; - __retVal[0] = m[0] * inv; - __retVal[1] = m[1] * inv; - __retVal[2] = m[2] * inv; - __retVal[3] = m[3] * inv; -} - -mat4x2 __operator / (const float a, const mat4x2 n) -{ - //return mat4x2 (a / n[0], a / n[1], a / n[2], a / n[3]); - const float inv = 1.0 / a; - __retVal[0] = inv * n[0]; - __retVal[1] = inv * n[1]; - __retVal[2] = inv * n[2]; - __retVal[3] = inv * n[3]; -} - -mat4x3 __operator / (const mat4x3 m, const float b) -{ - //return mat4x3 (m[0] / b, m[1] / b, m[2] / b, m[3] / b); - const float inv = 1.0 / b; - __retVal[0] = m[0] * inv; - __retVal[1] = m[1] * inv; - __retVal[2] = m[2] * inv; - __retVal[3] = m[3] * inv; -} - -mat4x3 __operator / (const float a, const mat4x3 n) -{ - //return mat4x3 (a / n[0], a / n[1], a / n[2], a / n[3]); - const float inv = 1.0 / a; - __retVal[0] = inv * n[0]; - __retVal[1] = inv * n[1]; - __retVal[2] = inv * n[2]; - __retVal[3] = inv * n[3]; -} - - -mat2x3 __operator - (const mat2x3 m) { - return mat2x3 (-m[0], -m[1]); -} - -mat2x4 __operator - (const mat2x4 m) { - return mat2x4 (-m[0], -m[1]); -} - -mat3x2 __operator - (const mat3x2 m) { - return mat3x2 (-m[0], -m[1], -m[2]); -} - -mat3x4 __operator - (const mat3x4 m) { - return mat3x4 (-m[0], -m[1], -m[2]); -} - -mat4x2 __operator - (const mat4x2 m) { - return mat4x2 (-m[0], -m[1], -m[2], -m[3]); -} - -mat4x3 __operator - (const mat4x3 m) { - return mat4x3 (-m[0], -m[1], -m[2], -m[3]); -} - - -void __operator -- (inout mat2x3 m) { - --m[0]; - --m[1]; -} - -void __operator -- (inout mat2x4 m) { - --m[0]; - --m[1]; -} - -void __operator -- (inout mat3x2 m) { - --m[0]; - --m[1]; - --m[2]; -} - -void __operator -- (inout mat3x4 m) { - --m[0]; - --m[1]; - --m[2]; -} - -void __operator -- (inout mat4x2 m) { - --m[0]; - --m[1]; - --m[2]; - --m[3]; -} - -void __operator -- (inout mat4x3 m) { - --m[0]; - --m[1]; - --m[2]; - --m[3]; -} - - -void __operator ++ (inout mat2x3 m) { - ++m[0]; - ++m[1]; -} - -void __operator ++ (inout mat2x4 m) { - ++m[0]; - ++m[1]; -} - -void __operator ++ (inout mat3x2 m) { - ++m[0]; - ++m[1]; - ++m[2]; -} - -void __operator ++ (inout mat3x4 m) { - ++m[0]; - ++m[1]; - ++m[2]; -} - -void __operator ++ (inout mat4x2 m) { - ++m[0]; - ++m[1]; - ++m[2]; - ++m[3]; -} - -void __operator ++ (inout mat4x3 m) { - ++m[0]; - ++m[1]; - ++m[2]; - ++m[3]; -} - diff --git a/src/mesa/slang/library/slang_builtin_120_common.gc b/src/mesa/slang/library/slang_builtin_120_common.gc deleted file mode 100644 index c6264c3b47..0000000000 --- a/src/mesa/slang/library/slang_builtin_120_common.gc +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.6 - * - * Copyright (C) 2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -// -// From Shader Spec, ver. 1.20, rev. 6 -// - -// -// 8.5 Matrix Functions -// - -mat2x3 matrixCompMult (mat2x3 m, mat2x3 n) { - return mat2x3 (m[0] * n[0], m[1] * n[1]); -} - -mat2x4 matrixCompMult (mat2x4 m, mat2x4 n) { - return mat2x4 (m[0] * n[0], m[1] * n[1]); -} - -mat3x2 matrixCompMult (mat3x2 m, mat3x2 n) { - return mat3x2 (m[0] * n[0], m[1] * n[1], m[2] * n[2]); -} - -mat3x4 matrixCompMult (mat3x4 m, mat3x4 n) { - return mat3x4 (m[0] * n[0], m[1] * n[1], m[2] * n[2]); -} - -mat4x2 matrixCompMult (mat4x2 m, mat4x2 n) { - return mat4x2 (m[0] * n[0], m[1] * n[1], m[2] * n[2], m[3] * n[3]); -} - -mat4x3 matrixCompMult (mat4x3 m, mat4x3 n) { - return mat4x3 (m[0] * n[0], m[1] * n[1], m[2] * n[2], m[3] * n[3]); -} - -mat2 outerProduct (vec2 c, vec2 r) { - return mat2 ( - c.x * r.x, c.y * r.x, - c.x * r.y, c.y * r.y - ); -} - -mat3 outerProduct (vec3 c, vec3 r) { - return mat3 ( - c.x * r.x, c.y * r.x, c.z * r.x, - c.x * r.y, c.y * r.y, c.z * r.y, - c.x * r.z, c.y * r.z, c.z * r.z - ); -} - -mat4 outerProduct (vec4 c, vec4 r) { - return mat4 ( - c.x * r.x, c.y * r.x, c.z * r.x, c.w * r.x, - c.x * r.y, c.y * r.y, c.z * r.y, c.w * r.y, - c.x * r.z, c.y * r.z, c.z * r.z, c.w * r.z, - c.x * r.w, c.y * r.w, c.z * r.w, c.w * r.w - ); -} - -mat2x3 outerProduct (vec3 c, vec2 r) { - return mat2x3 ( - c.x * r.x, c.y * r.x, c.z * r.x, - c.x * r.y, c.y * r.y, c.z * r.y - ); -} - -mat3x2 outerProduct (vec2 c, vec3 r) { - return mat3x2 ( - c.x * r.x, c.y * r.x, - c.x * r.y, c.y * r.y, - c.x * r.z, c.y * r.z - ); -} - -mat2x4 outerProduct (vec4 c, vec2 r) { - return mat2x4 ( - c.x * r.x, c.y * r.x, c.z * r.x, c.w * r.x, - c.x * r.y, c.y * r.y, c.z * r.y, c.w * r.y - ); -} - -mat4x2 outerProduct (vec2 c, vec4 r) { - return mat4x2 ( - c.x * r.x, c.y * r.x, - c.x * r.y, c.y * r.y, - c.x * r.z, c.y * r.z, - c.x * r.w, c.y * r.w - ); -} - -mat3x4 outerProduct (vec4 c, vec3 r) { - return mat3x4 ( - c.x * r.x, c.y * r.x, c.z * r.x, c.w * r.x, - c.x * r.y, c.y * r.y, c.z * r.y, c.w * r.y, - c.x * r.z, c.y * r.z, c.z * r.z, c.w * r.z - ); -} - -mat4x3 outerProduct (vec3 c, vec4 r) { - return mat4x3 ( - c.x * r.x, c.y * r.x, c.z * r.x, - c.x * r.y, c.y * r.y, c.z * r.y, - c.x * r.z, c.y * r.z, c.z * r.z, - c.x * r.w, c.y * r.w, c.z * r.w - ); -} - -mat2 transpose (mat2 m) { - return mat2 ( - m[0].x, m[1].x, - m[0].y, m[1].y - ); -} - -mat3 transpose (mat3 m) { - return mat3 ( - m[0].x, m[1].x, m[2].x, - m[0].y, m[1].y, m[2].y, - m[0].z, m[1].z, m[2].z - ); -} - -mat4 transpose (mat4 m) { - return mat4 ( - m[0].x, m[1].x, m[2].x, m[3].x, - m[0].y, m[1].y, m[2].y, m[3].y, - m[0].z, m[1].z, m[2].z, m[3].z, - m[0].w, m[1].w, m[2].w, m[3].w - ); -} - -mat2x3 transpose (mat3x2 m) { - return mat2x3 ( - m[0].x, m[1].x, m[2].x, - m[0].y, m[1].y, m[2].y - ); -} - -mat3x2 transpose (mat2x3 m) { - return mat3x2 ( - m[0].x, m[1].x, - m[0].y, m[1].y, - m[0].z, m[1].z - ); -} - -mat2x4 transpose (mat4x2 m) { - return mat2x4 ( - m[0].x, m[1].x, m[2].x, m[3].x, - m[0].y, m[1].y, m[2].y, m[3].y - ); -} - -mat4x2 transpose (mat2x4 m) { - return mat4x2 ( - m[0].x, m[1].x, - m[0].y, m[1].y, - m[0].z, m[1].z, - m[0].w, m[1].w - ); -} - -mat3x4 transpose (mat4x3 m) { - return mat3x4 ( - m[0].x, m[1].x, m[2].x, m[3].x, - m[0].y, m[1].y, m[2].y, m[3].y, - m[0].z, m[1].z, m[2].z, m[3].z - ); -} - -mat4x3 transpose (mat3x4 m) { - return mat4x3 ( - m[0].x, m[1].x, m[2].x, - m[0].y, m[1].y, m[2].y, - m[0].z, m[1].z, m[2].z, - m[0].w, m[1].w, m[2].w - ); -} - diff --git a/src/mesa/slang/library/slang_common_builtin.gc b/src/mesa/slang/library/slang_common_builtin.gc deleted file mode 100644 index 1f5ddbc1ee..0000000000 --- a/src/mesa/slang/library/slang_common_builtin.gc +++ /dev/null @@ -1,1887 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 2006 Brian Paul All Rights Reserved. - * Copyright (C) 2008 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -// -// From Shader Spec, ver. 1.10, rev. 59 -// - -// Note: the values assigned to these constants here aren't actually used. -// They're set by the compiler according to the GL context limits. -// See slang_simplify.c -const int gl_MaxLights = 8; -const int gl_MaxClipPlanes = 6; -const int gl_MaxTextureUnits = 8; -const int gl_MaxTextureCoords = 8; -const int gl_MaxVertexAttribs = 16; -const int gl_MaxVertexUniformComponents = 512; -const int gl_MaxVaryingFloats = 32; -const int gl_MaxVertexTextureImageUnits = 0; -const int gl_MaxCombinedTextureImageUnits = 2; -const int gl_MaxTextureImageUnits = 2; -const int gl_MaxFragmentUniformComponents = 64; -const int gl_MaxDrawBuffers = 1; - -uniform mat4 gl_ModelViewMatrix; -uniform mat4 gl_ProjectionMatrix; -uniform mat4 gl_ModelViewProjectionMatrix; -uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords]; - -uniform mat3 gl_NormalMatrix; - -uniform mat4 gl_ModelViewMatrixInverse; -uniform mat4 gl_ProjectionMatrixInverse; -uniform mat4 gl_ModelViewProjectionMatrixInverse; -uniform mat4 gl_TextureMatrixInverse[gl_MaxTextureCoords]; - -uniform mat4 gl_ModelViewMatrixTranspose; -uniform mat4 gl_ProjectionMatrixTranspose; -uniform mat4 gl_ModelViewProjectionMatrixTranspose; -uniform mat4 gl_TextureMatrixTranspose[gl_MaxTextureCoords]; - -uniform mat4 gl_ModelViewMatrixInverseTranspose; -uniform mat4 gl_ProjectionMatrixInverseTranspose; -uniform mat4 gl_ModelViewProjectionMatrixInverseTranspose; -uniform mat4 gl_TextureMatrixInverseTranspose[gl_MaxTextureCoords]; - -uniform float gl_NormalScale; - -struct gl_DepthRangeParameters { - float near; - float far; - float diff; -}; - -uniform gl_DepthRangeParameters gl_DepthRange; - -uniform vec4 gl_ClipPlane[gl_MaxClipPlanes]; - -struct gl_PointParameters { - float size; - float sizeMin; - float sizeMax; - float fadeThresholdSize; - float distanceConstantAttenuation; - float distanceLinearAttenuation; - float distanceQuadraticAttenuation; -}; - -uniform gl_PointParameters gl_Point; - -struct gl_MaterialParameters { - vec4 emission; - vec4 ambient; - vec4 diffuse; - vec4 specular; - float shininess; -}; - -uniform gl_MaterialParameters gl_FrontMaterial; -uniform gl_MaterialParameters gl_BackMaterial; - -/* NOTE: the order of these fields is significant! - * See the definition of the lighting state vars such as STATE_SPOT_DIRECTION. - */ -struct gl_LightSourceParameters { - vec4 ambient; - vec4 diffuse; - vec4 specular; - vec4 position; - vec4 halfVector; - vec3 spotDirection; - float spotCosCutoff; - - float constantAttenuation; - float linearAttenuation; - float quadraticAttenuation; - float spotExponent; - - float spotCutoff; -}; - -uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights]; - -struct gl_LightModelParameters { - vec4 ambient; -}; - -uniform gl_LightModelParameters gl_LightModel; - -struct gl_LightModelProducts { - vec4 sceneColor; -}; - -uniform gl_LightModelProducts gl_FrontLightModelProduct; -uniform gl_LightModelProducts gl_BackLightModelProduct; - -struct gl_LightProducts { - vec4 ambient; - vec4 diffuse; - vec4 specular; -}; - -uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights]; -uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights]; - -uniform vec4 gl_TextureEnvColor[gl_MaxTextureImageUnits]; -uniform vec4 gl_EyePlaneS[gl_MaxTextureCoords]; -uniform vec4 gl_EyePlaneT[gl_MaxTextureCoords]; -uniform vec4 gl_EyePlaneR[gl_MaxTextureCoords]; -uniform vec4 gl_EyePlaneQ[gl_MaxTextureCoords]; -uniform vec4 gl_ObjectPlaneS[gl_MaxTextureCoords]; -uniform vec4 gl_ObjectPlaneT[gl_MaxTextureCoords]; -uniform vec4 gl_ObjectPlaneR[gl_MaxTextureCoords]; -uniform vec4 gl_ObjectPlaneQ[gl_MaxTextureCoords]; - -struct gl_FogParameters { - vec4 color; - float density; - float start; - float end; - float scale; -}; - -uniform gl_FogParameters gl_Fog; - - - - - -// -// 8.1 Angle and Trigonometry Functions -// - -//// radians - -float radians(const float deg) -{ - const float c = 3.1415926 / 180.0; - __asm vec4_multiply __retVal, deg, c; -} - -vec2 radians(const vec2 deg) -{ - const float c = 3.1415926 / 180.0; - __asm vec4_multiply __retVal.xy, deg.xy, c.xx; -} - -vec3 radians(const vec3 deg) -{ - const float c = 3.1415926 / 180.0; - __asm vec4_multiply __retVal.xyz, deg.xyz, c.xxx; -} - -vec4 radians(const vec4 deg) -{ - const float c = 3.1415926 / 180.0; - __asm vec4_multiply __retVal, deg, c.xxxx; -} - - -//// degrees - -float degrees(const float rad) -{ - const float c = 180.0 / 3.1415926; - __asm vec4_multiply __retVal, rad, c; -} - -vec2 degrees(const vec2 rad) -{ - const float c = 180.0 / 3.1415926; - __asm vec4_multiply __retVal.xy, rad.xy, c.xx; -} - -vec3 degrees(const vec3 rad) -{ - const float c = 180.0 / 3.1415926; - __asm vec4_multiply __retVal.xyz, rad.xyz, c.xxx; -} - -vec4 degrees(const vec4 rad) -{ - const float c = 180.0 / 3.1415926; - __asm vec4_multiply __retVal, rad, c.xxxx; -} - - -//// sin - -float sin(const float radians) -{ - __asm float_sine __retVal, radians; -} - -vec2 sin(const vec2 radians) -{ - __asm float_sine __retVal.x, radians.x; - __asm float_sine __retVal.y, radians.y; -} - -vec3 sin(const vec3 radians) -{ - __asm float_sine __retVal.x, radians.x; - __asm float_sine __retVal.y, radians.y; - __asm float_sine __retVal.z, radians.z; -} - -vec4 sin(const vec4 radians) -{ - __asm float_sine __retVal.x, radians.x; - __asm float_sine __retVal.y, radians.y; - __asm float_sine __retVal.z, radians.z; - __asm float_sine __retVal.w, radians.w; -} - - -//// cos - -float cos(const float radians) -{ - __asm float_cosine __retVal, radians; -} - -vec2 cos(const vec2 radians) -{ - __asm float_cosine __retVal.x, radians.x; - __asm float_cosine __retVal.y, radians.y; -} - -vec3 cos(const vec3 radians) -{ - __asm float_cosine __retVal.x, radians.x; - __asm float_cosine __retVal.y, radians.y; - __asm float_cosine __retVal.z, radians.z; -} - -vec4 cos(const vec4 radians) -{ - __asm float_cosine __retVal.x, radians.x; - __asm float_cosine __retVal.y, radians.y; - __asm float_cosine __retVal.z, radians.z; - __asm float_cosine __retVal.w, radians.w; -} - - - -//// tan - -float tan(const float angle) -{ - const float s = sin(angle); - const float c = cos(angle); - return s / c; -} - -vec2 tan(const vec2 angle) -{ - const vec2 s = sin(angle); - const vec2 c = cos(angle); - return s / c; -} - -vec3 tan(const vec3 angle) -{ - const vec3 s = sin(angle); - const vec3 c = cos(angle); - return s / c; -} - -vec4 tan(const vec4 angle) -{ - const vec4 s = sin(angle); - const vec4 c = cos(angle); - return s / c; -} - - - -float asin(const float x) -{ - const float a0 = 1.5707288; // PI/2? - const float a1 = -0.2121144; - const float a2 = 0.0742610; - //const float a3 = -0.0187293; - const float halfPi = 3.1415926 * 0.5; - const float y = abs(x); - // three terms seem to be enough: - __retVal = (halfPi - sqrt(1.0 - y) * (a0 + y * (a1 + a2 * y))) * sign(x); - // otherwise, try four: - //__retVal = (halfPi - sqrt(1.0 - y) * (a0 + y * (a1 + y * (a2 + y * a3)))) * sign(x); -} - -vec2 asin(const vec2 v) -{ - __retVal.x = asin(v.x); - __retVal.y = asin(v.y); -} - -vec3 asin(const vec3 v) -{ - __retVal.x = asin(v.x); - __retVal.y = asin(v.y); - __retVal.z = asin(v.z); -} - -vec4 asin(const vec4 v) -{ - __retVal.x = asin(v.x); - __retVal.y = asin(v.y); - __retVal.z = asin(v.z); - __retVal.w = asin(v.w); -} - -float acos(const float x) -{ - const float halfPi = 3.1415926 * 0.5; - __retVal = halfPi - asin(x); -} - -vec2 acos(const vec2 v) -{ - __retVal.x = acos(v.x); - __retVal.y = acos(v.y); -} - -vec3 acos(const vec3 v) -{ - __retVal.x = acos(v.x); - __retVal.y = acos(v.y); - __retVal.z = acos(v.z); -} - -vec4 acos(const vec4 v) -{ - __retVal.x = acos(v.x); - __retVal.y = acos(v.y); - __retVal.z = acos(v.z); - __retVal.w = acos(v.w); -} - -float atan(const float x) -{ - __retVal = asin(x * inversesqrt(x * x + 1.0)); -} - -vec2 atan(const vec2 y_over_x) -{ - __retVal.x = atan(y_over_x.x); - __retVal.y = atan(y_over_x.y); -} - -vec3 atan(const vec3 y_over_x) -{ - __retVal.x = atan(y_over_x.x); - __retVal.y = atan(y_over_x.y); - __retVal.z = atan(y_over_x.z); -} - -vec4 atan(const vec4 y_over_x) -{ - __retVal.x = atan(y_over_x.x); - __retVal.y = atan(y_over_x.y); - __retVal.z = atan(y_over_x.z); - __retVal.w = atan(y_over_x.w); -} - -float atan(const float y, const float x) -{ - float r; - if (abs(x) > 1.0e-4) { - r = atan(y / x); - if (x < 0.0) { - r = r + 3.141593 - 6.283186 * float(y < 0.0); - } - } - else { - r = sign(y) * 1.5707965; // pi/2 - } - return r; -} - -vec2 atan(const vec2 u, const vec2 v) -{ - __retVal.x = atan(u.x, v.x); - __retVal.y = atan(u.y, v.y); -} - -vec3 atan(const vec3 u, const vec3 v) -{ - __retVal.x = atan(u.x, v.x); - __retVal.y = atan(u.y, v.y); - __retVal.z = atan(u.z, v.z); -} - -vec4 atan(const vec4 u, const vec4 v) -{ - __retVal.x = atan(u.x, v.x); - __retVal.y = atan(u.y, v.y); - __retVal.z = atan(u.z, v.z); - __retVal.w = atan(u.w, v.w); -} - - -// -// 8.2 Exponential Functions -// - -//// pow - -float pow(const float a, const float b) -{ - __asm float_power __retVal, a, b; -} - -vec2 pow(const vec2 a, const vec2 b) -{ - __asm float_power __retVal.x, a.x, b.x; - __asm float_power __retVal.y, a.y, b.y; -} - -vec3 pow(const vec3 a, const vec3 b) -{ - __asm float_power __retVal.x, a.x, b.x; - __asm float_power __retVal.y, a.y, b.y; - __asm float_power __retVal.z, a.z, b.z; -} - -vec4 pow(const vec4 a, const vec4 b) -{ - __asm float_power __retVal.x, a.x, b.x; - __asm float_power __retVal.y, a.y, b.y; - __asm float_power __retVal.z, a.z, b.z; - __asm float_power __retVal.w, a.w, b.w; -} - - -//// exp - -float exp(const float a) -{ - // NOTE: log2(e) = 1.44269502 - float t = a * 1.44269502; - __asm float_exp2 __retVal, t; -} - -vec2 exp(const vec2 a) -{ - vec2 t = a * 1.44269502; - __asm float_exp2 __retVal.x, t.x; - __asm float_exp2 __retVal.y, t.y; -} - -vec3 exp(const vec3 a) -{ - vec3 t = a * 1.44269502; - __asm float_exp2 __retVal.x, t.x; - __asm float_exp2 __retVal.y, t.y; - __asm float_exp2 __retVal.z, t.z; -} - -vec4 exp(const vec4 a) -{ - vec4 t = a * 1.44269502; - __asm float_exp2 __retVal.x, t.x; - __asm float_exp2 __retVal.y, t.y; - __asm float_exp2 __retVal.z, t.z; - __asm float_exp2 __retVal.w, t.w; -} - - - -//// log2 - -float log2(const float x) -{ - __asm float_log2 __retVal, x; -} - -vec2 log2(const vec2 v) -{ - __asm float_log2 __retVal.x, v.x; - __asm float_log2 __retVal.y, v.y; -} - -vec3 log2(const vec3 v) -{ - __asm float_log2 __retVal.x, v.x; - __asm float_log2 __retVal.y, v.y; - __asm float_log2 __retVal.z, v.z; -} - -vec4 log2(const vec4 v) -{ - __asm float_log2 __retVal.x, v.x; - __asm float_log2 __retVal.y, v.y; - __asm float_log2 __retVal.z, v.z; - __asm float_log2 __retVal.w, v.w; -} - - -//// log (natural log) - -float log(const float x) -{ - // note: logBaseB(x) = logBaseN(x) / logBaseN(B) - // compute log(x) = log2(x) / log2(e) - // c = 1.0 / log2(e) = 0.693147181 - const float c = 0.693147181; - return log2(x) * c; -} - -vec2 log(const vec2 v) -{ - const float c = 0.693147181; - return log2(v) * c; -} - -vec3 log(const vec3 v) -{ - const float c = 0.693147181; - return log2(v) * c; -} - -vec4 log(const vec4 v) -{ - const float c = 0.693147181; - return log2(v) * c; -} - - -//// exp2 - -float exp2(const float a) -{ - __asm float_exp2 __retVal, a; -} - -vec2 exp2(const vec2 a) -{ - __asm float_exp2 __retVal.x, a.x; - __asm float_exp2 __retVal.y, a.y; -} - -vec3 exp2(const vec3 a) -{ - __asm float_exp2 __retVal.x, a.x; - __asm float_exp2 __retVal.y, a.y; - __asm float_exp2 __retVal.z, a.z; -} - -vec4 exp2(const vec4 a) -{ - __asm float_exp2 __retVal.x, a.x; - __asm float_exp2 __retVal.y, a.y; - __asm float_exp2 __retVal.z, a.z; - __asm float_exp2 __retVal.w, a.w; -} - - -//// sqrt - -float sqrt(const float x) -{ - const float nx = -x; - float r; - __asm float_rsq r, x; - r = r * x; - __asm vec4_cmp __retVal, nx, r, 0.0; -} - -vec2 sqrt(const vec2 x) -{ - const vec2 nx = -x, zero = vec2(0.0); - vec2 r; - __asm float_rsq r.x, x.x; - __asm float_rsq r.y, x.y; - r = r * x; - __asm vec4_cmp __retVal, nx, r, zero; -} - -vec3 sqrt(const vec3 x) -{ - const vec3 nx = -x, zero = vec3(0.0); - vec3 r; - __asm float_rsq r.x, x.x; - __asm float_rsq r.y, x.y; - __asm float_rsq r.z, x.z; - r = r * x; - __asm vec4_cmp __retVal, nx, r, zero; -} - -vec4 sqrt(const vec4 x) -{ - const vec4 nx = -x, zero = vec4(0.0); - vec4 r; - __asm float_rsq r.x, x.x; - __asm float_rsq r.y, x.y; - __asm float_rsq r.z, x.z; - __asm float_rsq r.w, x.w; - r = r * x; - __asm vec4_cmp __retVal, nx, r, zero; -} - - -//// inversesqrt - -float inversesqrt(const float x) -{ - __asm float_rsq __retVal.x, x; -} - -vec2 inversesqrt(const vec2 v) -{ - __asm float_rsq __retVal.x, v.x; - __asm float_rsq __retVal.y, v.y; -} - -vec3 inversesqrt(const vec3 v) -{ - __asm float_rsq __retVal.x, v.x; - __asm float_rsq __retVal.y, v.y; - __asm float_rsq __retVal.z, v.z; -} - -vec4 inversesqrt(const vec4 v) -{ - __asm float_rsq __retVal.x, v.x; - __asm float_rsq __retVal.y, v.y; - __asm float_rsq __retVal.z, v.z; - __asm float_rsq __retVal.w, v.w; -} - - -//// normalize - -float normalize(const float x) -{ - __retVal = 1.0; -} - -vec2 normalize(const vec2 v) -{ - const float s = inversesqrt(dot(v, v)); - __asm vec4_multiply __retVal.xy, v, s; -} - -vec3 normalize(const vec3 v) -{ -// const float s = inversesqrt(dot(v, v)); -// __retVal = v * s; -// XXX note, we _could_ use __retVal.w instead of tmp and save a -// register, but that's actually a compilation error because v is a vec3 -// and the .w suffix is illegal. Oh well. - float tmp; - __asm vec3_dot tmp, v, v; - __asm float_rsq tmp, tmp; - __asm vec4_multiply __retVal.xyz, v, tmp; -} - -vec4 normalize(const vec4 v) -{ - float tmp; - __asm vec4_dot tmp, v, v; - __asm float_rsq tmp, tmp; - __asm vec4_multiply __retVal.xyz, v, tmp; -} - - - -// -// 8.3 Common Functions -// - - -//// abs - -float abs(const float a) -{ - __asm vec4_abs __retVal, a; -} - -vec2 abs(const vec2 a) -{ - __asm vec4_abs __retVal.xy, a; -} - -vec3 abs(const vec3 a) -{ - __asm vec4_abs __retVal.xyz, a; -} - -vec4 abs(const vec4 a) -{ - __asm vec4_abs __retVal, a; -} - - -//// sign - -float sign(const float x) -{ - float p, n; - __asm vec4_sgt p, x, 0.0; // p = (x > 0) - __asm vec4_sgt n, 0.0, x; // n = (x < 0) - __asm vec4_subtract __retVal, p, n; // sign = p - n -} - -vec2 sign(const vec2 v) -{ - vec2 p, n; - __asm vec4_sgt p.xy, v, 0.0; - __asm vec4_sgt n.xy, 0.0, v; - __asm vec4_subtract __retVal.xy, p, n; -} - -vec3 sign(const vec3 v) -{ - vec3 p, n; - __asm vec4_sgt p.xyz, v, 0.0; - __asm vec4_sgt n.xyz, 0.0, v; - __asm vec4_subtract __retVal.xyz, p, n; -} - -vec4 sign(const vec4 v) -{ - vec4 p, n; - __asm vec4_sgt p, v, 0.0; - __asm vec4_sgt n, 0.0, v; - __asm vec4_subtract __retVal, p, n; -} - - -//// floor - -float floor(const float a) -{ - __asm vec4_floor __retVal, a; -} - -vec2 floor(const vec2 a) -{ - __asm vec4_floor __retVal.xy, a; -} - -vec3 floor(const vec3 a) -{ - __asm vec4_floor __retVal.xyz, a; -} - -vec4 floor(const vec4 a) -{ - __asm vec4_floor __retVal, a; -} - - -//// ceil - -float ceil(const float a) -{ - // XXX this could be improved - float b = -a; - __asm vec4_floor b, b; - __retVal = -b; -} - -vec2 ceil(const vec2 a) -{ - vec2 b = -a; - __asm vec4_floor b, b; - __retVal.xy = -b; -} - -vec3 ceil(const vec3 a) -{ - vec3 b = -a; - __asm vec4_floor b, b; - __retVal.xyz = -b; -} - -vec4 ceil(const vec4 a) -{ - vec4 b = -a; - __asm vec4_floor b, b; - __retVal = -b; -} - - -//// fract - -float fract(const float a) -{ - __asm vec4_frac __retVal, a; -} - -vec2 fract(const vec2 a) -{ - __asm vec4_frac __retVal.xy, a; -} - -vec3 fract(const vec3 a) -{ - __asm vec4_frac __retVal.xyz, a; -} - -vec4 fract(const vec4 a) -{ - __asm vec4_frac __retVal, a; -} - - -//// mod (very untested!) - -float mod(const float a, const float b) -{ - float oneOverB; - __asm float_rcp oneOverB, b; - __retVal = a - b * floor(a * oneOverB); -} - -vec2 mod(const vec2 a, const float b) -{ - float oneOverB; - __asm float_rcp oneOverB, b; - __retVal.xy = a - b * floor(a * oneOverB); -} - -vec3 mod(const vec3 a, const float b) -{ - float oneOverB; - __asm float_rcp oneOverB, b; - __retVal.xyz = a - b * floor(a * oneOverB); -} - -vec4 mod(const vec4 a, const float b) -{ - float oneOverB; - __asm float_rcp oneOverB, b; - __retVal = a - b * floor(a * oneOverB); -} - -vec2 mod(const vec2 a, const vec2 b) -{ - vec2 oneOverB; - __asm float_rcp oneOverB.x, b.x; - __asm float_rcp oneOverB.y, b.y; - __retVal = a - b * floor(a * oneOverB); -} - -vec3 mod(const vec3 a, const vec3 b) -{ - vec3 oneOverB; - __asm float_rcp oneOverB.x, b.x; - __asm float_rcp oneOverB.y, b.y; - __asm float_rcp oneOverB.z, b.z; - __retVal = a - b * floor(a * oneOverB); -} - -vec4 mod(const vec4 a, const vec4 b) -{ - vec4 oneOverB; - __asm float_rcp oneOverB.x, b.x; - __asm float_rcp oneOverB.y, b.y; - __asm float_rcp oneOverB.z, b.z; - __asm float_rcp oneOverB.w, b.w; - __retVal = a - b * floor(a * oneOverB); -} - - -//// min - -float min(const float a, const float b) -{ - __asm vec4_min __retVal, a, b; -} - -vec2 min(const vec2 a, const vec2 b) -{ - __asm vec4_min __retVal.xy, a.xy, b.xy; -} - -vec3 min(const vec3 a, const vec3 b) -{ - __asm vec4_min __retVal.xyz, a.xyz, b.xyz; -} - -vec4 min(const vec4 a, const vec4 b) -{ - __asm vec4_min __retVal, a, b; -} - -vec2 min(const vec2 a, const float b) -{ - __asm vec4_min __retVal, a.xy, b; -} - -vec3 min(const vec3 a, const float b) -{ - __asm vec4_min __retVal, a.xyz, b; -} - -vec4 min(const vec4 a, const float b) -{ - __asm vec4_min __retVal, a, b; -} - - -//// max - -float max(const float a, const float b) -{ - __asm vec4_max __retVal, a, b; -} - -vec2 max(const vec2 a, const vec2 b) -{ - __asm vec4_max __retVal.xy, a.xy, b.xy; -} - -vec3 max(const vec3 a, const vec3 b) -{ - __asm vec4_max __retVal.xyz, a.xyz, b.xyz; -} - -vec4 max(const vec4 a, const vec4 b) -{ - __asm vec4_max __retVal, a, b; -} - -vec2 max(const vec2 a, const float b) -{ - __asm vec4_max __retVal, a.xy, b; -} - -vec3 max(const vec3 a, const float b) -{ - __asm vec4_max __retVal, a.xyz, b; -} - -vec4 max(const vec4 a, const float b) -{ - __asm vec4_max __retVal, a, b; -} - - -//// clamp - -float clamp(const float val, const float minVal, const float maxVal) -{ - __asm vec4_clamp __retVal, val, minVal, maxVal; -} - -vec2 clamp(const vec2 val, const float minVal, const float maxVal) -{ - __asm vec4_clamp __retVal, val, minVal, maxVal; -} - -vec3 clamp(const vec3 val, const float minVal, const float maxVal) -{ - __asm vec4_clamp __retVal, val, minVal, maxVal; -} - -vec4 clamp(const vec4 val, const float minVal, const float maxVal) -{ - __asm vec4_clamp __retVal, val, minVal, maxVal; -} - -vec2 clamp(const vec2 val, const vec2 minVal, const vec2 maxVal) -{ - __asm vec4_clamp __retVal, val, minVal, maxVal; -} - -vec3 clamp(const vec3 val, const vec3 minVal, const vec3 maxVal) -{ - __asm vec4_clamp __retVal, val, minVal, maxVal; -} - -vec4 clamp(const vec4 val, const vec4 minVal, const vec4 maxVal) -{ - __asm vec4_clamp __retVal, val, minVal, maxVal; -} - - -//// mix - -float mix(const float x, const float y, const float a) -{ - __asm vec4_lrp __retVal, a, y, x; -} - -vec2 mix(const vec2 x, const vec2 y, const float a) -{ - __asm vec4_lrp __retVal, a, y, x; -} - -vec3 mix(const vec3 x, const vec3 y, const float a) -{ - __asm vec4_lrp __retVal, a, y, x; -} - -vec4 mix(const vec4 x, const vec4 y, const float a) -{ - __asm vec4_lrp __retVal, a, y, x; -} - -vec2 mix(const vec2 x, const vec2 y, const vec2 a) -{ - __asm vec4_lrp __retVal, a, y, x; -} - -vec3 mix(const vec3 x, const vec3 y, const vec3 a) -{ - __asm vec4_lrp __retVal, a, y, x; -} - -vec4 mix(const vec4 x, const vec4 y, const vec4 a) -{ - __asm vec4_lrp __retVal, a, y, x; -} - - -//// step - -float step(const float edge, const float x) -{ - __asm vec4_sge __retVal, x, edge; -} - -vec2 step(const vec2 edge, const vec2 x) -{ - __asm vec4_sge __retVal.xy, x, edge; -} - -vec3 step(const vec3 edge, const vec3 x) -{ - __asm vec4_sge __retVal.xyz, x, edge; -} - -vec4 step(const vec4 edge, const vec4 x) -{ - __asm vec4_sge __retVal, x, edge; -} - -vec2 step(const float edge, const vec2 v) -{ - __asm vec4_sge __retVal.xy, v, edge; -} - -vec3 step(const float edge, const vec3 v) -{ - __asm vec4_sge __retVal.xyz, v, edge; -} - -vec4 step(const float edge, const vec4 v) -{ - __asm vec4_sge __retVal, v, edge; -} - - -//// smoothstep - -float smoothstep(const float edge0, const float edge1, const float x) -{ - float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); - return t * t * (3.0 - 2.0 * t); -} - -vec2 smoothstep(const vec2 edge0, const vec2 edge1, const vec2 v) -{ - vec2 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); - return t * t * (3.0 - 2.0 * t); -} - -vec3 smoothstep(const vec3 edge0, const vec3 edge1, const vec3 v) -{ - vec3 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); - return t * t * (3.0 - 2.0 * t); -} - -vec4 smoothstep(const vec4 edge0, const vec4 edge1, const vec4 v) -{ - vec4 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); - return t * t * (3.0 - 2.0 * t); -} - -vec2 smoothstep(const float edge0, const float edge1, const vec2 v) -{ - vec2 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); - return t * t * (3.0 - 2.0 * t); -} - -vec3 smoothstep(const float edge0, const float edge1, const vec3 v) -{ - vec3 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); - return t * t * (3.0 - 2.0 * t); -} - -vec4 smoothstep(const float edge0, const float edge1, const vec4 v) -{ - vec4 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); - return t * t * (3.0 - 2.0 * t); -} - - - -// -// 8.4 Geometric Functions -// - - -//// length - -float length(const float x) -{ - return abs(x); -} - -float length(const vec2 v) -{ - float r; - const float p = dot(v, v); // p = v.x * v.x + v.y * v.y - __asm float_rsq r, p; // r = 1 / sqrt(p) - __retVal = p * r; // p * r = sqrt(p); -} - -float length(const vec3 v) -{ - float r; - const float p = dot(v, v); // p = v.x * v.x + v.y * v.y + v.z * v.z - __asm float_rsq r, p; // r = 1 / sqrt(p) - __retVal = p * r; // p * r = sqrt(p); -} - -float length(const vec4 v) -{ - float r; - const float p = dot(v, v); // p = v.x * v.x + v.y * v.y + ... - __asm float_rsq r, p; // r = 1 / sqrt(p) - __retVal = p * r; // p * r = sqrt(p); -} - - -//// distance - -float distance(const float x, const float y) -{ - const float d = x - y; - __retVal = length(d); -} - -float distance(const vec2 v, const vec2 u) -{ - const vec2 d2 = v - u; - __retVal = length(d2); -} - -float distance(const vec3 v, const vec3 u) -{ - const vec3 d3 = v - u; - __retVal = length(d3); -} - -float distance(const vec4 v, const vec4 u) -{ - const vec4 d4 = v - u; - __retVal = length(d4); -} - - -//// cross - -vec3 cross(const vec3 v, const vec3 u) -{ - __asm vec3_cross __retVal.xyz, v, u; -} - - -//// faceforward - -float faceforward(const float N, const float I, const float Nref) -{ - // this could probably be done better - const float d = dot(Nref, I); - float s; - __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 - return mix(-N, N, s); -} - -vec2 faceforward(const vec2 N, const vec2 I, const vec2 Nref) -{ - // this could probably be done better - const float d = dot(Nref, I); - float s; - __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 - return mix(-N, N, s); -} - -vec3 faceforward(const vec3 N, const vec3 I, const vec3 Nref) -{ - // this could probably be done better - const float d = dot(Nref, I); - float s; - __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 - return mix(-N, N, s); -} - -vec4 faceforward(const vec4 N, const vec4 I, const vec4 Nref) -{ - // this could probably be done better - const float d = dot(Nref, I); - float s; - __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 - return mix(-N, N, s); -} - - -//// reflect - -float reflect(const float I, const float N) -{ - return I - 2.0 * dot(N, I) * N; -} - -vec2 reflect(const vec2 I, const vec2 N) -{ - return I - 2.0 * dot(N, I) * N; -} - -vec3 reflect(const vec3 I, const vec3 N) -{ - return I - 2.0 * dot(N, I) * N; -} - -vec4 reflect(const vec4 I, const vec4 N) -{ - return I - 2.0 * dot(N, I) * N; -} - -//// refract - -float refract(const float I, const float N, const float eta) -{ - float n_dot_i = dot(N, I); - float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); - float retval; - if (k < 0.0) - retval = 0.0; - else - retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; - return retval; -} - -vec2 refract(const vec2 I, const vec2 N, const float eta) -{ - float n_dot_i = dot(N, I); - float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); - vec2 retval; - if (k < 0.0) - retval = vec2(0.0); - else - retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; - return retval; -} - -vec3 refract(const vec3 I, const vec3 N, const float eta) -{ - float n_dot_i = dot(N, I); - float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); - vec3 retval; - if (k < 0.0) - retval = vec3(0.0); - else - retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; - return retval; -} - -vec4 refract(const vec4 I, const vec4 N, const float eta) -{ - float n_dot_i = dot(N, I); - float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); - vec4 retval; - if (k < 0.0) - retval = vec4(0.0); - else - retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; - return retval; -} - - - - -// -// 8.5 Matrix Functions -// - -mat2 matrixCompMult (mat2 m, mat2 n) { - return mat2 (m[0] * n[0], m[1] * n[1]); -} - -mat3 matrixCompMult (mat3 m, mat3 n) { - return mat3 (m[0] * n[0], m[1] * n[1], m[2] * n[2]); -} - -mat4 matrixCompMult (mat4 m, mat4 n) { - return mat4 (m[0] * n[0], m[1] * n[1], m[2] * n[2], m[3] * n[3]); -} - - - - -// -// 8.6 Vector Relational Functions -// - -//// lessThan - -bvec2 lessThan(const vec2 u, const vec2 v) -{ - __asm vec4_slt __retVal.xy, u, v; -} - -bvec3 lessThan(const vec3 u, const vec3 v) -{ - __asm vec4_slt __retVal.xyz, u, v; -} - -bvec4 lessThan(const vec4 u, const vec4 v) -{ - __asm vec4_slt __retVal, u, v; -} - -bvec2 lessThan(const ivec2 u, const ivec2 v) -{ - __asm vec4_slt __retVal.xy, u, v; -} - -bvec3 lessThan(const ivec3 u, const ivec3 v) -{ - __asm vec4_slt __retVal.xyz, u, v; -} - -bvec4 lessThan(const ivec4 u, const ivec4 v) -{ - __asm vec4_slt __retVal, u, v; -} - - -//// lessThanEqual - -bvec2 lessThanEqual(const vec2 u, const vec2 v) -{ - __asm vec4_sle __retVal.xy, u, v; -} - -bvec3 lessThanEqual(const vec3 u, const vec3 v) -{ - __asm vec4_sle __retVal.xyz, u, v; -} - -bvec4 lessThanEqual(const vec4 u, const vec4 v) -{ - __asm vec4_sle __retVal, u, v; -} - -bvec2 lessThanEqual(const ivec2 u, const ivec2 v) -{ - __asm vec4_sle __retVal.xy, u, v; -} - -bvec3 lessThanEqual(const ivec3 u, const ivec3 v) -{ - __asm vec4_sle __retVal.xyz, u, v; -} - -bvec4 lessThanEqual(const ivec4 u, const ivec4 v) -{ - __asm vec4_sle __retVal, u, v; -} - - -//// greaterThan - -bvec2 greaterThan(const vec2 u, const vec2 v) -{ - __asm vec4_sgt __retVal.xy, u, v; -} - -bvec3 greaterThan(const vec3 u, const vec3 v) -{ - __asm vec4_sgt __retVal.xyz, u, v; -} - -bvec4 greaterThan(const vec4 u, const vec4 v) -{ - __asm vec4_sgt __retVal, u, v; -} - -bvec2 greaterThan(const ivec2 u, const ivec2 v) -{ - __asm vec4_sgt __retVal.xy, u.xy, v.xy; -} - -bvec3 greaterThan(const ivec3 u, const ivec3 v) -{ - __asm vec4_sgt __retVal.xyz, u, v; -} - -bvec4 greaterThan(const ivec4 u, const ivec4 v) -{ - __asm vec4_sgt __retVal, u, v; -} - - -//// greaterThanEqual - -bvec2 greaterThanEqual(const vec2 u, const vec2 v) -{ - __asm vec4_sge __retVal.xy, u, v; -} - -bvec3 greaterThanEqual(const vec3 u, const vec3 v) -{ - __asm vec4_sge __retVal.xyz, u, v; -} - -bvec4 greaterThanEqual(const vec4 u, const vec4 v) -{ - __asm vec4_sge __retVal, u, v; -} - -bvec2 greaterThanEqual(const ivec2 u, const ivec2 v) -{ - __asm vec4_sge __retVal.xy, u, v; -} - -bvec3 greaterThanEqual(const ivec3 u, const ivec3 v) -{ - __asm vec4_sge __retVal.xyz, u, v; -} - -bvec4 greaterThanEqual(const ivec4 u, const ivec4 v) -{ - __asm vec4_sge __retVal, u, v; -} - - -//// equal - -bvec2 equal(const vec2 u, const vec2 v) -{ - __asm vec4_seq __retVal.xy, u, v; -} - -bvec3 equal(const vec3 u, const vec3 v) -{ - __asm vec4_seq __retVal.xyz, u, v; -} - -bvec4 equal(const vec4 u, const vec4 v) -{ - __asm vec4_seq __retVal, u, v; -} - -bvec2 equal(const ivec2 u, const ivec2 v) -{ - __asm vec4_seq __retVal.xy, u, v; -} - -bvec3 equal(const ivec3 u, const ivec3 v) -{ - __asm vec4_seq __retVal.xyz, u, v; -} - -bvec4 equal(const ivec4 u, const ivec4 v) -{ - __asm vec4_seq __retVal, u, v; -} - -bvec2 equal(const bvec2 u, const bvec2 v) -{ - __asm vec4_seq __retVal.xy, u, v; -} - -bvec3 equal(const bvec3 u, const bvec3 v) -{ - __asm vec4_seq __retVal.xyz, u, v; -} - -bvec4 equal(const bvec4 u, const bvec4 v) -{ - __asm vec4_seq __retVal, u, v; -} - - - - -//// notEqual - -bvec2 notEqual(const vec2 u, const vec2 v) -{ - __asm vec4_sne __retVal.xy, u, v; -} - -bvec3 notEqual(const vec3 u, const vec3 v) -{ - __asm vec4_sne __retVal.xyz, u, v; -} - -bvec4 notEqual(const vec4 u, const vec4 v) -{ - __asm vec4_sne __retVal, u, v; -} - -bvec2 notEqual(const ivec2 u, const ivec2 v) -{ - __asm vec4_sne __retVal.xy, u, v; -} - -bvec3 notEqual(const ivec3 u, const ivec3 v) -{ - __asm vec4_sne __retVal.xyz, u, v; -} - -bvec4 notEqual(const ivec4 u, const ivec4 v) -{ - __asm vec4_sne __retVal, u, v; -} - -bvec2 notEqual(const bvec2 u, const bvec2 v) -{ - __asm vec4_sne __retVal.xy, u, v; -} - -bvec3 notEqual(const bvec3 u, const bvec3 v) -{ - __asm vec4_sne __retVal.xyz, u, v; -} - -bvec4 notEqual(const bvec4 u, const bvec4 v) -{ - __asm vec4_sne __retVal, u, v; -} - - - -//// any - -bool any(const bvec2 v) -{ - float sum; - __asm vec4_add sum.x, v.x, v.y; - __asm vec4_sne __retVal.x, sum.x, 0.0; -} - -bool any(const bvec3 v) -{ - float sum; - __asm vec4_add sum.x, v.x, v.y; - __asm vec4_add sum.x, sum.x, v.z; - __asm vec4_sne __retVal.x, sum.x, 0.0; -} - -bool any(const bvec4 v) -{ - float sum; - __asm vec4_add sum.x, v.x, v.y; - __asm vec4_add sum.x, sum.x, v.z; - __asm vec4_add sum.x, sum.x, v.w; - __asm vec4_sne __retVal.x, sum.x, 0.0; -} - - -//// all - -bool all (const bvec2 v) -{ - float prod; - __asm vec4_multiply prod, v.x, v.y; - __asm vec4_sne __retVal, prod, 0.0; -} - -bool all (const bvec3 v) -{ - float prod; - __asm vec4_multiply prod, v.x, v.y; - __asm vec4_multiply prod, prod, v.z; - __asm vec4_sne __retVal, prod, 0.0; -} - -bool all (const bvec4 v) -{ - float prod; - __asm vec4_multiply prod, v.x, v.y; - __asm vec4_multiply prod, prod, v.z; - __asm vec4_multiply prod, prod, v.w; - __asm vec4_sne __retVal, prod, 0.0; -} - - - -//// not - -bvec2 not (const bvec2 v) -{ - __asm vec4_seq __retVal.xy, v, 0.0; -} - -bvec3 not (const bvec3 v) -{ - __asm vec4_seq __retVal.xyz, v, 0.0; -} - -bvec4 not (const bvec4 v) -{ - __asm vec4_seq __retVal, v, 0.0; -} - - - -//// Texture Lookup Functions (for both fragment and vertex shaders) - -vec4 texture1D(const sampler1D sampler, const float coord) -{ - __asm vec4_tex_1d __retVal, sampler, coord; -} - -vec4 texture1DProj(const sampler1D sampler, const vec2 coord) -{ - // need to swizzle .y into .w - __asm vec4_tex_1d_proj __retVal, sampler, coord.xyyy; -} - -vec4 texture1DProj(const sampler1D sampler, const vec4 coord) -{ - __asm vec4_tex_1d_proj __retVal, sampler, coord; -} - - -vec4 texture2D(const sampler2D sampler, const vec2 coord) -{ - __asm vec4_tex_2d __retVal, sampler, coord; -} - -vec4 texture2DProj(const sampler2D sampler, const vec3 coord) -{ - // need to swizzle 'z' into 'w'. - __asm vec4_tex_2d_proj __retVal, sampler, coord.xyzz; -} - -vec4 texture2DProj(const sampler2D sampler, const vec4 coord) -{ - __asm vec4_tex_2d_proj __retVal, sampler, coord; -} - - -vec4 texture3D(const sampler3D sampler, const vec3 coord) -{ - __asm vec4_tex_3d __retVal, sampler, coord; -} - -vec4 texture3DProj(const sampler3D sampler, const vec4 coord) -{ - __asm vec4_tex_3d_proj __retVal, sampler, coord; -} - - -vec4 textureCube(const samplerCube sampler, const vec3 coord) -{ - __asm vec4_tex_cube __retVal, sampler, coord; -} - - - -vec4 shadow1D(const sampler1DShadow sampler, const vec3 coord) -{ - __asm vec4_tex_1d_shadow __retVal, sampler, coord; -} - -vec4 shadow1DProj(const sampler1DShadow sampler, const vec4 coord) -{ - // .s and .p will be divided by .q - __asm vec4_tex_1d_proj_shadow __retVal, sampler, coord; -} - -vec4 shadow2D(const sampler2DShadow sampler, const vec3 coord) -{ - __asm vec4_tex_2d_shadow __retVal, sampler, coord; -} - -vec4 shadow2DProj(const sampler2DShadow sampler, const vec4 coord) -{ - // .s, .t and .p will be divided by .q - __asm vec4_tex_2d_proj_shadow __retVal, sampler, coord; -} - - -//// GL_ARB_texture_rectangle: -vec4 texture2DRect(const sampler2DRect sampler, const vec2 coord) -{ - __asm vec4_tex_rect __retVal, sampler, coord; -} - -vec4 texture2DRectProj(const sampler2DRect sampler, const vec3 coord) -{ - // need to swizzle .y into .w - __asm vec4_tex_rect_proj __retVal, sampler, coord.xyzz; -} - -vec4 texture2DRectProj(const sampler2DRect sampler, const vec4 coord) -{ - __asm vec4_tex_rect_proj __retVal, sampler, ccoord; -} - -vec4 shadow2DRect(const sampler2DRectShadow sampler, const vec3 coord) -{ - __asm vec4_tex_rect_shadow __retVal, sampler, coord; -} - -vec4 shadow2DRectProj(const sampler2DRectShadow sampler, const vec4 coord) -{ - __asm vec4_tex_rect_proj_shadow __retVal, sampler, coord; -} - - - -//// GL_EXT_texture_array -vec4 texture1DArray(const sampler1DArray sampler, const vec2 coord) -{ - __asm vec4_tex_1d_array __retVal, sampler, coord; -} - -vec4 texture2DArray(const sampler2DArray sampler, const vec3 coord) -{ - __asm vec4_tex_2d_array __retVal, sampler, coord; -} - - -// -// 8.9 Noise Functions -// -// AUTHOR: Stefan Gustavson (stegu@itn.liu.se), Nov 26, 2005 -// - -float noise1(const float x) -{ - __asm float_noise1 __retVal, x; -} - - -float noise1(const vec2 x) -{ - __asm float_noise2 __retVal, x; -} - -float noise1(const vec3 x) -{ - __asm float_noise3 __retVal, x; -} - -float noise1(const vec4 x) -{ - __asm float_noise4 __retVal, x; -} - -vec2 noise2(const float x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + 19.34); -} - -vec2 noise2(const vec2 x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + vec2(19.34, 7.66)); -} - -vec2 noise2(const vec3 x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + vec3(19.34, 7.66, 3.23)); -} - -vec2 noise2(const vec4 x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + vec4(19.34, 7.66, 3.23, 2.77)); -} - -vec3 noise3(const float x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + 19.34); - __retVal.z = noise1(x + 5.47); -} - -vec3 noise3(const vec2 x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + vec2(19.34, 7.66)); - __retVal.z = noise1(x + vec2(5.47, 17.85)); -} - -vec3 noise3(const vec3 x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + vec3(19.34, 7.66, 3.23)); - __retVal.z = noise1(x + vec3(5.47, 17.85, 11.04)); -} - -vec3 noise3(const vec4 x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + vec4(19.34, 7.66, 3.23, 2.77)); - __retVal.z = noise1(x + vec4(5.47, 17.85, 11.04, 13.19)); -} - -vec4 noise4(const float x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + 19.34); - __retVal.z = noise1(x + 5.47); - __retVal.w = noise1(x + 23.54); -} - -vec4 noise4(const vec2 x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + vec2 (19.34, 7.66)); - __retVal.z = noise1(x + vec2 (5.47, 17.85)); - __retVal.w = noise1(x + vec2 (23.54, 29.11)); -} - -vec4 noise4(const vec3 x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + vec3(19.34, 7.66, 3.23)); - __retVal.z = noise1(x + vec3(5.47, 17.85, 11.04)); - __retVal.w = noise1(x + vec3(23.54, 29.11, 31.91)); -} - -vec4 noise4(const vec4 x) -{ - __retVal.x = noise1(x); - __retVal.y = noise1(x + vec4(19.34, 7.66, 3.23, 2.77)); - __retVal.z = noise1(x + vec4(5.47, 17.85, 11.04, 13.19)); - __retVal.w = noise1(x + vec4(23.54, 29.11, 31.91, 37.48)); -} diff --git a/src/mesa/slang/library/slang_core.gc b/src/mesa/slang/library/slang_core.gc deleted file mode 100644 index 0a0d15903b..0000000000 --- a/src/mesa/slang/library/slang_core.gc +++ /dev/null @@ -1,2619 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -// -// This file defines nearly all constructors and operators for built-in data -// types, using extended language syntax. In general, compiler treats -// constructors and operators as ordinary functions with some exceptions. -// For example, the language does not allow functions to be called in -// constant expressions - here the exception is made to allow it. -// -// Each implementation provides its own version of this file. Each -// implementation can define the required set of operators and constructors -// in its own fashion. -// -// The extended language syntax is only present when compiling this file. -// It is implicitly included at the very beginning of the compiled shader, -// so no built-in functions can be used. -// -// To communicate with the implementation, a special extended "__asm" keyword -// is used, followed by an instruction name (any valid identifier), a -// destination variable identifier and a list of zero or more source -// variable identifiers. -// -// A variable identifier is a variable name declared earlier in the code -// (as a function parameter, local or global variable). -// -// An instruction name designates an instruction that must be exported -// by the implementation. Each instruction receives data from source -// variable identifiers and returns data in the destination variable -// identifier. -// -// It is up to the implementation how to define a particular operator -// or constructor. If it is expected to being used rarely, it can be -// defined in terms of other operators and constructors, -// for example: -// -// ivec2 __operator + (const ivec2 x, const ivec2 y) { -// return ivec2 (x[0] + y[0], x[1] + y[1]); -// } -// -// If a particular operator or constructor is expected to be used very -// often or is an atomic operation (that is, an operation that cannot be -// expressed in terms of other operations or would create a dependency -// cycle) it must be defined using one or more __asm constructs. -// -// Each implementation must define constructors for all scalar types -// (bool, float, int). There are 9 scalar-to-scalar constructors -// (including identity constructors). However, since the language -// introduces special constructors (like matrix constructor with a single -// scalar value), implementations must also implement these cases. -// The compiler provides the following algorithm when resolving a constructor: -// - try to find a constructor with a prototype matching ours, -// - if no constructor is found and this is a scalar-to-scalar constructor, -// raise an error, -// - if a constructor is found, execute it and return, -// - count the size of the constructor parameter list - if it is less than -// the size of our constructor's type, raise an error, -// - for each parameter in the list do a recursive constructor matching for -// appropriate scalar fields in the constructed variable, -// -// Each implementation must also define a set of operators that deal with -// built-in data types. -// There are four kinds of operators: -// 1) Operators that are implemented only by the compiler: "()" (function -// call), "," (sequence) and "?:" (selection). -// 2) Operators that are implemented by the compiler by expressing it in -// terms of other operators: -// - "." (field selection) - translated to subscript access, -// - "&&" (logical and) - translated to "<left_expr> ? <right_expr> : -// false", -// - "||" (logical or) - translated to "<left_expr> ? true : <right_expr>", -// 3) Operators that can be defined by the implementation and if the required -// prototype is not found, standard behaviour is used: -// - "==", "!=", "=" (equality, assignment) - compare or assign -// matching fields one-by-one; -// note that at least operators for scalar data types must be defined -// by the implementation to get it work, -// 4) All other operators not mentioned above. If no required prototype is -// found, an error is raised. An implementation must follow the language -// specification to provide all valid operator prototypes. -// - - - -//// Basic, scalar constructors/casts - -int __constructor(const float f) -{ - __asm vec4_to_ivec4 __retVal, f; -} - -int __constructor(const bool b) -{ - __retVal = b; -} - -int __constructor(const int i) -{ - __retVal = i; -} - -bool __constructor(const int i) -{ - __asm vec4_sne __retVal, i, 0.0; -} - -bool __constructor(const float f) -{ - __asm vec4_sne __retVal, f, 0.0; -} - -bool __constructor(const bool b) -{ - __retVal = b; -} - -float __constructor(const int i) -{ - __asm ivec4_to_vec4 __retVal, i; -} - -float __constructor(const bool b) -{ - __asm ivec4_to_vec4 __retVal, b; -} - -float __constructor(const float f) -{ - __retVal = f; -} - - -//// vec2 constructors - -vec2 __constructor(const float x, const float y) -{ - __retVal.x = x; - __retVal.y = y; -} - -vec2 __constructor(const float f) -{ - __asm vec4_move __retVal.xy, f; -} - -vec2 __constructor(const int i) -{ - __asm ivec4_to_vec4 __retVal.xy, i; -} - -vec2 __constructor(const bool b) -{ - __asm ivec4_to_vec4 __retVal.xy, b; -} - -vec2 __constructor(const bvec2 b) -{ -// __retVal = b; - __asm ivec4_to_vec4 __retVal.xy, b; -} - -vec2 __constructor(const vec3 v) -{ - __asm vec4_move __retVal.xy, v.xy; -} - -vec2 __constructor(const vec4 v) -{ - __asm vec4_move __retVal.xy, v.xy; -} - - -//// vec3 constructors - -vec3 __constructor(const float x, const float y, const float z) -{ - __retVal.x = x; - __retVal.y = y; - __retVal.z = z; -} - -vec3 __constructor(const float f) -{ - // Note: this could be "__retVal.xyz = f" but that's an illegal assignment - __asm vec4_move __retVal.xyz, f; -} - -vec3 __constructor(const int i) -{ - __asm ivec4_to_vec4 __retVal.xyz, i; -} - -vec3 __constructor(const bool b) -{ - __asm ivec4_to_vec4 __retVal.xyz, b; -} - -vec3 __constructor(const bvec3 b) -{ - __asm ivec4_to_vec4 __retVal.xyz, b; -} - -vec3 __constructor(const vec4 v) -{ - __asm vec4_move __retVal.xyz, v; -} - - -//// vec4 constructors - -vec4 __constructor(const float x, const float y, const float z, const float w) -{ - __retVal.x = x; - __retVal.y = y; - __retVal.z = z; - __retVal.w = w; -} - -vec4 __constructor(const float f) -{ - // Note: this could be "__retVal = f" but that's an illegal assignment - __asm vec4_move __retVal, f; -} - -vec4 __constructor(const int i) -{ - __asm ivec4_to_vec4 __retVal, i; -} - -vec4 __constructor(const bool b) -{ - __asm ivec4_to_vec4 __retVal, b; -} - -vec4 __constructor(const bvec4 b) -{ - __asm ivec4_to_vec4 __retVal, b; -} - -vec4 __constructor(const ivec4 i) -{ - __asm ivec4_to_vec4 __retVal, i; -} - -vec4 __constructor(const vec3 v3, const float f) -{ - // XXX this constructor shouldn't be needed anymore - __retVal.xyz = v3; - __retVal.w = f; -} - -vec4 __constructor(const vec2 v2, const float f1, const float f2) -{ - // XXX this constructor shouldn't be needed anymore - __retVal.xy = v2; - __retVal.z = f1; - __retVal.w = f2; -} - - -//// ivec2 constructors - -ivec2 __constructor(const int i, const int j) -{ - __retVal.x = i; - __retVal.y = j; -} - -ivec2 __constructor(const int i) -{ - __asm vec4_move __retVal.xy, i; -} - -ivec2 __constructor(const float f) -{ - __asm vec4_to_ivec4 __retVal.xy, f; -} - -ivec2 __constructor(const bool b) -{ - __asm vec4_to_ivec4 __retVal.xy, b; -} - - -//// ivec3 constructors - -ivec3 __constructor(const int i, const int j, const int k) -{ - __retVal.x = i; - __retVal.y = j; - __retVal.z = k; -} - -ivec3 __constructor(const int i) -{ - __asm vec4_move __retVal.xyz, i; -} - -ivec3 __constructor(const float f) -{ - __asm vec4_to_ivec4 __retVal.xyz, f; -} - -ivec3 __constructor(const bool b) -{ - __asm vec4_move __retVal.xyz, b; -} - - -//// ivec4 constructors - -ivec4 __constructor(const int x, const int y, const int z, const int w) -{ - __retVal.x = x; - __retVal.y = y; - __retVal.z = z; - __retVal.w = w; -} - -ivec4 __constructor(const int i) -{ - __asm vec4_move __retVal, i; -} - -ivec4 __constructor(const float f) -{ - __asm vec4_to_ivec4 __retVal, f; -} - -ivec4 __constructor(const bool b) -{ - __asm vec4_to_ivec4 __retVal, b; -} - - -//// bvec2 constructors - -bvec2 __constructor(const bool b1, const bool b2) -{ - __retVal.x = b1; - __retVal.y = b2; -} - -bvec2 __constructor(const int i1, const int i2) -{ - __asm vec4_sne __retVal.x, i1, 0.0; - __asm vec4_sne __retVal.y, i2, 0.0; -} - - -bvec2 __constructor(const bool b) -{ - __asm vec4_move __retVal.xy, b; -} - -bvec2 __constructor(const float f) -{ - __asm vec4_sne __retVal.xy, f, 0.0; -} - -bvec2 __constructor(const int i) -{ - __asm vec4_sne __retVal.xy, i, 0.0; -} - -bvec2 __constructor(const vec2 v) -{ - __asm vec4_sne __retVal.xy, v, 0.0; -} - -bvec2 __constructor(const ivec2 v) -{ - __asm vec4_sne __retVal.xy, v, 0.0; -} - - - -//// bvec3 constructors - -bvec3 __constructor(const bool b1, const bool b2, const bool b3) -{ - __retVal.x = b1; - __retVal.y = b2; - __retVal.z = b3; -} - -bvec3 __constructor(const float f1, const float f2, const float f3) -{ - __asm vec4_sne __retVal.x, f1, 0.0; - __asm vec4_sne __retVal.y, f2, 0.0; - __asm vec4_sne __retVal.z, f3, 0.0; -} - -bvec3 __constructor(const bool b) -{ - __asm vec4_move __retVal.xyz, b; -} - -bvec3 __constructor(const float f) -{ - __asm vec4_sne __retVal.xyz, f, 0.0; -} - -bvec3 __constructor(const int i) -{ - __asm vec4_sne __retVal.xyz, i, 0.0; -} - -bvec3 __constructor(const vec3 v) -{ - __asm vec4_sne __retVal.xyz, v, 0.0; -} - -bvec3 __constructor(const ivec3 v) -{ - __asm vec4_sne __retVal.xyz, v, 0.0; -} - - - -//// bvec4 constructors - -bvec4 __constructor(const bool b1, const bool b2, const bool b3, const bool b4) -{ - __retVal.x = b1; - __retVal.y = b2; - __retVal.z = b3; - __retVal.w = b4; -} - -bvec4 __constructor(const float f1, const float f2, const float f3, const float f4) -{ - const float zero = 0.0; - __asm vec4_sne __retVal.x, f1, zero; - __asm vec4_sne __retVal.y, f2, zero; - __asm vec4_sne __retVal.z, f3, zero; - __asm vec4_sne __retVal.w, f4, zero; -} - -bvec4 __constructor(const bool b) -{ - __asm vec4_move __retVal.xyzw, b; -} - -bvec4 __constructor(const float f) -{ - __asm vec4_sne __retVal.xyzw, f, 0.0; -} - -bvec4 __constructor(const int i) -{ - __asm vec4_sne __retVal.xyzw, i, 0.0; -} - -bvec4 __constructor(const vec4 v) -{ - __asm vec4_sne __retVal.xyzw, v, 0.0; -} - -bvec4 __constructor(const ivec4 v) -{ - __asm vec4_sne __retVal.xyzw, v, 0.0; -} - - - -//// mat2 constructors - -mat2 __constructor(const float m00, const float m10, - const float m01, const float m11) -{ - __retVal[0].x = m00; - __retVal[0].y = m10; - __retVal[1].x = m01; - __retVal[1].y = m11; -} - -mat2 __constructor(const float f) -{ - __retVal[0].x = f; - __retVal[0].y = 0.0; - __retVal[1].x = 0.0; - __retVal[1].y = f; -} - -mat2 __constructor(const int i) -{ - return mat2(float(i)); -} - -mat2 __constructor(const bool b) -{ - return mat2(float(b)); -} - -mat2 __constructor(const vec2 c0, const vec2 c1) -{ - __retVal[0] = c0; - __retVal[1] = c1; -} - - -//// mat3 constructors - -mat3 __constructor(const float m00, const float m10, const float m20, - const float m01, const float m11, const float m21, - const float m02, const float m12, const float m22) -{ - __retVal[0].x = m00; - __retVal[0].y = m10; - __retVal[0].z = m20; - __retVal[1].x = m01; - __retVal[1].y = m11; - __retVal[1].z = m21; - __retVal[2].x = m02; - __retVal[2].y = m12; - __retVal[2].z = m22; -} - -mat3 __constructor(const float f) -{ - vec2 v = vec2(f, 0.0); - __retVal[0] = v.xyy; - __retVal[1] = v.yxy; - __retVal[2] = v.yyx; -} - -mat3 __constructor(const int i) -{ - return mat3(float(i)); -} - -mat3 __constructor(const bool b) -{ - return mat3(float(b)); -} - -mat3 __constructor(const vec3 c0, const vec3 c1, const vec3 c2) -{ - __retVal[0] = c0; - __retVal[1] = c1; - __retVal[2] = c2; -} - - -//// mat4 constructors - -mat4 __constructor(const float m00, const float m10, const float m20, const float m30, - const float m01, const float m11, const float m21, const float m31, - const float m02, const float m12, const float m22, const float m32, - const float m03, const float m13, const float m23, const float m33) -{ - __retVal[0].x = m00; - __retVal[0].y = m10; - __retVal[0].z = m20; - __retVal[0].w = m30; - __retVal[1].x = m01; - __retVal[1].y = m11; - __retVal[1].z = m21; - __retVal[1].w = m31; - __retVal[2].x = m02; - __retVal[2].y = m12; - __retVal[2].z = m22; - __retVal[2].w = m32; - __retVal[3].x = m03; - __retVal[3].y = m13; - __retVal[3].z = m23; - __retVal[3].w = m33; -} - - -mat4 __constructor(const float f) -{ - vec2 v = vec2(f, 0.0); - __retVal[0] = v.xyyy; - __retVal[1] = v.yxyy; - __retVal[2] = v.yyxy; - __retVal[3] = v.yyyx; -} - -mat4 __constructor(const int i) -{ - return mat4(float(i)); -} - -mat4 __constructor(const bool b) -{ - return mat4(float(b)); -} - -mat4 __constructor(const vec4 c0, const vec4 c1, const vec4 c2, const vec4 c3) -{ - __retVal[0] = c0; - __retVal[1] = c1; - __retVal[2] = c2; - __retVal[3] = c3; -} - - - -//// Basic int operators - -int __operator + (const int a, const int b) -{ - __asm vec4_add __retVal, a, b; -} - -int __operator - (const int a, const int b) -{ - __asm vec4_subtract __retVal, a, b; -} - -int __operator * (const int a, const int b) -{ - __asm vec4_multiply __retVal, a, b; -} - -int __operator / (const int a, const int b) -{ - float bInv, x; - __asm float_rcp bInv, b; - __asm vec4_multiply x, a, bInv; - __asm vec4_to_ivec4 __retVal, x; -} - - -//// Basic ivec2 operators - -ivec2 __operator + (const ivec2 a, const ivec2 b) -{ - __asm vec4_add __retVal, a, b; -} - -ivec2 __operator - (const ivec2 a, const ivec2 b) -{ - __asm vec4_subtract __retVal, a, b; -} - -ivec2 __operator * (const ivec2 a, const ivec2 b) -{ - __asm vec4_multiply __retVal, a, b; -} - -ivec2 __operator / (const ivec2 a, const ivec2 b) -{ - vec2 bInv, x; - __asm float_rcp bInv.x, b.x; - __asm float_rcp bInv.y, b.y; - __asm vec4_multiply x, a, bInv; - __asm vec4_to_ivec4 __retVal, x; -} - - -//// Basic ivec3 operators - -ivec3 __operator + (const ivec3 a, const ivec3 b) -{ - __asm vec4_add __retVal, a, b; -} - -ivec3 __operator - (const ivec3 a, const ivec3 b) -{ - __asm vec4_subtract __retVal, a, b; -} - -ivec3 __operator * (const ivec3 a, const ivec3 b) -{ - __asm vec4_multiply __retVal, a, b; -} - -ivec3 __operator / (const ivec3 a, const ivec3 b) -{ - vec3 bInv, x; - __asm float_rcp bInv.x, b.x; - __asm float_rcp bInv.y, b.y; - __asm float_rcp bInv.z, b.z; - __asm vec4_multiply x, a, bInv; - __asm vec4_to_ivec4 __retVal, x; -} - - -//// Basic ivec4 operators - -ivec4 __operator + (const ivec4 a, const ivec4 b) -{ - __asm vec4_add __retVal, a, b; -} - -ivec4 __operator - (const ivec4 a, const ivec4 b) -{ - __asm vec4_subtract __retVal, a, b; -} - -ivec4 __operator * (const ivec4 a, const ivec4 b) -{ - __asm vec4_multiply __retVal, a, b; -} - -ivec4 __operator / (const ivec4 a, const ivec4 b) -{ - vec4 bInv, x; - __asm float_rcp bInv.x, b.x; - __asm float_rcp bInv.y, b.y; - __asm float_rcp bInv.z, b.z; - __asm float_rcp bInv.w, b.w; - __asm vec4_multiply x, a, bInv; - __asm vec4_to_ivec4 __retVal, x; -} - - -//// Basic float operators - -float __operator + (const float a, const float b) -{ - __asm vec4_add __retVal, a, b; -} - -float __operator - (const float a, const float b) -{ - __asm vec4_subtract __retVal, a, b; -} - -float __operator * (const float a, const float b) -{ - __asm vec4_multiply __retVal, a, b; -} - -float __operator / (const float a, const float b) -{ - float bInv; - __asm float_rcp bInv.x, b; - __asm vec4_multiply __retVal, a, bInv; -} - - -//// Basic vec2 operators - -vec2 __operator + (const vec2 v, const vec2 u) -{ - __asm vec4_add __retVal.xy, v, u; -} - -vec2 __operator - (const vec2 v, const vec2 u) -{ - __asm vec4_subtract __retVal.xy, v, u; -} - -vec2 __operator * (const vec2 v, const vec2 u) -{ - __asm vec4_multiply __retVal.xy, v, u; -} - -vec2 __operator / (const vec2 v, const vec2 u) -{ - vec2 w; // = 1 / u - __asm float_rcp w.x, u.x; - __asm float_rcp w.y, u.y; - __asm vec4_multiply __retVal.xy, v, w; -} - - -//// Basic vec3 operators - -vec3 __operator + (const vec3 v, const vec3 u) -{ - __asm vec4_add __retVal.xyz, v, u; -} - -vec3 __operator - (const vec3 v, const vec3 u) -{ - __asm vec4_subtract __retVal.xyz, v, u; -} - -vec3 __operator * (const vec3 v, const vec3 u) -{ - __asm vec4_multiply __retVal.xyz, v, u; -} - -vec3 __operator / (const vec3 v, const vec3 u) -{ - vec3 w; // = 1 / u - __asm float_rcp w.x, u.x; - __asm float_rcp w.y, u.y; - __asm float_rcp w.z, u.z; - __asm vec4_multiply __retVal.xyz, v, w; -} - - -//// Basic vec4 operators - -vec4 __operator + (const vec4 v, const vec4 u) -{ - __asm vec4_add __retVal, v, u; -} - -vec4 __operator - (const vec4 v, const vec4 u) -{ - __asm vec4_subtract __retVal, v, u; -} - -vec4 __operator * (const vec4 v, const vec4 u) -{ - __asm vec4_multiply __retVal, v, u; -} - -vec4 __operator / (const vec4 v, const vec4 u) -{ - vec4 w; // = 1 / u - __asm float_rcp w.x, u.x; - __asm float_rcp w.y, u.y; - __asm float_rcp w.z, u.z; - __asm float_rcp w.w, u.w; - __asm vec4_multiply __retVal, v, w; -} - - - - -//// Basic vec2/float operators - -vec2 __operator + (const float a, const vec2 u) -{ - __asm vec4_add __retVal.xy, a, u.xy; -} - -vec2 __operator + (const vec2 v, const float b) -{ - __asm vec4_add __retVal.xy, v.xy, b; -} - -vec2 __operator - (const float a, const vec2 u) -{ - __asm vec4_subtract __retVal.xy, a, u.xy; -} - -vec2 __operator - (const vec2 v, const float b) -{ - __asm vec4_subtract __retVal.xy, v.xy, b; -} - -vec2 __operator * (const float a, const vec2 u) -{ - __asm vec4_multiply __retVal.xy, a, u.xy; -} - -vec2 __operator * (const vec2 v, const float b) -{ - __asm vec4_multiply __retVal.xy, v.xy, b; -} - -vec2 __operator / (const float a, const vec2 u) -{ - vec2 invU; - __asm float_rcp invU.x, u.x; - __asm float_rcp invU.y, u.y; - __asm vec4_multiply __retVal.xy, a, invU.xy; -} - -vec2 __operator / (const vec2 v, const float b) -{ - float invB; - __asm float_rcp invB, b; - __asm vec4_multiply __retVal.xy, v.xy, invB; -} - - -//// Basic vec3/float operators - -vec3 __operator + (const float a, const vec3 u) -{ - __asm vec4_add __retVal.xyz, a, u.xyz; -} - -vec3 __operator + (const vec3 v, const float b) -{ - __asm vec4_add __retVal.xyz, v.xyz, b; -} - -vec3 __operator - (const float a, const vec3 u) -{ - __asm vec4_subtract __retVal.xyz, a, u.xyz; -} - -vec3 __operator - (const vec3 v, const float b) -{ - __asm vec4_subtract __retVal.xyz, v.xyz, b; -} - -vec3 __operator * (const float a, const vec3 u) -{ - __asm vec4_multiply __retVal.xyz, a, u.xyz; -} - -vec3 __operator * (const vec3 v, const float b) -{ - __asm vec4_multiply __retVal.xyz, v.xyz, b; -} - -vec3 __operator / (const float a, const vec3 u) -{ - vec3 invU; - __asm float_rcp invU.x, u.x; - __asm float_rcp invU.y, u.y; - __asm float_rcp invU.z, u.z; - __asm vec4_multiply __retVal.xyz, a, invU.xyz; -} - -vec3 __operator / (const vec3 v, const float b) -{ - float invB; - __asm float_rcp invB, b; - __asm vec4_multiply __retVal.xyz, v.xyz, invB; -} - - -//// Basic vec4/float operators - -vec4 __operator + (const float a, const vec4 u) -{ - __asm vec4_add __retVal, a, u; -} - -vec4 __operator + (const vec4 v, const float b) -{ - __asm vec4_add __retVal, v, b; -} - -vec4 __operator - (const float a, const vec4 u) -{ - __asm vec4_subtract __retVal, a, u; -} - -vec4 __operator - (const vec4 v, const float b) -{ - __asm vec4_subtract __retVal, v, b; -} - -vec4 __operator * (const float a, const vec4 u) -{ - __asm vec4_multiply __retVal, a, u; -} - -vec4 __operator * (const vec4 v, const float b) -{ - __asm vec4_multiply __retVal, v, b; -} - -vec4 __operator / (const float a, const vec4 u) -{ - vec4 invU; - __asm float_rcp invU.x, u.x; - __asm float_rcp invU.y, u.y; - __asm float_rcp invU.z, u.z; - __asm float_rcp invU.w, u.w; - __asm vec4_multiply __retVal, a, invU; -} - -vec4 __operator / (const vec4 v, const float b) -{ - float invB; - __asm float_rcp invB, b; - __asm vec4_multiply __retVal, v, invB; -} - - - -//// Basic ivec2/int operators - -ivec2 __operator + (const int a, const ivec2 u) -{ - __retVal = ivec2(a) + u; -} - -ivec2 __operator + (const ivec2 v, const int b) -{ - __retVal = v + ivec2(b); -} - -ivec2 __operator - (const int a, const ivec2 u) -{ - __retVal = ivec2(a) - u; -} - -ivec2 __operator - (const ivec2 v, const int b) -{ - __retVal = v - ivec2(b); -} - -ivec2 __operator * (const int a, const ivec2 u) -{ - __retVal = ivec2(a) * u; -} - -ivec2 __operator * (const ivec2 v, const int b) -{ - __retVal = v * ivec2(b); -} - -ivec2 __operator / (const int a, const ivec2 u) -{ - __retVal = ivec2(a) / u; -} - -ivec2 __operator / (const ivec2 v, const int b) -{ - __retVal = v / ivec2(b); -} - - -//// Basic ivec3/int operators - -ivec3 __operator + (const int a, const ivec3 u) -{ - __retVal = ivec3(a) + u; -} - -ivec3 __operator + (const ivec3 v, const int b) -{ - __retVal = v + ivec3(b); -} - -ivec3 __operator - (const int a, const ivec3 u) -{ - __retVal = ivec3(a) - u; -} - -ivec3 __operator - (const ivec3 v, const int b) -{ - __retVal = v - ivec3(b); -} - -ivec3 __operator * (const int a, const ivec3 u) -{ - __retVal = ivec3(a) * u; -} - -ivec3 __operator * (const ivec3 v, const int b) -{ - __retVal = v * ivec3(b); -} - -ivec3 __operator / (const int a, const ivec3 u) -{ - __retVal = ivec3(a) / u; -} - -ivec3 __operator / (const ivec3 v, const int b) -{ - __retVal = v / ivec3(b); -} - - -//// Basic ivec4/int operators - -ivec4 __operator + (const int a, const ivec4 u) -{ - __retVal = ivec4(a) + u; -} - -ivec4 __operator + (const ivec4 v, const int b) -{ - __retVal = v + ivec4(b); -} - -ivec4 __operator - (const int a, const ivec4 u) -{ - __retVal = ivec4(a) - u; -} - -ivec4 __operator - (const ivec4 v, const int b) -{ - __retVal = v - ivec4(b); -} - -ivec4 __operator * (const int a, const ivec4 u) -{ - __retVal = ivec4(a) * u; -} - -ivec4 __operator * (const ivec4 v, const int b) -{ - __retVal = v * ivec4(b); -} - -ivec4 __operator / (const int a, const ivec4 u) -{ - __retVal = ivec4(a) / u; -} - -ivec4 __operator / (const ivec4 v, const int b) -{ - __retVal = v / ivec4(b); -} - - - - -//// Unary negation operator - -int __operator - (const int a) -{ - __asm vec4_negate __retVal.x, a; -} - -ivec2 __operator - (const ivec2 v) -{ - __asm vec4_negate __retVal, v; -} - -ivec3 __operator - (const ivec3 v) -{ - __asm vec4_negate __retVal, v; -} - -ivec4 __operator - (const ivec4 v) -{ - __asm vec4_negate __retVal, v; -} - -float __operator - (const float a) -{ - __asm vec4_negate __retVal.x, a; -} - -vec2 __operator - (const vec2 v) -{ - __asm vec4_negate __retVal.xy, v.xy; -} - -vec3 __operator - (const vec3 v) -{ - __asm vec4_negate __retVal.xyz, v.xyz; -} - -vec4 __operator - (const vec4 v) -{ - __asm vec4_negate __retVal, v; -} - -mat2 __operator - (const mat2 m) -{ - __retVal[0] = -m[0]; - __retVal[1] = -m[1]; -} - -mat3 __operator - (const mat3 m) -{ - __retVal[0] = -m[0]; - __retVal[1] = -m[1]; - __retVal[2] = -m[2]; -} - -mat4 __operator - (const mat4 m) -{ - __retVal[0] = -m[0]; - __retVal[1] = -m[1]; - __retVal[2] = -m[2]; - __retVal[3] = -m[3]; -} - - - -//// dot product - -float dot(const float a, const float b) -{ - __retVal = a * b; -} - -float dot(const vec2 a, const vec2 b) -{ - __retVal = a.x * b.x + a.y * b.y; -} - -float dot(const vec3 a, const vec3 b) -{ - __asm vec3_dot __retVal, a, b; -} - -float dot(const vec4 a, const vec4 b) -{ - __asm vec4_dot __retVal, a, b; -} - - - -//// int assignment operators - -int __operator += (inout int a, const int b) -{ - a = a + b; - return a; -} - -int __operator -= (inout int a, const int b) -{ - a = a - b; - return a; -} - -int __operator *= (inout int a, const int b) -{ - a = a * b; - return a; -} - -int __operator /= (inout int a, const int b) -{ - a = a / b; - return a; -} - - -//// ivec2 assignment operators - -ivec2 __operator += (inout ivec2 v, const ivec2 u) -{ - v = v + u; - return v; -} - -ivec2 __operator -= (inout ivec2 v, const ivec2 u) -{ - v = v - u; - return v; -} - -ivec2 __operator *= (inout ivec2 v, const ivec2 u) -{ - v = v * u; - return v; -} - -ivec2 __operator /= (inout ivec2 v, const ivec2 u) -{ - v = v / u; - return v; -} - - -//// ivec3 assignment operators - -ivec3 __operator += (inout ivec3 v, const ivec3 u) -{ - v = v + u; - return v; -} - -ivec3 __operator -= (inout ivec3 v, const ivec3 u) -{ - v = v - u; - return v; -} - -ivec3 __operator *= (inout ivec3 v, const ivec3 u) -{ - v = v * u; - return v; -} - -ivec3 __operator /= (inout ivec3 v, const ivec3 u) -{ - v = v / u; - return v; -} - - -//// ivec4 assignment operators - -ivec4 __operator += (inout ivec4 v, const ivec4 u) -{ - v = v + u; - return v; -} - -ivec4 __operator -= (inout ivec4 v, const ivec4 u) -{ - v = v - u; - return v; -} - -ivec4 __operator *= (inout ivec4 v, const ivec4 u) -{ - v = v * u; - return v; -} - -ivec4 __operator /= (inout ivec4 v, const ivec4 u) -{ - v = v / u; - return v; -} - - -//// float assignment operators - -float __operator += (inout float a, const float b) -{ - a = a + b; - return a; -} - -float __operator -= (inout float a, const float b) -{ - a = a - b; - return a; -} - -float __operator *= (inout float a, const float b) -{ - a = a * b; - return a; -} - -float __operator /= (inout float a, const float b) -{ - a = a / b; - return a; -} - - -//// vec2 assignment operators - -vec2 __operator += (inout vec2 v, const vec2 u) -{ - v = v + u; - return v; -} - -vec2 __operator -= (inout vec2 v, const vec2 u) -{ - v = v - u; - return v; -} - -vec2 __operator *= (inout vec2 v, const vec2 u) -{ - v = v * u; - return v; -} - -vec2 __operator /= (inout vec2 v, const vec2 u) -{ - v = v / u; - return v; -} - - -//// vec3 assignment operators - -vec3 __operator += (inout vec3 v, const vec3 u) -{ - v = v + u; - return v; -} - -vec3 __operator -= (inout vec3 v, const vec3 u) -{ - v = v - u; - return v; -} - -vec3 __operator *= (inout vec3 v, const vec3 u) -{ - v = v * u; - return v; -} - -vec3 __operator /= (inout vec3 v, const vec3 u) -{ - v = v / u; - return v; -} - - -//// vec4 assignment operators - -vec4 __operator += (inout vec4 v, const vec4 u) -{ - v = v + u; - return v; -} - -vec4 __operator -= (inout vec4 v, const vec4 u) -{ - v = v - u; - return v; -} - -vec4 __operator *= (inout vec4 v, const vec4 u) -{ - v = v * u; - return v; -} - -vec4 __operator /= (inout vec4 v, const vec4 u) -{ - v = v / u; - return v; -} - - - -//// ivec2/int assignment operators - -ivec2 __operator += (inout ivec2 v, const int a) -{ - v = v + ivec2(a); - return v; -} - -ivec2 __operator -= (inout ivec2 v, const int a) -{ - v = v - ivec2(a); - return v; -} - -ivec2 __operator *= (inout ivec2 v, const int a) -{ - v = v * ivec2(a); - return v; -} - -ivec2 __operator /= (inout ivec2 v, const int a) -{ - v = v / ivec2(a); - return v; -} - - -//// ivec3/int assignment operators - -ivec3 __operator += (inout ivec3 v, const int a) -{ - v = v + ivec3(a); - return v; -} - -ivec3 __operator -= (inout ivec3 v, const int a) -{ - v = v - ivec3(a); - return v; -} - -ivec3 __operator *= (inout ivec3 v, const int a) -{ - v = v * ivec3(a); - return v; -} - -ivec4 __operator /= (inout ivec3 v, const int a) -{ - v = v / ivec3(a); - return v; -} - - -//// ivec4/int assignment operators - -ivec4 __operator += (inout ivec4 v, const int a) -{ - v = v + ivec4(a); - return v; -} - -ivec4 __operator -= (inout ivec4 v, const int a) -{ - v = v - ivec4(a); - return v; -} - -ivec4 __operator *= (inout ivec4 v, const int a) -{ - v = v * ivec4(a); - return v; -} - -ivec4 __operator /= (inout ivec4 v, const int a) -{ - v = v / ivec4(a); - return v; -} - - - -//// vec2/float assignment operators - -vec2 __operator += (inout vec2 v, const float a) -{ - v = v + vec2(a); - return v; -} - -vec2 __operator -= (inout vec2 v, const float a) -{ - v = v - vec2(a); - return v; -} - -vec2 __operator *= (inout vec2 v, const float a) -{ - v = v * vec2(a); - return v; -} - -vec2 __operator /= (inout vec2 v, const float a) -{ - v = v / vec2(a); - return v; -} - - -//// vec3/float assignment operators - -vec3 __operator += (inout vec3 v, const float a) -{ - v = v + vec3(a); - return v; -} - -vec3 __operator -= (inout vec3 v, const float a) -{ - v = v - vec3(a); - return v; -} - -vec3 __operator *= (inout vec3 v, const float a) -{ - v = v * vec3(a); - return v; -} - -vec3 __operator /= (inout vec3 v, const float a) -{ - v = v / vec3(a); - return v; -} - - -//// vec4/float assignment operators - -vec4 __operator += (inout vec4 v, const float a) -{ - v = v + vec4(a); - return v; -} - -vec4 __operator -= (inout vec4 v, const float a) -{ - v = v - vec4(a); - return v; -} - -vec4 __operator *= (inout vec4 v, const float a) -{ - v = v * vec4(a); - return v; -} - -vec4 __operator /= (inout vec4 v, const float a) -{ - v = v / vec4(a); - return v; -} - - - - - -//// Basic mat2 operations - -mat2 __operator + (const mat2 m, const mat2 n) -{ - __retVal[0] = m[0] + n[0]; - __retVal[1] = m[1] + n[1]; -} - -mat2 __operator - (const mat2 m, const mat2 n) -{ - __retVal[0] = m[0] - n[0]; - __retVal[1] = m[1] - n[1]; -} - -mat2 __operator * (const mat2 m, const mat2 n) -{ - __retVal[0] = m[0] * n[0].xx + m[1] * n[0].yy; - __retVal[1] = m[0] * n[1].xx + m[1] * n[1].yy; -} - -mat2 __operator / (const mat2 m, const mat2 n) -{ - __retVal[0] = m[0] / n[0]; - __retVal[1] = m[1] / n[1]; -} - - -//// Basic mat3 operations - -mat3 __operator + (const mat3 m, const mat3 n) -{ - __retVal[0] = m[0] + n[0]; - __retVal[1] = m[1] + n[1]; - __retVal[2] = m[2] + n[2]; -} - -mat3 __operator - (const mat3 m, const mat3 n) -{ - __retVal[0] = m[0] - n[0]; - __retVal[1] = m[1] - n[1]; - __retVal[2] = m[2] - n[2]; -} - -mat3 __operator * (const mat3 m, const mat3 n) -{ - __retVal[0] = m[0] * n[0].xxx + m[1] * n[0].yyy + m[2] * n[0].zzz; - __retVal[1] = m[0] * n[1].xxx + m[1] * n[1].yyy + m[2] * n[1].zzz; - __retVal[2] = m[0] * n[2].xxx + m[1] * n[2].yyy + m[2] * n[2].zzz; -} - -mat3 __operator / (const mat3 m, const mat3 n) -{ - __retVal[0] = m[0] / n[0]; - __retVal[1] = m[1] / n[1]; - __retVal[2] = m[2] / n[2]; -} - - -//// Basic mat4 operations - -mat4 __operator + (const mat4 m, const mat4 n) -{ - __retVal[0] = m[0] + n[0]; - __retVal[1] = m[1] + n[1]; - __retVal[2] = m[2] + n[2]; - __retVal[3] = m[3] + n[3]; -} - -mat4 __operator - (const mat4 m, const mat4 n) -{ - __retVal[0] = m[0] - n[0]; - __retVal[1] = m[1] - n[1]; - __retVal[2] = m[2] - n[2]; - __retVal[3] = m[3] - n[3]; -} - -mat4 __operator * (const mat4 m, const mat4 n) -{ - __retVal[0] = m[0] * n[0].xxxx + m[1] * n[0].yyyy + m[2] * n[0].zzzz + m[3] * n[0].wwww; - __retVal[1] = m[0] * n[1].xxxx + m[1] * n[1].yyyy + m[2] * n[1].zzzz + m[3] * n[1].wwww; - __retVal[2] = m[0] * n[2].xxxx + m[1] * n[2].yyyy + m[2] * n[2].zzzz + m[3] * n[2].wwww; - __retVal[3] = m[0] * n[3].xxxx + m[1] * n[3].yyyy + m[2] * n[3].zzzz + m[3] * n[3].wwww; -} - -mat4 __operator / (const mat4 m, const mat4 n) -{ - __retVal[0] = m[0] / n[0]; - __retVal[1] = m[1] / n[1]; - __retVal[2] = m[2] / n[2]; - __retVal[3] = m[3] / n[3]; -} - - -//// mat2/float operations - -mat2 __operator + (const float a, const mat2 n) -{ - __retVal[0] = a + n[0]; - __retVal[1] = a + n[1]; -} - -mat2 __operator + (const mat2 m, const float b) -{ - __retVal[0] = m[0] + b; - __retVal[1] = m[1] + b; -} - -mat2 __operator - (const float a, const mat2 n) -{ - __retVal[0] = a - n[0]; - __retVal[1] = a - n[1]; -} - -mat2 __operator - (const mat2 m, const float b) -{ - __retVal[0] = m[0] - b; - __retVal[1] = m[1] - b; -} - -mat2 __operator * (const float a, const mat2 n) -{ - __retVal[0] = a * n[0]; - __retVal[1] = a * n[1]; -} - -mat2 __operator * (const mat2 m, const float b) -{ - __retVal[0] = m[0] * b; - __retVal[1] = m[1] * b; -} - -mat2 __operator / (const float a, const mat2 n) -{ - __retVal[0] = a / n[0]; - __retVal[1] = a / n[1]; -} - -mat2 __operator / (const mat2 m, const float b) -{ - __retVal[0] = m[0] / b; - __retVal[1] = m[1] / b; -} - - -//// mat3/float operations - -mat3 __operator + (const float a, const mat3 n) -{ - __retVal[0] = a + n[0]; - __retVal[1] = a + n[1]; - __retVal[2] = a + n[2]; -} - -mat3 __operator + (const mat3 m, const float b) -{ - __retVal[0] = m[0] + b; - __retVal[1] = m[1] + b; - __retVal[2] = m[2] + b; -} - -mat3 __operator - (const float a, const mat3 n) -{ - __retVal[0] = a - n[0]; - __retVal[1] = a - n[1]; - __retVal[2] = a - n[2]; -} - -mat3 __operator - (const mat3 m, const float b) -{ - __retVal[0] = m[0] - b; - __retVal[1] = m[1] - b; - __retVal[2] = m[2] - b; -} - -mat3 __operator * (const float a, const mat3 n) -{ - __retVal[0] = a * n[0]; - __retVal[1] = a * n[1]; - __retVal[2] = a * n[2]; -} - -mat3 __operator * (const mat3 m, const float b) -{ - __retVal[0] = m[0] * b; - __retVal[1] = m[1] * b; - __retVal[2] = m[2] * b; -} - -mat3 __operator / (const float a, const mat3 n) -{ - __retVal[0] = a / n[0]; - __retVal[1] = a / n[1]; - __retVal[2] = a / n[2]; -} - -mat3 __operator / (const mat3 m, const float b) -{ - __retVal[0] = m[0] / b; - __retVal[1] = m[1] / b; - __retVal[2] = m[2] / b; -} - - -//// mat4/float operations - -mat4 __operator + (const float a, const mat4 n) -{ - __retVal[0] = a + n[0]; - __retVal[1] = a + n[1]; - __retVal[2] = a + n[2]; - __retVal[3] = a + n[3]; -} - -mat4 __operator + (const mat4 m, const float b) -{ - __retVal[0] = m[0] + b; - __retVal[1] = m[1] + b; - __retVal[2] = m[2] + b; - __retVal[3] = m[3] + b; -} - -mat4 __operator - (const float a, const mat4 n) -{ - __retVal[0] = a - n[0]; - __retVal[1] = a - n[1]; - __retVal[2] = a - n[2]; - __retVal[3] = a - n[3]; -} - -mat4 __operator - (const mat4 m, const float b) -{ - __retVal[0] = m[0] - b; - __retVal[1] = m[1] - b; - __retVal[2] = m[2] - b; - __retVal[3] = m[3] - b; -} - -mat4 __operator * (const float a, const mat4 n) -{ - __retVal[0] = a * n[0]; - __retVal[1] = a * n[1]; - __retVal[2] = a * n[2]; - __retVal[3] = a * n[3]; -} - -mat4 __operator * (const mat4 m, const float b) -{ - __retVal[0] = m[0] * b; - __retVal[1] = m[1] * b; - __retVal[2] = m[2] * b; - __retVal[3] = m[3] * b; -} - -mat4 __operator / (const float a, const mat4 n) -{ - __retVal[0] = a / n[0]; - __retVal[1] = a / n[1]; - __retVal[2] = a / n[2]; - __retVal[3] = a / n[3]; -} - -mat4 __operator / (const mat4 m, const float b) -{ - __retVal[0] = m[0] / b; - __retVal[1] = m[1] / b; - __retVal[2] = m[2] / b; - __retVal[3] = m[3] / b; -} - - - -//// matrix / vector products - -vec2 __operator * (const mat2 m, const vec2 v) -{ - __retVal = m[0] * v.xx - + m[1] * v.yy; -} - -vec2 __operator * (const vec2 v, const mat2 m) -{ - __retVal.x = dot(v, m[0]); - __retVal.y = dot(v, m[1]); -} - -vec3 __operator * (const mat3 m, const vec3 v) -{ - __retVal = m[0] * v.xxx - + m[1] * v.yyy - + m[2] * v.zzz; -} - -vec3 __operator * (const vec3 v, const mat3 m) -{ - __retVal.x = dot(v, m[0]); - __retVal.y = dot(v, m[1]); - __retVal.z = dot(v, m[2]); -} - -vec4 __operator * (const mat4 m, const vec4 v) -{ - __retVal = m[0] * v.xxxx - + m[1] * v.yyyy - + m[2] * v.zzzz - + m[3] * v.wwww; -} - -vec4 __operator * (const vec4 v, const mat4 m) -{ - __retVal.x = dot(v, m[0]); - __retVal.y = dot(v, m[1]); - __retVal.z = dot(v, m[2]); - __retVal.w = dot(v, m[3]); -} - - - -//// mat2 assignment operators - -mat2 __operator += (inout mat2 m, const mat2 n) -{ - m[0] = m[0] + n[0]; - m[1] = m[1] + n[1]; - return m; -} - -mat2 __operator -= (inout mat2 m, const mat2 n) -{ - m[0] = m[0] - n[0]; - m[1] = m[1] - n[1]; - return m; -} - -mat2 __operator *= (inout mat2 m, const mat2 n) -{ - m = m * n; - return m; -} - -mat2 __operator /= (inout mat2 m, const mat2 n) -{ - m[0] = m[0] / n[0]; - m[1] = m[1] / n[1]; - return m; -} - - -//// mat3 assignment operators - -mat3 __operator += (inout mat3 m, const mat3 n) -{ - m[0] = m[0] + n[0]; - m[1] = m[1] + n[1]; - m[2] = m[2] + n[2]; - return m; -} - -mat3 __operator -= (inout mat3 m, const mat3 n) -{ - m[0] = m[0] - n[0]; - m[1] = m[1] - n[1]; - m[2] = m[2] - n[2]; - return m; -} - -mat3 __operator *= (inout mat3 m, const mat3 n) -{ - m = m * n; - return m; -} - -mat3 __operator /= (inout mat3 m, const mat3 n) -{ - m[0] = m[0] / n[0]; - m[1] = m[1] / n[1]; - m[2] = m[2] / n[2]; - return m; -} - - -// mat4 assignment operators - -mat4 __operator += (inout mat4 m, const mat4 n) -{ - m[0] = m[0] + n[0]; - m[1] = m[1] + n[1]; - m[2] = m[2] + n[2]; - m[3] = m[3] + n[3]; - return m; -} - -mat4 __operator -= (inout mat4 m, const mat4 n) -{ - m[0] = m[0] - n[0]; - m[1] = m[1] - n[1]; - m[2] = m[2] - n[2]; - m[3] = m[3] - n[3]; - return m; -} - -mat4 __operator *= (inout mat4 m, const mat4 n) -{ - m = m * n; - return m; -} - -mat4 __operator /= (inout mat4 m, const mat4 n) -{ - m[0] = m[0] / n[0]; - m[1] = m[1] / n[1]; - m[2] = m[2] / n[2]; - m[3] = m[3] / n[3]; - return m; -} - - -//// mat2/float assignment operators - -mat2 __operator += (inout mat2 m, const float a) -{ - vec2 v = vec2(a); - m[0] = m[0] + v; - m[1] = m[1] + v; - return m; -} - -mat2 __operator -= (inout mat2 m, const float a) -{ - vec2 v = vec2(a); - m[0] = m[0] - v; - m[1] = m[1] - v; - return m; -} - -mat2 __operator *= (inout mat2 m, const float a) -{ - vec2 v = vec2(a); - m[0] = m[0] * v; - m[1] = m[1] * v; - return m; -} - -mat2 __operator /= (inout mat2 m, const float a) -{ - vec2 v = vec2(1.0 / a); - m[0] = m[0] * v; - m[1] = m[1] * v; - return m; -} - - -//// mat3/float assignment operators - -mat3 __operator += (inout mat3 m, const float a) -{ - vec3 v = vec3(a); - m[0] = m[0] + v; - m[1] = m[1] + v; - m[2] = m[2] + v; - return m; -} - -mat3 __operator -= (inout mat3 m, const float a) -{ - vec3 v = vec3(a); - m[0] = m[0] - v; - m[1] = m[1] - v; - m[2] = m[2] - v; - return m; -} - -mat3 __operator *= (inout mat3 m, const float a) -{ - vec3 v = vec3(a); - m[0] = m[0] * v; - m[1] = m[1] * v; - m[2] = m[2] * v; - return m; -} - -mat3 __operator /= (inout mat3 m, const float a) -{ - vec3 v = vec3(1.0 / a); - m[0] = m[0] * v; - m[1] = m[1] * v; - m[2] = m[2] * v; - return m; -} - - -//// mat4/float assignment operators - -mat4 __operator += (inout mat4 m, const float a) -{ - vec4 v = vec4(a); - m[0] = m[0] + v; - m[1] = m[1] + v; - m[2] = m[2] + v; - m[3] = m[3] + v; - return m; -} - -mat4 __operator -= (inout mat4 m, const float a) -{ - vec4 v = vec4(a); - m[0] = m[0] - v; - m[1] = m[1] - v; - m[2] = m[2] - v; - m[3] = m[3] - v; - return m; -} - -mat4 __operator *= (inout mat4 m, const float a) -{ - vec4 v = vec4(a); - m[0] = m[0] * v; - m[1] = m[1] * v; - m[2] = m[2] * v; - m[3] = m[3] * v; - return m; -} - -mat4 __operator /= (inout mat4 m, const float a) -{ - vec4 v = vec4(1.0 / a); - m[0] = m[0] * v; - m[1] = m[1] * v; - m[2] = m[2] * v; - m[3] = m[3] * v; - return m; -} - - - -//// vec/mat assignment operators - -vec2 __operator *= (inout vec2 v, const mat2 m) -{ - v = v * m; - return v; -} - -vec3 __operator *= (inout vec3 v, const mat3 m) -{ - v = v * m; - return v; -} - -vec4 __operator *= (inout vec4 v, const mat4 m) -{ - v = v * m; - return v; -} - - - -//// pre-decrement operators - -int __operator --(inout int a) -{ - a = a - 1; - __retVal = a; -} - -ivec2 __operator --(inout ivec2 v) -{ - v = v - ivec2(1); - __retVal = v; -} - -ivec3 __operator --(inout ivec3 v) -{ - v = v - ivec3(1); - __retVal = v; -} - -ivec4 __operator --(inout ivec4 v) -{ - v = v - ivec4(1); - __retVal = v; -} - - -float __operator --(inout float a) -{ - a = a - 1.0; - __retVal = a; -} - -vec2 __operator --(inout vec2 v) -{ - v = v - vec2(1.0); - __retVal = v; -} - -vec3 __operator --(inout vec3 v) -{ - v = v - vec3(1.0); - __retVal = v; -} - -vec4 __operator --(inout vec4 v) -{ - v = v - vec4(1.0); - __retVal = v; -} - - -mat2 __operator --(inout mat2 m) -{ - m[0] = m[0] - vec2(1.0); - m[1] = m[1] - vec2(1.0); - __retVal = m; -} - -mat3 __operator --(inout mat3 m) -{ - m[0] = m[0] - vec3(1.0); - m[1] = m[1] - vec3(1.0); - m[2] = m[2] - vec3(1.0); - __retVal = m; -} - -mat4 __operator --(inout mat4 m) -{ - m[0] = m[0] - vec4(1.0); - m[1] = m[1] - vec4(1.0); - m[2] = m[2] - vec4(1.0); - m[3] = m[3] - vec4(1.0); - __retVal = m; -} - - -//// pre-increment operators - -int __operator ++(inout int a) -{ - a = a + 1; - __retVal = a; -} - -ivec2 __operator ++(inout ivec2 v) -{ - v = v + ivec2(1); - __retVal = v; -} - -ivec3 __operator ++(inout ivec3 v) -{ - v = v + ivec3(1); - __retVal = v; -} - -ivec4 __operator ++(inout ivec4 v) -{ - v = v + ivec4(1); - __retVal = v; -} - - -float __operator ++(inout float a) -{ - a = a + 1.0; - __retVal = a; -} - -vec2 __operator ++(inout vec2 v) -{ - v = v + vec2(1.0); - __retVal = v; -} - -vec3 __operator ++(inout vec3 v) -{ - v = v + vec3(1.0); - __retVal = v; -} - -vec4 __operator ++(inout vec4 v) -{ - v = v + vec4(1.0); - __retVal = v; -} - - -mat2 __operator ++(inout mat2 m) -{ - m[0] = m[0] + vec2(1.0); - m[1] = m[1] + vec2(1.0); - __retVal = m; -} - -mat3 __operator ++(inout mat3 m) -{ - m[0] = m[0] + vec3(1.0); - m[1] = m[1] + vec3(1.0); - m[2] = m[2] + vec3(1.0); - __retVal = m; -} - -mat4 __operator ++(inout mat4 m) -{ - m[0] = m[0] + vec4(1.0); - m[1] = m[1] + vec4(1.0); - m[2] = m[2] + vec4(1.0); - m[3] = m[3] + vec4(1.0); - __retVal = m; -} - - - -//// post-decrement - -int __postDecr(inout int a) -{ - __retVal = a; - a = a - 1; -} - -ivec2 __postDecr(inout ivec2 v) -{ - __retVal = v; - v = v - ivec2(1); -} - -ivec3 __postDecr(inout ivec3 v) -{ - __retVal = v; - v = v - ivec3(1); -} - -ivec4 __postDecr(inout ivec4 v) -{ - __retVal = v; - v = v - ivec4(1); -} - - -float __postDecr(inout float a) -{ - __retVal = a; - a = a - 1.0; -} - -vec2 __postDecr(inout vec2 v) -{ - __retVal = v; - v = v - vec2(1.0); -} - -vec3 __postDecr(inout vec3 v) -{ - __retVal = v; - v = v - vec3(1.0); -} - -vec4 __postDecr(inout vec4 v) -{ - __retVal = v; - v = v - vec4(1.0); -} - - -mat2 __postDecr(inout mat2 m) -{ - __retVal = m; - m[0] = m[0] - vec2(1.0); - m[1] = m[1] - vec2(1.0); -} - -mat3 __postDecr(inout mat3 m) -{ - __retVal = m; - m[0] = m[0] - vec3(1.0); - m[1] = m[1] - vec3(1.0); - m[2] = m[2] - vec3(1.0); -} - -mat4 __postDecr(inout mat4 m) -{ - __retVal = m; - m[0] = m[0] - vec4(1.0); - m[1] = m[1] - vec4(1.0); - m[2] = m[2] - vec4(1.0); - m[3] = m[3] - vec4(1.0); -} - - -//// post-increment - -float __postIncr(inout float a) -{ - __retVal = a; - a = a + 1; -} - -vec2 __postIncr(inout vec2 v) -{ - __retVal = v; - v = v + vec2(1.0); -} - -vec3 __postIncr(inout vec3 v) -{ - __retVal = v; - v = v + vec3(1.0); -} - -vec4 __postIncr(inout vec4 v) -{ - __retVal = v; - v = v + vec4(1.0); -} - - -int __postIncr(inout int a) -{ - __retVal = a; - a = a + 1; -} - -ivec2 __postIncr(inout ivec2 v) -{ - __retVal = v; - v = v + ivec2(1); -} - -ivec3 __postIncr(inout ivec3 v) -{ - __retVal = v; - v = v + ivec3(1); -} - -ivec4 __postIncr(inout ivec4 v) -{ - __retVal = v; - v = v + ivec3(1); -} - - -mat2 __postIncr(inout mat2 m) -{ - mat2 n = m; - m[0] = m[0] + vec2(1.0); - m[1] = m[1] + vec2(1.0); - return n; -} - -mat3 __postIncr(inout mat3 m) -{ - mat3 n = m; - m[0] = m[0] + vec3(1.0); - m[1] = m[1] + vec3(1.0); - m[2] = m[2] + vec3(1.0); - return n; -} - -mat4 __postIncr(inout mat4 m) -{ - mat4 n = m; - m[0] = m[0] + vec4(1.0); - m[1] = m[1] + vec4(1.0); - m[2] = m[2] + vec4(1.0); - m[3] = m[3] + vec4(1.0); - return n; -} - - - -//// inequality operators - - -// XXX are the inequality operators for floats/ints really needed???? -bool __operator < (const float a, const float b) -{ - __asm vec4_sgt __retVal.x, b, a; -} - - -bool __operator < (const int a, const int b) { - return float (a) < float (b); -} - -bool __operator > (const float a, const float b) { - bool c; - __asm float_less c, b, a; - return c; -} - -bool __operator > (const int a, const int b) { - return float (a) > float (b); -} - -bool __operator >= (const float a, const float b) { - bool g, e; - __asm float_less g, b, a; - __asm float_equal e, a, b; - return g || e; -} - -bool __operator >= (const int a, const int b) { - return float (a) >= float (b); -} - -bool __operator <= (const float a, const float b) { - bool g, e; - __asm float_less g, a, b; - __asm float_equal e, a, b; - return g || e; -} - -bool __operator <= (const int a, const int b) { - return float (a) <= float (b); -} - - - -// -// MESA-specific extension functions. -// - -void printMESA (const float f) { - __asm float_print f; -} - -void printMESA (const int i) { - __asm int_print i; -} - -void printMESA (const bool b) { - __asm bool_print b; -} - -void printMESA (const vec2 v) { - printMESA (v.x); - printMESA (v.y); -} - -void printMESA (const vec3 v) { - printMESA (v.x); - printMESA (v.y); - printMESA (v.z); -} - -void printMESA (const vec4 v) { - printMESA (v.x); - printMESA (v.y); - printMESA (v.z); - printMESA (v.w); -} - -void printMESA (const ivec2 v) { - printMESA (v.x); - printMESA (v.y); -} - -void printMESA (const ivec3 v) { - printMESA (v.x); - printMESA (v.y); - printMESA (v.z); -} - -void printMESA (const ivec4 v) { - printMESA (v.x); - printMESA (v.y); - printMESA (v.z); - printMESA (v.w); -} - -void printMESA (const bvec2 v) { - printMESA (v.x); - printMESA (v.y); -} - -void printMESA (const bvec3 v) { - printMESA (v.x); - printMESA (v.y); - printMESA (v.z); -} - -void printMESA (const bvec4 v) { - printMESA (v.x); - printMESA (v.y); - printMESA (v.z); - printMESA (v.w); -} - -void printMESA (const mat2 m) { - printMESA (m[0]); - printMESA (m[1]); -} - -void printMESA (const mat3 m) { - printMESA (m[0]); - printMESA (m[1]); - printMESA (m[2]); -} - -void printMESA (const mat4 m) { - printMESA (m[0]); - printMESA (m[1]); - printMESA (m[2]); - printMESA (m[3]); -} - -void printMESA (const sampler1D e) { - __asm int_print e; -} - -void printMESA (const sampler2D e) { - __asm int_print e; -} - -void printMESA (const sampler3D e) { - __asm int_print e; -} - -void printMESA (const samplerCube e) { - __asm int_print e; -} - -void printMESA (const sampler1DShadow e) { - __asm int_print e; -} - -void printMESA (const sampler2DShadow e) { - __asm int_print e; -} - diff --git a/src/mesa/slang/library/slang_fragment_builtin.gc b/src/mesa/slang/library/slang_fragment_builtin.gc deleted file mode 100644 index 54a80ea0e0..0000000000 --- a/src/mesa/slang/library/slang_fragment_builtin.gc +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -// -// From Shader Spec, ver. 1.10, rev. 59 -// - -__fixed_input vec4 gl_FragCoord; -__fixed_input bool gl_FrontFacing; -__fixed_output vec4 gl_FragColor; -__fixed_output vec4 gl_FragData[gl_MaxDrawBuffers]; -__fixed_output float gl_FragDepth; - -varying vec4 gl_Color; -varying vec4 gl_SecondaryColor; -varying vec4 gl_TexCoord[gl_MaxTextureCoords]; -varying float gl_FogFragCoord; - - - -//// 8.7 Texture Lookup Functions (with bias) - -vec4 texture1D(const sampler1D sampler, const float coord, const float bias) -{ - vec4 coord4; - coord4.x = coord; - coord4.w = bias; - __asm vec4_tex_1d_bias __retVal, sampler, coord4; -} - -vec4 texture1DProj(const sampler1D sampler, const vec2 coord, const float bias) -{ - // do projection here (there's no vec4_texbp1d instruction) - vec4 pcoord; - pcoord.x = coord.x / coord.y; - pcoord.w = bias; - __asm vec4_tex_1d_bias __retVal, sampler, pcoord; -} - -vec4 texture1DProj(const sampler1D sampler, const vec4 coord, const float bias) -{ - // do projection here (there's no vec4_texbp1d instruction) - vec4 pcoord; - pcoord.x = coord.x / coord.z; - pcoord.w = bias; - __asm vec4_tex_1d_bias __retVal, sampler, pcoord; -} - - - - -vec4 texture2D(const sampler2D sampler, const vec2 coord, const float bias) -{ - vec4 coord4; - coord4.xy = coord.xy; - coord4.w = bias; - __asm vec4_tex_2d_bias __retVal, sampler, coord4; -} - -vec4 texture2DProj(const sampler2D sampler, const vec3 coord, const float bias) -{ - // do projection here (there's no vec4_texbp2d instruction) - vec4 pcoord; - pcoord.xy = coord.xy / coord.z; - pcoord.w = bias; - __asm vec4_tex_2d_bias __retVal, sampler, pcoord; -} - -vec4 texture2DProj(const sampler2D sampler, const vec4 coord, const float bias) -{ - // do projection here (there's no vec4_texbp2d instruction) - vec4 pcoord; - pcoord.xy = coord.xy / coord.w; - pcoord.w = bias; - __asm vec4_tex_2d_bias __retVal, sampler, pcoord; -} - - - - -vec4 texture3D(const sampler3D sampler, const vec3 coord, const float bias) -{ - vec4 coord4; - coord4.xyz = coord.xyz; - coord4.w = bias; - __asm vec4_tex_3d_bias __retVal, sampler, coord4; -} - -vec4 texture3DProj(const sampler3D sampler, const vec4 coord, const float bias) -{ - // do projection here (there's no vec4_texbp3d instruction) - vec4 pcoord; - pcoord.xyz = coord.xyz / coord.w; - pcoord.w = bias; - __asm vec4_tex_3d_bias __retVal, sampler, pcoord; -} - - - - -vec4 textureCube(const samplerCube sampler, const vec3 coord, const float bias) -{ - vec4 coord4; - coord4.xyz = coord; - coord4.w = bias; - __asm vec4_tex_cube __retVal, sampler, coord4; -} - - - -vec4 shadow1D(const sampler1DShadow sampler, const vec3 coord, const float bias) -{ - vec4 coord4; - coord4.xyz = coord; - coord4.w = bias; - __asm vec4_tex_1d_bias_shadow __retVal, sampler, coord4; -} - -vec4 shadow1DProj(const sampler1DShadow sampler, const vec4 coord, const float bias) -{ - vec4 pcoord; - pcoord.x = coord.x / coord.w; - pcoord.z = coord.z; - pcoord.w = bias; - __asm vec4_tex_1d_bias_shadow __retVal, sampler, pcoord; -} - -vec4 shadow2D(const sampler2DShadow sampler, const vec3 coord, const float bias) -{ - vec4 coord4; - coord4.xyz = coord; - coord4.w = bias; - __asm vec4_tex_2d_bias_shadow __retVal, sampler, coord4; -} - -vec4 shadow2DProj(const sampler2DShadow sampler, const vec4 coord, const float bias) -{ - vec4 pcoord; - pcoord.xy = coord.xy / coord.w; - pcoord.z = coord.z; - pcoord.w = bias; - __asm vec4_tex_2d_bias_shadow __retVal, sampler, pcoord; -} - - - -//// GL_EXT_texture_array - -vec4 texture1DArray(const sampler1DArray sampler, const vec2 coord) -{ - vec4 coord4; - coord4.xy = coord; - __asm vec4_tex_1d_array __retVal, sampler, coord4; -} - -vec4 texture1DArray(const sampler1DArray sampler, const vec2 coord, const float bias) -{ - vec4 coord4; - coord4.xy = coord; - coord4.w = bias; - __asm vec4_tex_1d_array_bias __retVal, sampler, coord4; -} - -vec4 texure2DArray(const sampler2DArray sampler, const vec3 coord) -{ - vec4 coord4; - coord4.xyz = coord; - __asm vec4_tex_2d_array __retVal, sampler, coord4; -} - -vec4 texture2DArray(const sampler2DArray sampler, const vec3 coord, const float bias) -{ - vec4 coord4; - coord4.xyz = coord; - coord4.w = bias; - __asm vec4_tex_2d_array_bias __retVal, sampler, coord4; -} - -vec4 shadow1DArray(const sampler1DArrayShadow sampler, const vec2 coord) -{ - vec4 coord4; - coord4.xy = coord; - __asm vec4_tex_1d_array_shadow __retVal, sampler, coord4; -} - -vec4 shadow1DArray(const sampler1DArrayShadow sampler, const vec2 coord, const float bias) -{ - vec4 coord4; - coord4.xy = coord; - coord4.w = bias; - __asm vec4_tex_1d_array_bias_shadow __retVal, sampler, coord4; -} - -vec4 shadow2DArray(const sampler2DArrayShadow sampler, const vec3 coord) -{ - vec4 coord4; - coord4.xyz = coord; - __asm vec4_tex_2d_array_shadow __retVal, sampler, coord4; -} - -vec4 shadow2DArray(const sampler2DArrayShadow sampler, const vec3 coord, const float bias) -{ - vec4 coord4; - coord4.xyz = coord; - coord4.w = bias; - __asm vec4_tex_2d_array_bias_shadow __retVal, sampler, coord4; -} - - - -// -// 8.8 Fragment Processing Functions -// - -float dFdx(const float p) -{ - __asm vec4_ddx __retVal.x, p.xxxx; -} - -vec2 dFdx(const vec2 p) -{ - __asm vec4_ddx __retVal.xy, p.xyyy; -} - -vec3 dFdx(const vec3 p) -{ - __asm vec4_ddx __retVal.xyz, p.xyzz; -} - -vec4 dFdx(const vec4 p) -{ - __asm vec4_ddx __retVal, p; -} - -float dFdy(const float p) -{ - __asm vec4_ddy __retVal.x, p.xxxx; -} - -vec2 dFdy(const vec2 p) -{ - __asm vec4_ddy __retVal.xy, p.xyyy; -} - -vec3 dFdy(const vec3 p) -{ - __asm vec4_ddy __retVal.xyz, p.xyzz; -} - -vec4 dFdy(const vec4 p) -{ - __asm vec4_ddy __retVal, p; -} - -float fwidth (const float p) -{ - // XXX hand-write with __asm - return abs(dFdx(p)) + abs(dFdy(p)); -} - -vec2 fwidth(const vec2 p) -{ - // XXX hand-write with __asm - return abs(dFdx(p)) + abs(dFdy(p)); -} - -vec3 fwidth(const vec3 p) -{ - // XXX hand-write with __asm - return abs(dFdx(p)) + abs(dFdy(p)); -} - -vec4 fwidth(const vec4 p) -{ - // XXX hand-write with __asm - return abs(dFdx(p)) + abs(dFdy(p)); -} - diff --git a/src/mesa/slang/library/slang_geometry_builtin.gc b/src/mesa/slang/library/slang_geometry_builtin.gc deleted file mode 100644 index 07524912ba..0000000000 --- a/src/mesa/slang/library/slang_geometry_builtin.gc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Mesa 3-D graphics library - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -const int _mesa_VerticesInMax = 6; - -__fixed_input int gl_PrimitiveIDIn; -__fixed_output int gl_PrimitiveID; -__fixed_output int gl_Layer; - - -varying in vec4 gl_FrontColorIn[_mesa_VerticesInMax]; -varying in vec4 gl_BackColorIn[_mesa_VerticesInMax]; -varying in vec4 gl_FrontSecondaryColorIn[_mesa_VerticesInMax]; -varying in vec4 gl_BackSecondaryColorIn[_mesa_VerticesInMax]; -/*varying in vec4 gl_TexCoordIn[_mesa_VerticesInMax][gl_MaxTextureCoords];*/ -varying in float gl_FogFragCoordIn[_mesa_VerticesInMax]; -varying in vec4 gl_PositionIn[_mesa_VerticesInMax]; -varying in float gl_PointSizeIn[_mesa_VerticesInMax]; -varying in vec4 gl_ClipVertexIn[_mesa_VerticesInMax]; - -varying out vec4 gl_Position; -varying out vec4 gl_FrontColor; -varying out vec4 gl_BackColor; -varying out vec4 gl_FrontSecondaryColor; -varying out vec4 gl_BackSecondaryColor; -varying out vec4 gl_TexCoord[gl_MaxTextureCoords]; -varying out float gl_FogFragCoord; - -void EmitVertex() -{ - __asm emit_vertex; -} - -void EndPrimitive() -{ - __asm end_primitive; -} diff --git a/src/mesa/slang/library/slang_vertex_builtin.gc b/src/mesa/slang/library/slang_vertex_builtin.gc deleted file mode 100644 index 0c67c2ef20..0000000000 --- a/src/mesa/slang/library/slang_vertex_builtin.gc +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -// -// From Shader Spec, ver. 1.10, rev. 59 -// - -__fixed_output vec4 gl_Position; -__fixed_output float gl_PointSize; -__fixed_output vec4 gl_ClipVertex; - -attribute vec4 gl_Color; -attribute vec4 gl_SecondaryColor; -attribute vec3 gl_Normal; -attribute vec4 gl_Vertex; -attribute vec4 gl_MultiTexCoord0; -attribute vec4 gl_MultiTexCoord1; -attribute vec4 gl_MultiTexCoord2; -attribute vec4 gl_MultiTexCoord3; -attribute vec4 gl_MultiTexCoord4; -attribute vec4 gl_MultiTexCoord5; -attribute vec4 gl_MultiTexCoord6; -attribute vec4 gl_MultiTexCoord7; -attribute float gl_FogCoord; - -varying vec4 gl_FrontColor; -varying vec4 gl_BackColor; -varying vec4 gl_FrontSecondaryColor; -varying vec4 gl_BackSecondaryColor; -varying vec4 gl_TexCoord[gl_MaxTextureCoords]; -varying float gl_FogFragCoord; - -// -// Geometric Functions -// - -vec4 ftransform() -{ - __retVal = gl_ModelViewProjectionMatrix[0] * gl_Vertex.xxxx - + gl_ModelViewProjectionMatrix[1] * gl_Vertex.yyyy - + gl_ModelViewProjectionMatrix[2] * gl_Vertex.zzzz - + gl_ModelViewProjectionMatrix[3] * gl_Vertex.wwww; -} - - - -// -// 8.7 Texture Lookup Functions -// These are pretty much identical to the ones in slang_fragment_builtin.gc -// When used in a vertex program, the texture sample instructions should not -// be using a LOD term so it's effectively zero. Adding 'lod' to that does -// what we want. -// - -vec4 texture1DLod(const sampler1D sampler, const float coord, const float lod) -{ - vec4 coord4; - coord4.x = coord; - coord4.w = lod; - __asm vec4_tex_1d_bias __retVal, sampler, coord4; -} - -vec4 texture1DProjLod(const sampler1D sampler, const vec2 coord, const float lod) -{ - vec4 pcoord; - pcoord.x = coord.x / coord.y; - pcoord.w = lod; - __asm vec4_tex_1d_bias __retVal, sampler, pcoord; -} - -vec4 texture1DProjLod(const sampler1D sampler, const vec4 coord, const float lod) -{ - vec4 pcoord; - pcoord.x = coord.x / coord.z; - pcoord.w = lod; - __asm vec4_tex_1d_bias __retVal, sampler, pcoord; -} - - - -vec4 texture2DLod(const sampler2D sampler, const vec2 coord, const float lod) -{ - vec4 coord4; - coord4.xy = coord.xy; - coord4.w = lod; - __asm vec4_tex_2d_bias __retVal, sampler, coord4; -} - -vec4 texture2DProjLod(const sampler2D sampler, const vec3 coord, const float lod) -{ - vec4 pcoord; - pcoord.xy = coord.xy / coord.z; - pcoord.w = lod; - __asm vec4_tex_2d_bias __retVal, sampler, pcoord; -} - -vec4 texture2DProjLod(const sampler2D sampler, const vec4 coord, const float lod) -{ - vec4 pcoord; - pcoord.xy = coord.xy / coord.z; - pcoord.w = lod; - __asm vec4_tex_2d_bias __retVal, sampler, pcoord; -} - - -vec4 texture3DLod(const sampler3D sampler, const vec3 coord, const float lod) -{ - vec4 coord4; - coord4.xyz = coord.xyz; - coord4.w = lod; - __asm vec4_tex_3d_bias __retVal, sampler, coord4; -} - -vec4 texture3DProjLod(const sampler3D sampler, const vec4 coord, const float lod) -{ - // do projection here (there's no vec4_tex_3d_bias_proj instruction) - vec4 pcoord; - pcoord.xyz = coord.xyz / coord.w; - pcoord.w = lod; - __asm vec4_tex_3d_bias __retVal, sampler, pcoord; -} - - -vec4 textureCubeLod(const samplerCube sampler, const vec3 coord, const float lod) -{ - vec4 coord4; - coord4.xyz = coord; - coord4.w = lod; - __asm vec4_tex_cube __retVal, sampler, coord4; -} - - -vec4 shadow1DLod(const sampler1DShadow sampler, const vec3 coord, const float lod) -{ - vec4 coord4; - coord4.xyz = coord; - coord4.w = lod; - __asm vec4_tex_1d_bias_shadow __retVal, sampler, coord4; -} - -vec4 shadow1DProjLod(const sampler1DShadow sampler, const vec4 coord, - const float lod) -{ - vec4 pcoord; - pcoord.x = coord.x / coord.w; - pcoord.z = coord.z; - pcoord.w = lod; - __asm vec4_tex_1d_bias_shadow __retVal, sampler, pcoord; -} - - -vec4 shadow2DLod(const sampler2DShadow sampler, const vec3 coord, const float lod) -{ - vec4 coord4; - coord4.xyz = coord; - coord4.w = lod; - __asm vec4_tex_2d_bias_shadow __retVal, sampler, coord4; -} - -vec4 shadow2DProjLod(const sampler2DShadow sampler, const vec4 coord, - const float lod) -{ - vec4 pcoord; - pcoord.xy = coord.xy / coord.w; - pcoord.z = coord.z; - pcoord.w = lod; - __asm vec4_tex_2d_bias_shadow __retVal, sampler, pcoord; -} - - -//// GL_EXT_texture_array - -vec4 texture1DArrayLod(const sampler1DArray sampler, const vec2 coord, const float lod) -{ - vec4 coord4; - coord4.xy = coord; - coord4.w = lod; - __asm vec4_tex_1d_array_bias __retVal, sampler, coord4; -} - - -vec4 texture2DArrayLod(const sampler2DArray sampler, const vec3 coord, const float lod) -{ - vec4 coord4; - coord4.xyz = coord; - coord4.w = lod; - __asm vec4_tex_2d_array_bias __retVal, sampler, coord4; -} - diff --git a/src/mesa/slang/slang_builtin.c b/src/mesa/slang/slang_builtin.c deleted file mode 100644 index a7e0efcb7b..0000000000 --- a/src/mesa/slang/slang_builtin.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * Copyright (C) 2008 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_builtin.c - * Resolve built-in uniform vars. - * \author Brian Paul - */ - -#include "main/imports.h" -#include "main/mtypes.h" -#include "program/program.h" -#include "program/prog_instruction.h" -#include "program/prog_parameter.h" -#include "program/prog_statevars.h" -#include "slang/slang_ir.h" -#include "slang/slang_builtin.h" - - -/** special state token (see below) */ -#define STATE_ARRAY ((gl_state_index) 0xfffff) - - -/** - * Lookup GL state given a variable name, 0, 1 or 2 indexes and a field. - * Allocate room for the state in the given param list and return position - * in the list. - * Yes, this is kind of ugly, but it works. - */ -static GLint -lookup_statevar(const char *var, GLint index1, GLint index2, const char *field, - GLuint *swizzleOut, - struct gl_program_parameter_list *paramList) -{ - /* - * NOTE: The ARB_vertex_program extension specified that matrices get - * loaded in registers in row-major order. With GLSL, we want column- - * major order. So, we need to transpose all matrices here... - */ - static const struct { - const char *name; - gl_state_index matrix; - gl_state_index modifier; - } matrices[] = { - { "gl_ModelViewMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE }, - { "gl_ModelViewMatrixInverse", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVTRANS }, - { "gl_ModelViewMatrixTranspose", STATE_MODELVIEW_MATRIX, 0 }, - { "gl_ModelViewMatrixInverseTranspose", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE }, - - { "gl_ProjectionMatrix", STATE_PROJECTION_MATRIX, STATE_MATRIX_TRANSPOSE }, - { "gl_ProjectionMatrixInverse", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVTRANS }, - { "gl_ProjectionMatrixTranspose", STATE_PROJECTION_MATRIX, 0 }, - { "gl_ProjectionMatrixInverseTranspose", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVERSE }, - - { "gl_ModelViewProjectionMatrix", STATE_MVP_MATRIX, STATE_MATRIX_TRANSPOSE }, - { "gl_ModelViewProjectionMatrixInverse", STATE_MVP_MATRIX, STATE_MATRIX_INVTRANS }, - { "gl_ModelViewProjectionMatrixTranspose", STATE_MVP_MATRIX, 0 }, - { "gl_ModelViewProjectionMatrixInverseTranspose", STATE_MVP_MATRIX, STATE_MATRIX_INVERSE }, - - { "gl_TextureMatrix", STATE_TEXTURE_MATRIX, STATE_MATRIX_TRANSPOSE }, - { "gl_TextureMatrixInverse", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVTRANS }, - { "gl_TextureMatrixTranspose", STATE_TEXTURE_MATRIX, 0 }, - { "gl_TextureMatrixInverseTranspose", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE }, - - { "gl_NormalMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE }, - - { NULL, 0, 0 } - }; - gl_state_index tokens[STATE_LENGTH]; - GLuint i; - GLboolean isMatrix = GL_FALSE; - - for (i = 0; i < STATE_LENGTH; i++) { - tokens[i] = 0; - } - *swizzleOut = SWIZZLE_NOOP; - - /* first, look if var is a pre-defined matrix */ - for (i = 0; matrices[i].name; i++) { - if (strcmp(var, matrices[i].name) == 0) { - tokens[0] = matrices[i].matrix; - /* tokens[1], [2] and [3] filled below */ - tokens[4] = matrices[i].modifier; - isMatrix = GL_TRUE; - break; - } - } - - if (isMatrix) { - if (tokens[0] == STATE_TEXTURE_MATRIX) { - /* texture_matrix[index1][index2] */ - tokens[1] = index1 >= 0 ? index1 : 0; /* which texture matrix */ - index1 = index2; /* move matrix row value to index1 */ - } - if (index1 < 0) { - /* index1 is unused: prevent extra addition at end of function */ - index1 = 0; - } - } - else if (strcmp(var, "gl_DepthRange") == 0) { - tokens[0] = STATE_DEPTH_RANGE; - assert(field); - if (strcmp(field, "near") == 0) { - *swizzleOut = SWIZZLE_XXXX; - } - else if (strcmp(field, "far") == 0) { - *swizzleOut = SWIZZLE_YYYY; - } - else if (strcmp(field, "diff") == 0) { - *swizzleOut = SWIZZLE_ZZZZ; - } - else { - return -1; - } - } - else if (strcmp(var, "gl_ClipPlane") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_CLIPPLANE; - tokens[1] = index1; - } - else if (strcmp(var, "gl_Point") == 0) { - assert(field); - if (strcmp(field, "size") == 0) { - tokens[0] = STATE_POINT_SIZE; - *swizzleOut = SWIZZLE_XXXX; - } - else if (strcmp(field, "sizeMin") == 0) { - tokens[0] = STATE_POINT_SIZE; - *swizzleOut = SWIZZLE_YYYY; - } - else if (strcmp(field, "sizeMax") == 0) { - tokens[0] = STATE_POINT_SIZE; - *swizzleOut = SWIZZLE_ZZZZ; - } - else if (strcmp(field, "fadeThresholdSize") == 0) { - tokens[0] = STATE_POINT_SIZE; - *swizzleOut = SWIZZLE_WWWW; - } - else if (strcmp(field, "distanceConstantAttenuation") == 0) { - tokens[0] = STATE_POINT_ATTENUATION; - *swizzleOut = SWIZZLE_XXXX; - } - else if (strcmp(field, "distanceLinearAttenuation") == 0) { - tokens[0] = STATE_POINT_ATTENUATION; - *swizzleOut = SWIZZLE_YYYY; - } - else if (strcmp(field, "distanceQuadraticAttenuation") == 0) { - tokens[0] = STATE_POINT_ATTENUATION; - *swizzleOut = SWIZZLE_ZZZZ; - } - else { - return -1; - } - } - else if (strcmp(var, "gl_FrontMaterial") == 0 || - strcmp(var, "gl_BackMaterial") == 0) { - tokens[0] = STATE_MATERIAL; - if (strcmp(var, "gl_FrontMaterial") == 0) - tokens[1] = 0; - else - tokens[1] = 1; - assert(field); - if (strcmp(field, "emission") == 0) { - tokens[2] = STATE_EMISSION; - } - else if (strcmp(field, "ambient") == 0) { - tokens[2] = STATE_AMBIENT; - } - else if (strcmp(field, "diffuse") == 0) { - tokens[2] = STATE_DIFFUSE; - } - else if (strcmp(field, "specular") == 0) { - tokens[2] = STATE_SPECULAR; - } - else if (strcmp(field, "shininess") == 0) { - tokens[2] = STATE_SHININESS; - *swizzleOut = SWIZZLE_XXXX; - } - else { - return -1; - } - } - else if (strcmp(var, "gl_LightSource") == 0) { - if (!field || index1 < 0) - return -1; - - tokens[0] = STATE_LIGHT; - tokens[1] = index1; - - if (strcmp(field, "ambient") == 0) { - tokens[2] = STATE_AMBIENT; - } - else if (strcmp(field, "diffuse") == 0) { - tokens[2] = STATE_DIFFUSE; - } - else if (strcmp(field, "specular") == 0) { - tokens[2] = STATE_SPECULAR; - } - else if (strcmp(field, "position") == 0) { - tokens[2] = STATE_POSITION; - } - else if (strcmp(field, "halfVector") == 0) { - tokens[2] = STATE_HALF_VECTOR; - } - else if (strcmp(field, "spotDirection") == 0) { - tokens[2] = STATE_SPOT_DIRECTION; - } - else if (strcmp(field, "spotCosCutoff") == 0) { - tokens[2] = STATE_SPOT_DIRECTION; - *swizzleOut = SWIZZLE_WWWW; - } - else if (strcmp(field, "spotCutoff") == 0) { - tokens[2] = STATE_SPOT_CUTOFF; - *swizzleOut = SWIZZLE_XXXX; - } - else if (strcmp(field, "spotExponent") == 0) { - tokens[2] = STATE_ATTENUATION; - *swizzleOut = SWIZZLE_WWWW; - } - else if (strcmp(field, "constantAttenuation") == 0) { - tokens[2] = STATE_ATTENUATION; - *swizzleOut = SWIZZLE_XXXX; - } - else if (strcmp(field, "linearAttenuation") == 0) { - tokens[2] = STATE_ATTENUATION; - *swizzleOut = SWIZZLE_YYYY; - } - else if (strcmp(field, "quadraticAttenuation") == 0) { - tokens[2] = STATE_ATTENUATION; - *swizzleOut = SWIZZLE_ZZZZ; - } - else { - return -1; - } - } - else if (strcmp(var, "gl_LightModel") == 0) { - if (strcmp(field, "ambient") == 0) { - tokens[0] = STATE_LIGHTMODEL_AMBIENT; - } - else { - return -1; - } - } - else if (strcmp(var, "gl_FrontLightModelProduct") == 0) { - if (strcmp(field, "sceneColor") == 0) { - tokens[0] = STATE_LIGHTMODEL_SCENECOLOR; - tokens[1] = 0; - } - else { - return -1; - } - } - else if (strcmp(var, "gl_BackLightModelProduct") == 0) { - if (strcmp(field, "sceneColor") == 0) { - tokens[0] = STATE_LIGHTMODEL_SCENECOLOR; - tokens[1] = 1; - } - else { - return -1; - } - } - else if (strcmp(var, "gl_FrontLightProduct") == 0 || - strcmp(var, "gl_BackLightProduct") == 0) { - if (index1 < 0 || !field) - return -1; - - tokens[0] = STATE_LIGHTPROD; - tokens[1] = index1; /* light number */ - if (strcmp(var, "gl_FrontLightProduct") == 0) { - tokens[2] = 0; /* front */ - } - else { - tokens[2] = 1; /* back */ - } - if (strcmp(field, "ambient") == 0) { - tokens[3] = STATE_AMBIENT; - } - else if (strcmp(field, "diffuse") == 0) { - tokens[3] = STATE_DIFFUSE; - } - else if (strcmp(field, "specular") == 0) { - tokens[3] = STATE_SPECULAR; - } - else { - return -1; - } - } - else if (strcmp(var, "gl_TextureEnvColor") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_TEXENV_COLOR; - tokens[1] = index1; - } - else if (strcmp(var, "gl_EyePlaneS") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_TEXGEN; - tokens[1] = index1; /* tex unit */ - tokens[2] = STATE_TEXGEN_EYE_S; - } - else if (strcmp(var, "gl_EyePlaneT") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_TEXGEN; - tokens[1] = index1; /* tex unit */ - tokens[2] = STATE_TEXGEN_EYE_T; - } - else if (strcmp(var, "gl_EyePlaneR") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_TEXGEN; - tokens[1] = index1; /* tex unit */ - tokens[2] = STATE_TEXGEN_EYE_R; - } - else if (strcmp(var, "gl_EyePlaneQ") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_TEXGEN; - tokens[1] = index1; /* tex unit */ - tokens[2] = STATE_TEXGEN_EYE_Q; - } - else if (strcmp(var, "gl_ObjectPlaneS") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_TEXGEN; - tokens[1] = index1; /* tex unit */ - tokens[2] = STATE_TEXGEN_OBJECT_S; - } - else if (strcmp(var, "gl_ObjectPlaneT") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_TEXGEN; - tokens[1] = index1; /* tex unit */ - tokens[2] = STATE_TEXGEN_OBJECT_T; - } - else if (strcmp(var, "gl_ObjectPlaneR") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_TEXGEN; - tokens[1] = index1; /* tex unit */ - tokens[2] = STATE_TEXGEN_OBJECT_R; - } - else if (strcmp(var, "gl_ObjectPlaneQ") == 0) { - if (index1 < 0) - return -1; - tokens[0] = STATE_TEXGEN; - tokens[1] = index1; /* tex unit */ - tokens[2] = STATE_TEXGEN_OBJECT_Q; - } - else if (strcmp(var, "gl_Fog") == 0) { - if (strcmp(field, "color") == 0) { - tokens[0] = STATE_FOG_COLOR; - } - else if (strcmp(field, "density") == 0) { - tokens[0] = STATE_FOG_PARAMS; - *swizzleOut = SWIZZLE_XXXX; - } - else if (strcmp(field, "start") == 0) { - tokens[0] = STATE_FOG_PARAMS; - *swizzleOut = SWIZZLE_YYYY; - } - else if (strcmp(field, "end") == 0) { - tokens[0] = STATE_FOG_PARAMS; - *swizzleOut = SWIZZLE_ZZZZ; - } - else if (strcmp(field, "scale") == 0) { - tokens[0] = STATE_FOG_PARAMS; - *swizzleOut = SWIZZLE_WWWW; - } - else { - return -1; - } - } - else { - return -1; - } - - if (isMatrix) { - /* load all four rows (or columns) of matrix */ - GLint pos[4]; - GLuint j; - for (j = 0; j < 4; j++) { - tokens[2] = tokens[3] = j; /* jth row of matrix */ - pos[j] = _mesa_add_state_reference(paramList, tokens); - assert(pos[j] >= 0); - ASSERT(pos[j] >= 0); - } - return pos[0] + index1; - } - else { - /* allocate a single register */ - GLint pos = _mesa_add_state_reference(paramList, tokens); - ASSERT(pos >= 0); - return pos; - } -} - - - -/** - * Given a variable name and datatype, emit uniform/constant buffer - * entries which will store that state variable. - * For example, if name="gl_LightSource" we'll emit 64 state variable - * vectors/references and return position where that data starts. This will - * allow run-time array indexing into the light source array. - * - * Note that this is a recursive function. - * - * \return -1 if error, else index of start of data in the program parameter list - */ -static GLint -emit_statevars(const char *name, int array_len, - const slang_type_specifier *type, - gl_state_index tokens[STATE_LENGTH], - struct gl_program_parameter_list *paramList) -{ - if (type->type == SLANG_SPEC_ARRAY) { - GLint i, pos = -1; - assert(array_len > 0); - if (strcmp(name, "gl_ClipPlane") == 0) { - tokens[0] = STATE_CLIPPLANE; - } - else if (strcmp(name, "gl_LightSource") == 0) { - tokens[0] = STATE_LIGHT; - } - else if (strcmp(name, "gl_FrontLightProduct") == 0) { - tokens[0] = STATE_LIGHTPROD; - tokens[2] = 0; /* front */ - } - else if (strcmp(name, "gl_BackLightProduct") == 0) { - tokens[0] = STATE_LIGHTPROD; - tokens[2] = 1; /* back */ - } - else if (strcmp(name, "gl_TextureEnvColor") == 0) { - tokens[0] = STATE_TEXENV_COLOR; - } - else if (strcmp(name, "gl_EyePlaneS") == 0) { - tokens[0] = STATE_TEXGEN; - tokens[2] = STATE_TEXGEN_EYE_S; - } - else if (strcmp(name, "gl_EyePlaneT") == 0) { - tokens[0] = STATE_TEXGEN; - tokens[2] = STATE_TEXGEN_EYE_T; - } - else if (strcmp(name, "gl_EyePlaneR") == 0) { - tokens[0] = STATE_TEXGEN; - tokens[2] = STATE_TEXGEN_EYE_R; - } - else if (strcmp(name, "gl_EyePlaneQ") == 0) { - tokens[0] = STATE_TEXGEN; - tokens[2] = STATE_TEXGEN_EYE_Q; - } - else if (strcmp(name, "gl_ObjectPlaneS") == 0) { - tokens[0] = STATE_TEXGEN; - tokens[2] = STATE_TEXGEN_OBJECT_S; - } - else if (strcmp(name, "gl_ObjectPlaneT") == 0) { - tokens[0] = STATE_TEXGEN; - tokens[2] = STATE_TEXGEN_OBJECT_T; - } - else if (strcmp(name, "gl_ObjectPlaneR") == 0) { - tokens[0] = STATE_TEXGEN; - tokens[2] = STATE_TEXGEN_OBJECT_R; - } - else if (strcmp(name, "gl_ObjectPlaneQ") == 0) { - tokens[0] = STATE_TEXGEN; - tokens[2] = STATE_TEXGEN_OBJECT_Q; - } - else if (strcmp(name, "gl_TextureMatrix") == 0) { - tokens[0] = STATE_TEXTURE_MATRIX; - tokens[4] = STATE_MATRIX_TRANSPOSE; - } - else if (strcmp(name, "gl_TextureMatrixInverse") == 0) { - tokens[0] = STATE_TEXTURE_MATRIX; - tokens[4] = STATE_MATRIX_INVTRANS; - } - else if (strcmp(name, "gl_TextureMatrixTranspose") == 0) { - tokens[0] = STATE_TEXTURE_MATRIX; - tokens[4] = 0; - } - else if (strcmp(name, "gl_TextureMatrixInverseTranspose") == 0) { - tokens[0] = STATE_TEXTURE_MATRIX; - tokens[4] = STATE_MATRIX_INVERSE; - } - else { - return -1; /* invalid array name */ - } - /* emit state vars for each array element */ - for (i = 0; i < array_len; i++) { - GLint p; - tokens[1] = i; - p = emit_statevars(NULL, 0, type->_array, tokens, paramList); - if (i == 0) - pos = p; - } - return pos; - } - else if (type->type == SLANG_SPEC_STRUCT) { - const slang_variable_scope *fields = type->_struct->fields; - GLuint i, pos = 0; - for (i = 0; i < fields->num_variables; i++) { - const slang_variable *var = fields->variables[i]; - GLint p = emit_statevars(var->a_name, 0, &var->type.specifier, - tokens, paramList); - if (i == 0) - pos = p; - } - return pos; - } - else if (type->type == SLANG_SPEC_MAT4) { - /* unroll/emit 4 array rows (or columns) */ - slang_type_specifier vec4; - GLint i, p, pos = -1; - vec4.type = SLANG_SPEC_VEC4; - for (i = 0; i < 4; i++) { - tokens[2] = tokens[3] = i; /* row[i] (or column[i]) of matrix */ - p = emit_statevars(NULL, 0, &vec4, tokens, paramList); - if (pos == -1) - pos = p; - } - return pos; - } - else { - GLint pos; - assert(type->type == SLANG_SPEC_VEC4 || - type->type == SLANG_SPEC_VEC3 || - type->type == SLANG_SPEC_VEC2 || - type->type == SLANG_SPEC_FLOAT || - type->type == SLANG_SPEC_IVEC4 || - type->type == SLANG_SPEC_IVEC3 || - type->type == SLANG_SPEC_IVEC2 || - type->type == SLANG_SPEC_INT); - if (name) { - GLint t; - - if (tokens[0] == STATE_LIGHT) - t = 2; - else if (tokens[0] == STATE_LIGHTPROD) - t = 3; - else - return -1; /* invalid array name */ - - if (strcmp(name, "ambient") == 0) { - tokens[t] = STATE_AMBIENT; - } - else if (strcmp(name, "diffuse") == 0) { - tokens[t] = STATE_DIFFUSE; - } - else if (strcmp(name, "specular") == 0) { - tokens[t] = STATE_SPECULAR; - } - else if (strcmp(name, "position") == 0) { - tokens[t] = STATE_POSITION; - } - else if (strcmp(name, "halfVector") == 0) { - tokens[t] = STATE_HALF_VECTOR; - } - else if (strcmp(name, "spotDirection") == 0) { - tokens[t] = STATE_SPOT_DIRECTION; /* xyz components */ - } - else if (strcmp(name, "spotCosCutoff") == 0) { - tokens[t] = STATE_SPOT_DIRECTION; /* w component */ - } - - else if (strcmp(name, "constantAttenuation") == 0) { - tokens[t] = STATE_ATTENUATION; /* x component */ - } - else if (strcmp(name, "linearAttenuation") == 0) { - tokens[t] = STATE_ATTENUATION; /* y component */ - } - else if (strcmp(name, "quadraticAttenuation") == 0) { - tokens[t] = STATE_ATTENUATION; /* z component */ - } - else if (strcmp(name, "spotExponent") == 0) { - tokens[t] = STATE_ATTENUATION; /* w = spot exponent */ - } - - else if (strcmp(name, "spotCutoff") == 0) { - tokens[t] = STATE_SPOT_CUTOFF; /* x component */ - } - - else { - return -1; /* invalid field name */ - } - } - - pos = _mesa_add_state_reference(paramList, tokens); - return pos; - } - - return 1; -} - - -/** - * Unroll the named built-in uniform variable into a sequence of state - * vars in the given parameter list. - */ -static GLint -alloc_state_var_array(const slang_variable *var, - struct gl_program_parameter_list *paramList) -{ - gl_state_index tokens[STATE_LENGTH]; - GLuint i; - GLint pos; - - /* Initialize the state tokens array. This is very important. - * When we call _mesa_add_state_reference() it'll searches the parameter - * list to see if the given statevar token sequence is already present. - * This is normally a good thing since it prevents redundant values in the - * constant buffer. - * - * But when we're building arrays of state this can be bad. For example, - * consider this fragment of GLSL code: - * foo = gl_LightSource[3].diffuse; - * ... - * bar = gl_LightSource[i].diffuse; - * - * When we unroll the gl_LightSource array (for "bar") we want to re-emit - * gl_LightSource[3].diffuse and not re-use the first instance (from "foo") - * since that would upset the array layout. We handle this situation by - * setting the last token in the state var token array to the special - * value STATE_ARRAY. - * This token will only be set for array state. We can hijack the last - * element in the array for this since it's never used for light, clipplane - * or texture env array state. - */ - for (i = 0; i < STATE_LENGTH; i++) - tokens[i] = 0; - tokens[STATE_LENGTH - 1] = STATE_ARRAY; - - pos = emit_statevars(var->a_name, var->array_len, &var->type.specifier, - tokens, paramList); - - return pos; -} - - - -/** - * Allocate storage for a pre-defined uniform (a GL state variable). - * As a memory-saving optimization, we try to only allocate storage for - * state vars that are actually used. - * - * Arrays such as gl_LightSource are handled specially. For an expression - * like "gl_LightSource[2].diffuse", we can allocate a single uniform/constant - * slot and return the index. In this case, we return direct=TRUE. - * - * Buf for something like "gl_LightSource[i].diffuse" we don't know the value - * of 'i' at compile time so we need to "unroll" the gl_LightSource array - * into a consecutive sequence of uniform/constant slots so it can be indexed - * at runtime. In this case, we return direct=FALSE. - * - * Currently, all pre-defined uniforms are in one of these forms: - * var - * var[i] - * var.field - * var[i].field - * var[i][j] - * - * \return -1 upon error, else position in paramList of the state variable/data - */ -GLint -_slang_alloc_statevar(slang_ir_node *n, - struct gl_program_parameter_list *paramList, - GLboolean *direct) -{ - slang_ir_node *n0 = n; - const char *field = NULL; - GLint index1 = -1, index2 = -1; - GLuint swizzle; - - *direct = GL_TRUE; - - if (n->Opcode == IR_FIELD) { - field = n->Field; - n = n->Children[0]; - } - - if (n->Opcode == IR_ELEMENT) { - if (n->Children[1]->Opcode == IR_FLOAT) { - index1 = (GLint) n->Children[1]->Value[0]; - } - else { - *direct = GL_FALSE; - } - n = n->Children[0]; - } - - if (n->Opcode == IR_ELEMENT) { - /* XXX can only handle constant indexes for now */ - if (n->Children[1]->Opcode == IR_FLOAT) { - /* two-dimensional array index: mat[i][j] */ - index2 = index1; - index1 = (GLint) n->Children[1]->Value[0]; - } - else { - *direct = GL_FALSE; - } - n = n->Children[0]; - } - - assert(n->Opcode == IR_VAR); - - if (*direct) { - const char *var = (const char *) n->Var->a_name; - GLint pos = - lookup_statevar(var, index1, index2, field, &swizzle, paramList); - if (pos >= 0) { - /* newly resolved storage for the statevar/constant/uniform */ - n0->Store->File = PROGRAM_STATE_VAR; - n0->Store->Index = pos; - n0->Store->Swizzle = swizzle; - n0->Store->Parent = NULL; - return pos; - } - } - - *direct = GL_FALSE; - return alloc_state_var_array(n->Var, paramList); -} - - - - -#define SWIZZLE_ZWWW MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W) - - -/** Predefined shader inputs */ -struct input_info -{ - const char *Name; - GLuint Attrib; - GLenum Type; - GLuint Swizzle; - GLboolean Array; -}; - -/** Predefined vertex shader inputs/attributes */ -static const struct input_info vertInputs[] = { - { "gl_Vertex", VERT_ATTRIB_POS, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_Normal", VERT_ATTRIB_NORMAL, GL_FLOAT_VEC3, SWIZZLE_NOOP, GL_FALSE }, - { "gl_Color", VERT_ATTRIB_COLOR0, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_SecondaryColor", VERT_ATTRIB_COLOR1, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_FogCoord", VERT_ATTRIB_FOG, GL_FLOAT, SWIZZLE_XXXX, GL_FALSE }, - { "gl_MultiTexCoord0", VERT_ATTRIB_TEX0, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_MultiTexCoord1", VERT_ATTRIB_TEX1, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_MultiTexCoord2", VERT_ATTRIB_TEX2, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_MultiTexCoord3", VERT_ATTRIB_TEX3, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_MultiTexCoord4", VERT_ATTRIB_TEX4, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_MultiTexCoord5", VERT_ATTRIB_TEX5, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_MultiTexCoord6", VERT_ATTRIB_TEX6, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_MultiTexCoord7", VERT_ATTRIB_TEX7, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE } -}; - -static const struct input_info geomInputs[] = { - { "gl_PrimitiveIDIn", GEOM_ATTRIB_PRIMITIVE_ID, GL_FLOAT, SWIZZLE_NOOP, GL_FALSE }, - { "gl_FrontColorIn", GEOM_ATTRIB_COLOR0, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_TRUE }, - { "gl_BackColorIn", GEOM_ATTRIB_COLOR1, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_TRUE }, - { "gl_FrontSecondaryColorIn", GEOM_ATTRIB_SECONDARY_COLOR0, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_TRUE }, - { "gl_BackSecondaryColorIn", GEOM_ATTRIB_SECONDARY_COLOR1, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_TRUE }, - { "gl_TexCoordIn", GEOM_ATTRIB_TEX_COORD, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_TRUE }, - { "gl_FogFragCoordIn", GEOM_ATTRIB_FOG_FRAG_COORD, GL_FLOAT, SWIZZLE_NOOP, GL_TRUE }, - { "gl_PositionIn", GEOM_ATTRIB_POSITION, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_TRUE }, - { "gl_ClipVertexIn", GEOM_ATTRIB_CLIP_VERTEX, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_TRUE }, - { "gl_PointSizeIn", GEOM_ATTRIB_POINT_SIZE, GL_FLOAT, SWIZZLE_NOOP, GL_TRUE } -}; - -/** Predefined fragment shader inputs */ -static const struct input_info fragInputs[] = { - { "gl_FragCoord", FRAG_ATTRIB_WPOS, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_Color", FRAG_ATTRIB_COL0, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_SecondaryColor", FRAG_ATTRIB_COL1, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_TexCoord", FRAG_ATTRIB_TEX0, GL_FLOAT_VEC4, SWIZZLE_NOOP, GL_FALSE }, - { "gl_FogFragCoord", FRAG_ATTRIB_FOGC, GL_FLOAT, SWIZZLE_XXXX, GL_FALSE }, - { "gl_FrontFacing", FRAG_ATTRIB_FACE, GL_FLOAT, SWIZZLE_XXXX, GL_FALSE }, - { "gl_PointCoord", FRAG_ATTRIB_PNTC, GL_FLOAT_VEC2, SWIZZLE_XYZW, GL_FALSE } -}; - - -/** - * Return the VERT_ATTRIB_* or FRAG_ATTRIB_* value that corresponds to - * a vertex or fragment program input variable. Return -1 if the input - * name is invalid. - * XXX return size too - */ -GLint -_slang_input_index(const char *name, GLenum target, GLuint *swizzleOut, - GLboolean *is_array) -{ - const struct input_info *inputs; - GLuint i, n; - - switch (target) { - case GL_VERTEX_PROGRAM_ARB: - inputs = vertInputs; - n = Elements(vertInputs); - break; - case GL_FRAGMENT_PROGRAM_ARB: - inputs = fragInputs; - n = Elements(fragInputs); - break; - case MESA_GEOMETRY_PROGRAM: - inputs = geomInputs; - n = Elements(geomInputs); - break; - default: - _mesa_problem(NULL, "bad target in _slang_input_index"); - return -1; - } - - ASSERT(MAX_TEXTURE_COORD_UNITS == 8); /* if this fails, fix vertInputs above */ - - for (i = 0; i < n; i++) { - if (strcmp(inputs[i].Name, name) == 0) { - /* found */ - *swizzleOut = inputs[i].Swizzle; - if (is_array) - *is_array = inputs[i].Array; - return inputs[i].Attrib; - } - } - return -1; -} - - -/** - * Return name of the given vertex attribute (VERT_ATTRIB_x). - */ -const char * -_slang_vert_attrib_name(GLuint attrib) -{ - GLuint i; - assert(attrib < VERT_ATTRIB_GENERIC0); - for (i = 0; Elements(vertInputs); i++) { - if (vertInputs[i].Attrib == attrib) - return vertInputs[i].Name; - } - return NULL; -} - - -/** - * Return type (GL_FLOAT, GL_FLOAT_VEC2, etc) of the given vertex - * attribute (VERT_ATTRIB_x). - */ -GLenum -_slang_vert_attrib_type(GLuint attrib) -{ - GLuint i; - assert(attrib < VERT_ATTRIB_GENERIC0); - for (i = 0; Elements(vertInputs); i++) { - if (vertInputs[i].Attrib == attrib) - return vertInputs[i].Type; - } - return GL_NONE; -} - - - - - -/** Predefined shader output info */ -struct output_info -{ - const char *Name; - GLuint Attrib; - GLenum Type; -}; - -/** Predefined vertex shader outputs */ -static const struct output_info vertOutputs[] = { - { "gl_Position", VERT_RESULT_HPOS, GL_FLOAT_VEC4 }, - { "gl_FrontColor", VERT_RESULT_COL0, GL_FLOAT_VEC4 }, - { "gl_BackColor", VERT_RESULT_BFC0, GL_FLOAT_VEC4 }, - { "gl_FrontSecondaryColor", VERT_RESULT_COL1, GL_FLOAT_VEC4 }, - { "gl_BackSecondaryColor", VERT_RESULT_BFC1, GL_FLOAT_VEC4 }, - { "gl_TexCoord", VERT_RESULT_TEX0, GL_FLOAT_VEC4 }, - { "gl_FogFragCoord", VERT_RESULT_FOGC, GL_FLOAT }, - { "gl_PointSize", VERT_RESULT_PSIZ, GL_FLOAT } -}; - -/** Predefined geometry shader outputs */ -static const struct output_info geomOutputs[] = { - { "gl_Position", GEOM_RESULT_POS, GL_FLOAT_VEC4 }, - { "gl_FrontColor", GEOM_RESULT_COL0, GL_FLOAT_VEC4 }, - { "gl_BackColor", GEOM_RESULT_COL1, GL_FLOAT_VEC4 }, - { "gl_FrontSecondaryColor", GEOM_RESULT_SCOL0, GL_FLOAT_VEC4 }, - { "gl_BackSecondaryColor", GEOM_RESULT_SCOL1, GL_FLOAT_VEC4 }, - { "gl_TexCoord", GEOM_RESULT_TEX0, GL_FLOAT_VEC4 }, - { "gl_FogFragCoord", GEOM_RESULT_FOGC, GL_FLOAT }, - { "gl_ClipVertex", GEOM_RESULT_CLPV, GL_FLOAT_VEC4 }, - { "gl_PointSize", GEOM_RESULT_PSIZ, GL_FLOAT }, - { "gl_PrimitiveID", GEOM_RESULT_PRID, GL_FLOAT }, - { "gl_Layer", GEOM_RESULT_LAYR, GL_FLOAT } -}; - -/** Predefined fragment shader outputs */ -static const struct output_info fragOutputs[] = { - { "gl_FragColor", FRAG_RESULT_COLOR, GL_FLOAT_VEC4 }, - { "gl_FragDepth", FRAG_RESULT_DEPTH, GL_FLOAT }, - { "gl_FragData", FRAG_RESULT_DATA0, GL_FLOAT_VEC4 } -}; - - -/** - * Return the VERT_RESULT_*, GEOM_RESULT_* or FRAG_RESULT_* value that corresponds - * to a vertex or fragment program output variable. Return -1 for an invalid - * output name. - */ -GLint -_slang_output_index(const char *name, GLenum target) -{ - const struct output_info *outputs; - GLuint i, n; - - switch (target) { - case GL_VERTEX_PROGRAM_ARB: - outputs = vertOutputs; - n = Elements(vertOutputs); - break; - case GL_FRAGMENT_PROGRAM_ARB: - outputs = fragOutputs; - n = Elements(fragOutputs); - break; - case MESA_GEOMETRY_PROGRAM: - outputs = geomOutputs; - n = Elements(geomOutputs); - break; - default: - _mesa_problem(NULL, "bad target in _slang_output_index"); - return -1; - } - - for (i = 0; i < n; i++) { - if (strcmp(outputs[i].Name, name) == 0) { - /* found */ - return outputs[i].Attrib; - } - } - return -1; -} - - -/** - * Given a VERT_RESULT_x index, return the corresponding string name. - */ -const char * -_slang_vertex_output_name(gl_vert_result index) -{ - if (index < Elements(vertOutputs)) - return vertOutputs[index].Name; - else - return NULL; -} - - -/** - * Given a GEOM_RESULT_x index, return the corresponding string name. - */ -const char * -_slang_geometry_output_name(gl_geom_result index) -{ - if (index < Elements(geomOutputs)) - return geomOutputs[index].Name; - else - return NULL; -} - - -/** - * Given a FRAG_RESULT_x index, return the corresponding string name. - */ -const char * -_slang_fragment_output_name(gl_frag_result index) -{ - if (index < Elements(fragOutputs)) - return fragOutputs[index].Name; - else - return NULL; -} - - -/** - * Given a VERT_RESULT_x index, return the corresponding varying - * var's datatype. - */ -GLenum -_slang_vertex_output_type(gl_vert_result index) -{ - if (index < Elements(vertOutputs)) - return vertOutputs[index].Type; - else - return GL_NONE; -} diff --git a/src/mesa/slang/slang_builtin.h b/src/mesa/slang/slang_builtin.h deleted file mode 100644 index dc92f83f8e..0000000000 --- a/src/mesa/slang/slang_builtin.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#ifndef SLANG_BUILTIN_H -#define SLANG_BUILTIN_H - -#include "main/glheader.h" -#include "main/mtypes.h" -#include "slang_ir.h" - - -extern GLint -_slang_alloc_statevar(slang_ir_node *n, - struct gl_program_parameter_list *paramList, - GLboolean *direct); - - -extern GLint -_slang_input_index(const char *name, GLenum target, GLuint *swizzleOut, - GLboolean *is_array); - -extern GLint -_slang_output_index(const char *name, GLenum target); - - -extern const char * -_slang_vert_attrib_name(GLuint attrib); - -extern GLenum -_slang_vert_attrib_type(GLuint attrib); - - -const char * -_slang_vertex_output_name(gl_vert_result index); - -const char * -_slang_fragment_output_name(gl_frag_result index); - -const char * -_slang_geometry_output_name(gl_geom_result index); - -GLenum -_slang_vertex_output_type(gl_vert_result index); - - -#endif /* SLANG_BUILTIN_H */ diff --git a/src/mesa/slang/slang_codegen.c b/src/mesa/slang/slang_codegen.c deleted file mode 100644 index 95787e4409..0000000000 --- a/src/mesa/slang/slang_codegen.c +++ /dev/null @@ -1,5410 +0,0 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * Copyright (C) 2008 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_codegen.c - * Generate IR tree from AST. - * \author Brian Paul - */ - - -/*** - *** NOTES: - *** The new_() functions return a new instance of a simple IR node. - *** The gen_() functions generate larger IR trees from the simple nodes. - ***/ - - - -#include "main/imports.h" -#include "main/macros.h" -#include "main/mtypes.h" -#include "program/program.h" -#include "program/prog_instruction.h" -#include "program/prog_parameter.h" -#include "program/prog_print.h" -#include "program/prog_statevars.h" -#include "slang_typeinfo.h" -#include "slang_builtin.h" -#include "slang_codegen.h" -#include "slang_compile.h" -#include "slang_label.h" -#include "slang_mem.h" -#include "slang_simplify.h" -#include "slang_emit.h" -#include "slang_vartable.h" -#include "slang_ir.h" -#include "slang_print.h" - - -/** Max iterations to unroll */ -const GLuint MAX_FOR_LOOP_UNROLL_ITERATIONS = 32; - -/** Max for-loop body size (in slang operations) to unroll */ -const GLuint MAX_FOR_LOOP_UNROLL_BODY_SIZE = 50; - -/** Max for-loop body complexity to unroll. - * We'll compute complexity as the product of the number of iterations - * and the size of the body. So long-ish loops with very simple bodies - * can be unrolled, as well as short loops with larger bodies. - */ -const GLuint MAX_FOR_LOOP_UNROLL_COMPLEXITY = 256; - - - -static slang_ir_node * -_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper); - -static void -slang_substitute(slang_assemble_ctx *A, slang_operation *oper, - GLuint substCount, slang_variable **substOld, - slang_operation **substNew, GLboolean isLHS); - - -/** - * Retrieves type information about an operation. - * Returns GL_TRUE on success. - * Returns GL_FALSE otherwise. - */ -static GLboolean -typeof_operation(const struct slang_assemble_ctx_ *A, - slang_operation *op, - slang_typeinfo *ti) -{ - return _slang_typeof_operation(op, &A->space, ti, A->atoms, A->log); -} - - -static GLboolean -is_sampler_type(const slang_fully_specified_type *t) -{ - switch (t->specifier.type) { - case SLANG_SPEC_SAMPLER_1D: - case SLANG_SPEC_SAMPLER_2D: - case SLANG_SPEC_SAMPLER_3D: - case SLANG_SPEC_SAMPLER_CUBE: - case SLANG_SPEC_SAMPLER_1D_SHADOW: - case SLANG_SPEC_SAMPLER_2D_SHADOW: - case SLANG_SPEC_SAMPLER_RECT: - case SLANG_SPEC_SAMPLER_RECT_SHADOW: - case SLANG_SPEC_SAMPLER_1D_ARRAY: - case SLANG_SPEC_SAMPLER_2D_ARRAY: - case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: - case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Return the offset (in floats or ints) of the named field within - * the given struct. Return -1 if field not found. - * If field is NULL, return the size of the struct instead. - */ -static GLint -_slang_field_offset(const slang_type_specifier *spec, slang_atom field) -{ - GLint offset = 0; - GLuint i; - for (i = 0; i < spec->_struct->fields->num_variables; i++) { - const slang_variable *v = spec->_struct->fields->variables[i]; - const GLuint sz = _slang_sizeof_type_specifier(&v->type.specifier); - if (sz > 1) { - /* types larger than 1 float are register (4-float) aligned */ - offset = (offset + 3) & ~3; - } - if (field && v->a_name == field) { - return offset; - } - offset += sz; - } - if (field) - return -1; /* field not found */ - else - return offset; /* struct size */ -} - - -/** - * Return the size (in floats) of the given type specifier. - * If the size is greater than 4, the size should be a multiple of 4 - * so that the correct number of 4-float registers are allocated. - * For example, a mat3x2 is size 12 because we want to store the - * 3 columns in 3 float[4] registers. - */ -GLuint -_slang_sizeof_type_specifier(const slang_type_specifier *spec) -{ - GLuint sz; - switch (spec->type) { - case SLANG_SPEC_VOID: - sz = 0; - break; - case SLANG_SPEC_BOOL: - sz = 1; - break; - case SLANG_SPEC_BVEC2: - sz = 2; - break; - case SLANG_SPEC_BVEC3: - sz = 3; - break; - case SLANG_SPEC_BVEC4: - sz = 4; - break; - case SLANG_SPEC_INT: - sz = 1; - break; - case SLANG_SPEC_IVEC2: - sz = 2; - break; - case SLANG_SPEC_IVEC3: - sz = 3; - break; - case SLANG_SPEC_IVEC4: - sz = 4; - break; - case SLANG_SPEC_FLOAT: - sz = 1; - break; - case SLANG_SPEC_VEC2: - sz = 2; - break; - case SLANG_SPEC_VEC3: - sz = 3; - break; - case SLANG_SPEC_VEC4: - sz = 4; - break; - case SLANG_SPEC_MAT2: - sz = 2 * 4; /* 2 columns (regs) */ - break; - case SLANG_SPEC_MAT3: - sz = 3 * 4; - break; - case SLANG_SPEC_MAT4: - sz = 4 * 4; - break; - case SLANG_SPEC_MAT23: - sz = 2 * 4; /* 2 columns (regs) */ - break; - case SLANG_SPEC_MAT32: - sz = 3 * 4; /* 3 columns (regs) */ - break; - case SLANG_SPEC_MAT24: - sz = 2 * 4; - break; - case SLANG_SPEC_MAT42: - sz = 4 * 4; /* 4 columns (regs) */ - break; - case SLANG_SPEC_MAT34: - sz = 3 * 4; - break; - case SLANG_SPEC_MAT43: - sz = 4 * 4; /* 4 columns (regs) */ - break; - case SLANG_SPEC_SAMPLER_1D: - case SLANG_SPEC_SAMPLER_2D: - case SLANG_SPEC_SAMPLER_3D: - case SLANG_SPEC_SAMPLER_CUBE: - case SLANG_SPEC_SAMPLER_1D_SHADOW: - case SLANG_SPEC_SAMPLER_2D_SHADOW: - case SLANG_SPEC_SAMPLER_RECT: - case SLANG_SPEC_SAMPLER_RECT_SHADOW: - case SLANG_SPEC_SAMPLER_1D_ARRAY: - case SLANG_SPEC_SAMPLER_2D_ARRAY: - case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: - case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: - sz = 1; /* a sampler is basically just an integer index */ - break; - case SLANG_SPEC_STRUCT: - sz = _slang_field_offset(spec, 0); /* special use */ - if (sz == 1) { - /* 1-float structs are actually troublesome to deal with since they - * might get placed at R.x, R.y, R.z or R.z. Return size=2 to - * ensure the object is placed at R.x - */ - sz = 2; - } - else if (sz > 4) { - sz = (sz + 3) & ~0x3; /* round up to multiple of four */ - } - break; - case SLANG_SPEC_ARRAY: - sz = _slang_sizeof_type_specifier(spec->_array); - break; - default: - _mesa_problem(NULL, "Unexpected type in _slang_sizeof_type_specifier()"); - sz = 0; - } - - if (sz > 4) { - /* if size is > 4, it should be a multiple of four */ - assert((sz & 0x3) == 0); - } - return sz; -} - - -/** - * Query variable/array length (number of elements). - * This is slightly non-trivial because there are two ways to express - * arrays: "float x[3]" vs. "float[3] x". - * \return the length of the array for the given variable, or 0 if not an array - */ -static GLint -_slang_array_length(const slang_variable *var) -{ - if (var->type.array_len > 0) { - /* Ex: float[4] x; */ - return var->type.array_len; - } - if (var->array_len > 0) { - /* Ex: float x[4]; */ - return var->array_len; - } - return 0; -} - - -/** - * Compute total size of array give size of element, number of elements. - * \return size in floats - */ -static GLint -_slang_array_size(GLint elemSize, GLint arrayLen) -{ - GLint total; - assert(elemSize > 0); - if (arrayLen > 1) { - /* round up base type to multiple of 4 */ - total = ((elemSize + 3) & ~0x3) * MAX2(arrayLen, 1); - } - else { - total = elemSize; - } - return total; -} - - -/** - * Return the TEXTURE_*_INDEX value that corresponds to a sampler type, - * or -1 if the type is not a sampler. - */ -static GLint -sampler_to_texture_index(const slang_type_specifier_type type) -{ - switch (type) { - case SLANG_SPEC_SAMPLER_1D: - return TEXTURE_1D_INDEX; - case SLANG_SPEC_SAMPLER_2D: - return TEXTURE_2D_INDEX; - case SLANG_SPEC_SAMPLER_3D: - return TEXTURE_3D_INDEX; - case SLANG_SPEC_SAMPLER_CUBE: - return TEXTURE_CUBE_INDEX; - case SLANG_SPEC_SAMPLER_1D_SHADOW: - return TEXTURE_1D_INDEX; /* XXX fix */ - case SLANG_SPEC_SAMPLER_2D_SHADOW: - return TEXTURE_2D_INDEX; /* XXX fix */ - case SLANG_SPEC_SAMPLER_RECT: - return TEXTURE_RECT_INDEX; - case SLANG_SPEC_SAMPLER_RECT_SHADOW: - return TEXTURE_RECT_INDEX; /* XXX fix */ - case SLANG_SPEC_SAMPLER_1D_ARRAY: - return TEXTURE_1D_ARRAY_INDEX; - case SLANG_SPEC_SAMPLER_2D_ARRAY: - return TEXTURE_2D_ARRAY_INDEX; - case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: - return TEXTURE_1D_ARRAY_INDEX; - case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: - return TEXTURE_2D_ARRAY_INDEX; - default: - return -1; - } -} - - -/** helper to build a SLANG_OPER_IDENTIFIER node */ -static void -slang_operation_identifier(slang_operation *oper, - slang_assemble_ctx *A, - const char *name) -{ - oper->type = SLANG_OPER_IDENTIFIER; - oper->a_id = slang_atom_pool_atom(A->atoms, name); -} - - -/** - * Called when we begin code/IR generation for a new while/do/for loop. - */ -static void -push_loop(slang_assemble_ctx *A, slang_operation *loopOper, slang_ir_node *loopIR) -{ - A->LoopOperStack[A->LoopDepth] = loopOper; - A->LoopIRStack[A->LoopDepth] = loopIR; - A->LoopDepth++; -} - - -/** - * Called when we end code/IR generation for a new while/do/for loop. - */ -static void -pop_loop(slang_assemble_ctx *A) -{ - assert(A->LoopDepth > 0); - A->LoopDepth--; -} - - -/** - * Return pointer to slang_operation for the loop we're currently inside, - * or NULL if not in a loop. - */ -static const slang_operation * -current_loop_oper(const slang_assemble_ctx *A) -{ - if (A->LoopDepth > 0) - return A->LoopOperStack[A->LoopDepth - 1]; - else - return NULL; -} - - -/** - * Return pointer to slang_ir_node for the loop we're currently inside, - * or NULL if not in a loop. - */ -static slang_ir_node * -current_loop_ir(const slang_assemble_ctx *A) -{ - if (A->LoopDepth > 0) - return A->LoopIRStack[A->LoopDepth - 1]; - else - return NULL; -} - - -/**********************************************************************/ - - -/** - * Map "_asm foo" to IR_FOO, etc. - */ -typedef struct -{ - const char *Name; - slang_ir_opcode Opcode; - GLuint HaveRetValue, NumParams; -} slang_asm_info; - - -static slang_asm_info AsmInfo[] = { - /* vec4 binary op */ - { "vec4_add", IR_ADD, 1, 2 }, - { "vec4_subtract", IR_SUB, 1, 2 }, - { "vec4_multiply", IR_MUL, 1, 2 }, - { "vec4_dot", IR_DOT4, 1, 2 }, - { "vec3_dot", IR_DOT3, 1, 2 }, - { "vec2_dot", IR_DOT2, 1, 2 }, - { "vec3_nrm", IR_NRM3, 1, 1 }, - { "vec4_nrm", IR_NRM4, 1, 1 }, - { "vec3_cross", IR_CROSS, 1, 2 }, - { "vec4_lrp", IR_LRP, 1, 3 }, - { "vec4_min", IR_MIN, 1, 2 }, - { "vec4_max", IR_MAX, 1, 2 }, - { "vec4_cmp", IR_CMP, 1, 3 }, - { "vec4_clamp", IR_CLAMP, 1, 3 }, - { "vec4_seq", IR_SEQUAL, 1, 2 }, - { "vec4_sne", IR_SNEQUAL, 1, 2 }, - { "vec4_sge", IR_SGE, 1, 2 }, - { "vec4_sgt", IR_SGT, 1, 2 }, - { "vec4_sle", IR_SLE, 1, 2 }, - { "vec4_slt", IR_SLT, 1, 2 }, - /* vec4 unary */ - { "vec4_move", IR_MOVE, 1, 1 }, - { "vec4_floor", IR_FLOOR, 1, 1 }, - { "vec4_frac", IR_FRAC, 1, 1 }, - { "vec4_abs", IR_ABS, 1, 1 }, - { "vec4_negate", IR_NEG, 1, 1 }, - { "vec4_ddx", IR_DDX, 1, 1 }, - { "vec4_ddy", IR_DDY, 1, 1 }, - /* float binary op */ - { "float_power", IR_POW, 1, 2 }, - /* texture / sampler */ - { "vec4_tex_1d", IR_TEX, 1, 2 }, - { "vec4_tex_1d_bias", IR_TEXB, 1, 2 }, /* 1d w/ bias */ - { "vec4_tex_1d_proj", IR_TEXP, 1, 2 }, /* 1d w/ projection */ - { "vec4_tex_2d", IR_TEX, 1, 2 }, - { "vec4_tex_2d_bias", IR_TEXB, 1, 2 }, /* 2d w/ bias */ - { "vec4_tex_2d_proj", IR_TEXP, 1, 2 }, /* 2d w/ projection */ - { "vec4_tex_3d", IR_TEX, 1, 2 }, - { "vec4_tex_3d_bias", IR_TEXB, 1, 2 }, /* 3d w/ bias */ - { "vec4_tex_3d_proj", IR_TEXP, 1, 2 }, /* 3d w/ projection */ - { "vec4_tex_cube", IR_TEX, 1, 2 }, /* cubemap */ - { "vec4_tex_rect", IR_TEX, 1, 2 }, /* rectangle */ - { "vec4_tex_rect_bias", IR_TEX, 1, 2 }, /* rectangle w/ projection */ - { "vec4_tex_1d_array", IR_TEX, 1, 2 }, - { "vec4_tex_1d_array_bias", IR_TEXB, 1, 2 }, - { "vec4_tex_1d_array_shadow", IR_TEX, 1, 2 }, - { "vec4_tex_1d_array_bias_shadow", IR_TEXB, 1, 2 }, - { "vec4_tex_2d_array", IR_TEX, 1, 2 }, - { "vec4_tex_2d_array_bias", IR_TEXB, 1, 2 }, - { "vec4_tex_2d_array_shadow", IR_TEX, 1, 2 }, - { "vec4_tex_2d_array_bias_shadow", IR_TEXB, 1, 2 }, - - /* texture / sampler but with shadow comparison */ - { "vec4_tex_1d_shadow", IR_TEX_SH, 1, 2 }, - { "vec4_tex_1d_bias_shadow", IR_TEXB_SH, 1, 2 }, - { "vec4_tex_1d_proj_shadow", IR_TEXP_SH, 1, 2 }, - { "vec4_tex_2d_shadow", IR_TEX_SH, 1, 2 }, - { "vec4_tex_2d_bias_shadow", IR_TEXB_SH, 1, 2 }, - { "vec4_tex_2d_proj_shadow", IR_TEXP_SH, 1, 2 }, - { "vec4_tex_rect_shadow", IR_TEX_SH, 1, 2 }, - { "vec4_tex_rect_proj_shadow", IR_TEXP_SH, 1, 2 }, - - /* unary op */ - { "ivec4_to_vec4", IR_I_TO_F, 1, 1 }, /* int[4] to float[4] */ - { "vec4_to_ivec4", IR_F_TO_I, 1, 1 }, /* float[4] to int[4] */ - { "float_exp", IR_EXP, 1, 1 }, - { "float_exp2", IR_EXP2, 1, 1 }, - { "float_log2", IR_LOG2, 1, 1 }, - { "float_rsq", IR_RSQ, 1, 1 }, - { "float_rcp", IR_RCP, 1, 1 }, - { "float_sine", IR_SIN, 1, 1 }, - { "float_cosine", IR_COS, 1, 1 }, - { "float_noise1", IR_NOISE1, 1, 1}, - { "float_noise2", IR_NOISE2, 1, 1}, - { "float_noise3", IR_NOISE3, 1, 1}, - { "float_noise4", IR_NOISE4, 1, 1}, - - { "emit_vertex", IR_EMIT_VERTEX, 0, 0}, - { "end_primitive", IR_END_PRIMITIVE, 0, 0}, - - { NULL, IR_NOP, 0, 0 } -}; - - -static slang_ir_node * -new_node3(slang_ir_opcode op, - slang_ir_node *c0, slang_ir_node *c1, slang_ir_node *c2) -{ - slang_ir_node *n = (slang_ir_node *) _slang_alloc(sizeof(slang_ir_node)); - if (n) { - n->Opcode = op; - n->Children[0] = c0; - n->Children[1] = c1; - n->Children[2] = c2; - n->InstLocation = -1; - } - return n; -} - -static slang_ir_node * -new_node2(slang_ir_opcode op, slang_ir_node *c0, slang_ir_node *c1) -{ - return new_node3(op, c0, c1, NULL); -} - -static slang_ir_node * -new_node1(slang_ir_opcode op, slang_ir_node *c0) -{ - return new_node3(op, c0, NULL, NULL); -} - -static slang_ir_node * -new_node0(slang_ir_opcode op) -{ - return new_node3(op, NULL, NULL, NULL); -} - - -/** - * Create sequence of two nodes. - */ -static slang_ir_node * -new_seq(slang_ir_node *left, slang_ir_node *right) -{ - if (!left) - return right; - if (!right) - return left; - return new_node2(IR_SEQ, left, right); -} - -static slang_ir_node * -new_label(slang_label *label) -{ - slang_ir_node *n = new_node0(IR_LABEL); - assert(label); - if (n) - n->Label = label; - return n; -} - -static slang_ir_node * -new_float_literal(const float v[4], GLuint size) -{ - slang_ir_node *n = new_node0(IR_FLOAT); - assert(size <= 4); - COPY_4V(n->Value, v); - /* allocate a storage object, but compute actual location (Index) later */ - n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size); - return n; -} - - -static slang_ir_node * -new_not(slang_ir_node *n) -{ - return new_node1(IR_NOT, n); -} - - -/** - * Non-inlined function call. - */ -static slang_ir_node * -new_function_call(slang_ir_node *code, slang_label *name) -{ - slang_ir_node *n = new_node1(IR_CALL, code); - assert(name); - if (n) - n->Label = name; - return n; -} - - -/** - * Unconditional jump. - */ -static slang_ir_node * -new_return(slang_label *dest) -{ - slang_ir_node *n = new_node0(IR_RETURN); - assert(dest); - if (n) - n->Label = dest; - return n; -} - - -static slang_ir_node * -new_loop(slang_ir_node *body) -{ - return new_node1(IR_LOOP, body); -} - - -static slang_ir_node * -new_break(slang_ir_node *loopNode) -{ - slang_ir_node *n = new_node0(IR_BREAK); - assert(loopNode); - assert(loopNode->Opcode == IR_LOOP); - if (n) { - /* insert this node at head of linked list of cont/break instructions */ - n->List = loopNode->List; - loopNode->List = n; - } - return n; -} - - -/** - * Make new IR_BREAK_IF_TRUE. - */ -static slang_ir_node * -new_break_if_true(slang_assemble_ctx *A, slang_ir_node *cond) -{ - slang_ir_node *loopNode = current_loop_ir(A); - slang_ir_node *n; - assert(loopNode); - assert(loopNode->Opcode == IR_LOOP); - n = new_node1(IR_BREAK_IF_TRUE, cond); - if (n) { - /* insert this node at head of linked list of cont/break instructions */ - n->List = loopNode->List; - loopNode->List = n; - } - return n; -} - - -/** - * Make new IR_CONT_IF_TRUE node. - */ -static slang_ir_node * -new_cont_if_true(slang_assemble_ctx *A, slang_ir_node *cond) -{ - slang_ir_node *loopNode = current_loop_ir(A); - slang_ir_node *n; - assert(loopNode); - assert(loopNode->Opcode == IR_LOOP); - n = new_node1(IR_CONT_IF_TRUE, cond); - if (n) { - n->Parent = loopNode; /* pointer to containing loop */ - /* insert this node at head of linked list of cont/break instructions */ - n->List = loopNode->List; - loopNode->List = n; - } - return n; -} - - -static slang_ir_node * -new_cond(slang_ir_node *n) -{ - slang_ir_node *c = new_node1(IR_COND, n); - return c; -} - - -static slang_ir_node * -new_if(slang_ir_node *cond, slang_ir_node *ifPart, slang_ir_node *elsePart) -{ - return new_node3(IR_IF, cond, ifPart, elsePart); -} - - -/** - * New IR_VAR node - a reference to a previously declared variable. - */ -static slang_ir_node * -new_var(slang_assemble_ctx *A, slang_variable *var) -{ - slang_ir_node *n = new_node0(IR_VAR); - if (n) { - ASSERT(var); - ASSERT(var->store); - ASSERT(!n->Store); - ASSERT(!n->Var); - - /* Set IR node's Var and Store pointers */ - n->Var = var; - n->Store = var->store; - } - return n; -} - - -/** - * Check if the given function is really just a wrapper for a - * basic assembly instruction. - */ -static GLboolean -slang_is_asm_function(const slang_function *fun) -{ - if (fun->body->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE && - fun->body->num_children == 1 && - fun->body->children[0].type == SLANG_OPER_ASM) { - return GL_TRUE; - } - return GL_FALSE; -} - - -static GLboolean -_slang_is_noop(const slang_operation *oper) -{ - if (!oper || - oper->type == SLANG_OPER_VOID || - (oper->num_children == 1 && oper->children[0].type == SLANG_OPER_VOID)) - return GL_TRUE; - else - return GL_FALSE; -} - - -/** - * Recursively search tree for a node of the given type. - */ -#if 0 -static slang_operation * -_slang_find_node_type(slang_operation *oper, slang_operation_type type) -{ - GLuint i; - if (oper->type == type) - return oper; - for (i = 0; i < oper->num_children; i++) { - slang_operation *p = _slang_find_node_type(&oper->children[i], type); - if (p) - return p; - } - return NULL; -} -#endif - - -/** - * Count the number of operations of the given time rooted at 'oper'. - */ -static GLuint -_slang_count_node_type(const slang_operation *oper, slang_operation_type type) -{ - GLuint i, count = 0; - if (oper->type == type) { - return 1; - } - for (i = 0; i < oper->num_children; i++) { - count += _slang_count_node_type(&oper->children[i], type); - } - return count; -} - - -/** - * Check if the 'return' statement found under 'oper' is a "tail return" - * that can be no-op'd. For example: - * - * void func(void) - * { - * .. do something .. - * return; // this is a no-op - * } - * - * This is used when determining if a function can be inlined. If the - * 'return' is not the last statement, we can't inline the function since - * we still need the semantic behaviour of the 'return' but we don't want - * to accidentally return from the _calling_ function. We'd need to use an - * unconditional branch, but we don't have such a GPU instruction (not - * always, at least). - */ -static GLboolean -_slang_is_tail_return(const slang_operation *oper) -{ - GLuint k = oper->num_children; - - while (k > 0) { - const slang_operation *last = &oper->children[k - 1]; - if (last->type == SLANG_OPER_RETURN) - return GL_TRUE; - else if (last->type == SLANG_OPER_IDENTIFIER || - last->type == SLANG_OPER_LABEL) - k--; /* try prev child */ - else if (last->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE || - last->type == SLANG_OPER_BLOCK_NEW_SCOPE) - /* try sub-children */ - return _slang_is_tail_return(last); - else - break; - } - - return GL_FALSE; -} - - -/** - * Generate a variable declaration opeartion. - * I.e.: generate AST code for "bool flag = false;" - */ -static void -slang_generate_declaration(slang_assemble_ctx *A, - slang_variable_scope *scope, - slang_operation *decl, - slang_type_specifier_type type, - const char *name, - GLint initValue) -{ - slang_variable *var; - - assert(type == SLANG_SPEC_BOOL || - type == SLANG_SPEC_INT); - - decl->type = SLANG_OPER_VARIABLE_DECL; - - var = slang_variable_scope_grow(scope); - - slang_fully_specified_type_construct(&var->type); - - var->type.specifier.type = type; - var->a_name = slang_atom_pool_atom(A->atoms, name); - decl->a_id = var->a_name; - var->initializer = slang_operation_new(1); - slang_operation_literal_bool(var->initializer, initValue); -} - - -static void -slang_resolve_variable(slang_operation *oper) -{ - if (oper->type == SLANG_OPER_IDENTIFIER && !oper->var) { - oper->var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); - } -} - - -/** - * Rewrite AST code for "return expression;". - * - * We return values from functions by assinging the returned value to - * the hidden __retVal variable which is an extra 'out' parameter we add - * to the function signature. - * This code basically converts "return expr;" into "__retVal = expr; return;" - * - * \return the new AST code. - */ -static slang_operation * -gen_return_with_expression(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_operation *blockOper, *assignOper; - - assert(oper->type == SLANG_OPER_RETURN); - - if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "illegal return expression"); - return NULL; - } - - blockOper = slang_operation_new(1); - blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; - blockOper->locals->outer_scope = oper->locals->outer_scope; - slang_operation_add_children(blockOper, 2); - - if (A->UseReturnFlag) { - /* Emit: - * { - * if (__notRetFlag) - * __retVal = expr; - * __notRetFlag = 0; - * } - */ - { - slang_operation *ifOper = slang_oper_child(blockOper, 0); - ifOper->type = SLANG_OPER_IF; - slang_operation_add_children(ifOper, 3); - { - slang_operation *cond = slang_oper_child(ifOper, 0); - cond->type = SLANG_OPER_IDENTIFIER; - cond->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); - } - { - slang_operation *elseOper = slang_oper_child(ifOper, 2); - elseOper->type = SLANG_OPER_VOID; - } - assignOper = slang_oper_child(ifOper, 1); - } - { - slang_operation *setOper = slang_oper_child(blockOper, 1); - setOper->type = SLANG_OPER_ASSIGN; - slang_operation_add_children(setOper, 2); - { - slang_operation *lhs = slang_oper_child(setOper, 0); - lhs->type = SLANG_OPER_IDENTIFIER; - lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); - } - { - slang_operation *rhs = slang_oper_child(setOper, 1); - slang_operation_literal_bool(rhs, GL_FALSE); - } - } - } - else { - /* Emit: - * { - * __retVal = expr; - * return_inlined; - * } - */ - assignOper = slang_oper_child(blockOper, 0); - { - slang_operation *returnOper = slang_oper_child(blockOper, 1); - returnOper->type = SLANG_OPER_RETURN_INLINED; - assert(returnOper->num_children == 0); - } - } - - /* __retVal = expression; */ - assignOper->type = SLANG_OPER_ASSIGN; - slang_operation_add_children(assignOper, 2); - { - slang_operation *lhs = slang_oper_child(assignOper, 0); - lhs->type = SLANG_OPER_IDENTIFIER; - lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal"); - } - { - slang_operation *rhs = slang_oper_child(assignOper, 1); - slang_operation_copy(rhs, &oper->children[0]); - } - - /*blockOper->locals->outer_scope = oper->locals->outer_scope;*/ - - /*slang_print_tree(blockOper, 0);*/ - - return blockOper; -} - - -/** - * Rewrite AST code for "return;" (no expression). - */ -static slang_operation * -gen_return_without_expression(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_operation *newRet; - - assert(oper->type == SLANG_OPER_RETURN); - - if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "return statement requires an expression"); - return NULL; - } - - if (A->UseReturnFlag) { - /* Emit: - * __notRetFlag = 0; - */ - { - newRet = slang_operation_new(1); - newRet->locals->outer_scope = oper->locals->outer_scope; - newRet->type = SLANG_OPER_ASSIGN; - slang_operation_add_children(newRet, 2); - { - slang_operation *lhs = slang_oper_child(newRet, 0); - lhs->type = SLANG_OPER_IDENTIFIER; - lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); - } - { - slang_operation *rhs = slang_oper_child(newRet, 1); - slang_operation_literal_bool(rhs, GL_FALSE); - } - } - } - else { - /* Emit: - * return_inlined; - */ - newRet = slang_operation_new(1); - newRet->locals->outer_scope = oper->locals->outer_scope; - newRet->type = SLANG_OPER_RETURN_INLINED; - } - - /*slang_print_tree(newRet, 0);*/ - - return newRet; -} - - - - -/** - * Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions. - */ -static void -slang_substitute(slang_assemble_ctx *A, slang_operation *oper, - GLuint substCount, slang_variable **substOld, - slang_operation **substNew, GLboolean isLHS) -{ - switch (oper->type) { - case SLANG_OPER_VARIABLE_DECL: - { - slang_variable *v = _slang_variable_locate(oper->locals, - oper->a_id, GL_TRUE); - assert(v); - if (v->initializer && oper->num_children == 0) { - /* set child of oper to copy of initializer */ - oper->num_children = 1; - oper->children = slang_operation_new(1); - slang_operation_copy(&oper->children[0], v->initializer); - } - if (oper->num_children == 1) { - /* the initializer */ - slang_substitute(A, &oper->children[0], substCount, - substOld, substNew, GL_FALSE); - } - } - break; - case SLANG_OPER_IDENTIFIER: - assert(oper->num_children == 0); - if (1/**!isLHS XXX FIX */) { - slang_atom id = oper->a_id; - slang_variable *v; - GLuint i; - v = _slang_variable_locate(oper->locals, id, GL_TRUE); - if (!v) { -#if 0 - if (strcmp((char *) oper->a_id, "__notRetFlag")) - _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); -#endif - return; - } - - /* look for a substitution */ - for (i = 0; i < substCount; i++) { - if (v == substOld[i]) { - /* OK, replace this SLANG_OPER_IDENTIFIER with a new expr */ -#if 0 /* DEBUG only */ - if (substNew[i]->type == SLANG_OPER_IDENTIFIER) { - assert(substNew[i]->var); - assert(substNew[i]->var->a_name); - printf("Substitute %s with %s in id node %p\n", - (char*)v->a_name, (char*) substNew[i]->var->a_name, - (void*) oper); - } - else { - printf("Substitute %s with %f in id node %p\n", - (char*)v->a_name, substNew[i]->literal[0], - (void*) oper); - } -#endif - slang_operation_copy(oper, substNew[i]); - break; - } - } - } - break; - - case SLANG_OPER_RETURN: - { - slang_operation *newReturn; - /* generate new 'return' code' */ - if (slang_oper_child(oper, 0)->type == SLANG_OPER_VOID) - newReturn = gen_return_without_expression(A, oper); - else - newReturn = gen_return_with_expression(A, oper); - - if (!newReturn) - return; - - /* do substitutions on the new 'return' code */ - slang_substitute(A, newReturn, - substCount, substOld, substNew, GL_FALSE); - - /* install new 'return' code */ - slang_operation_copy(oper, newReturn); - slang_operation_destruct(newReturn); - } - break; - - case SLANG_OPER_ASSIGN: - case SLANG_OPER_SUBSCRIPT: - /* special case: - * child[0] can't have substitutions but child[1] can. - */ - slang_substitute(A, &oper->children[0], - substCount, substOld, substNew, GL_TRUE); - slang_substitute(A, &oper->children[1], - substCount, substOld, substNew, GL_FALSE); - break; - case SLANG_OPER_FIELD: - /* XXX NEW - test */ - slang_substitute(A, &oper->children[0], - substCount, substOld, substNew, GL_TRUE); - break; - default: - { - GLuint i; - for (i = 0; i < oper->num_children; i++) - slang_substitute(A, &oper->children[i], - substCount, substOld, substNew, GL_FALSE); - } - } -} - - -/** - * Produce inline code for a call to an assembly instruction. - * This is typically used to compile a call to a built-in function like this: - * - * vec4 mix(const vec4 x, const vec4 y, const vec4 a) - * { - * __asm vec4_lrp __retVal, a, y, x; - * } - * - * - * A call to - * r = mix(p1, p2, p3); - * - * Becomes: - * - * mov - * / \ - * r vec4_lrp - * / | \ - * p3 p2 p1 - * - * We basically translate a SLANG_OPER_CALL into a SLANG_OPER_ASM. - */ -static slang_operation * -slang_inline_asm_function(slang_assemble_ctx *A, - slang_function *fun, slang_operation *oper) -{ - const GLuint numArgs = oper->num_children; - GLuint i; - slang_operation *inlined; - const GLboolean haveRetValue = _slang_function_has_return_value(fun); - slang_variable **substOld; - slang_operation **substNew; - - ASSERT(slang_is_asm_function(fun)); - ASSERT(fun->param_count == numArgs + haveRetValue); - - /* - printf("Inline %s as %s\n", - (char*) fun->header.a_name, - (char*) fun->body->children[0].a_id); - */ - - /* - * We'll substitute formal params with actual args in the asm call. - */ - substOld = (slang_variable **) - _slang_alloc(numArgs * sizeof(slang_variable *)); - substNew = (slang_operation **) - _slang_alloc(numArgs * sizeof(slang_operation *)); - for (i = 0; i < numArgs; i++) { - substOld[i] = fun->parameters->variables[i]; - substNew[i] = oper->children + i; - } - - /* make a copy of the code to inline */ - inlined = slang_operation_new(1); - slang_operation_copy(inlined, &fun->body->children[0]); - if (haveRetValue) { - /* get rid of the __retVal child */ - inlined->num_children--; - for (i = 0; i < inlined->num_children; i++) { - inlined->children[i] = inlined->children[i + 1]; - } - } - - /* now do formal->actual substitutions */ - slang_substitute(A, inlined, numArgs, substOld, substNew, GL_FALSE); - - _slang_free(substOld); - _slang_free(substNew); - -#if 0 - printf("+++++++++++++ inlined asm function %s +++++++++++++\n", - (char *) fun->header.a_name); - slang_print_tree(inlined, 3); - printf("+++++++++++++++++++++++++++++++++++++++++++++++++++\n"); -#endif - - return inlined; -} - - -/** - * Inline the given function call operation. - * Return a new slang_operation that corresponds to the inlined code. - */ -static slang_operation * -slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, - slang_operation *oper, slang_operation *returnOper) -{ - typedef enum { - SUBST = 1, - COPY_IN, - COPY_OUT - } ParamMode; - ParamMode *paramMode; - const GLboolean haveRetValue = _slang_function_has_return_value(fun); - const GLuint numArgs = oper->num_children; - const GLuint totalArgs = numArgs + haveRetValue; - slang_operation *args = oper->children; - slang_operation *inlined, *top; - slang_variable **substOld; - slang_operation **substNew; - GLuint substCount, numCopyIn, i; - slang_function *prevFunction; - slang_variable_scope *newScope = NULL; - - /* save / push */ - prevFunction = A->CurFunction; - A->CurFunction = fun; - - /*assert(oper->type == SLANG_OPER_CALL); (or (matrix) multiply, etc) */ - assert(fun->param_count == totalArgs); - - /* allocate temporary arrays */ - paramMode = (ParamMode *) - _slang_alloc(totalArgs * sizeof(ParamMode)); - substOld = (slang_variable **) - _slang_alloc(totalArgs * sizeof(slang_variable *)); - substNew = (slang_operation **) - _slang_alloc(totalArgs * sizeof(slang_operation *)); - -#if 0 - printf("\nInline call to %s (total vars=%d nparams=%d)\n", - (char *) fun->header.a_name, - fun->parameters->num_variables, numArgs); -#endif - - if (haveRetValue && !returnOper) { - /* Create 3-child comma sequence for inlined code: - * child[0]: declare __resultTmp - * child[1]: inlined function body - * child[2]: __resultTmp - */ - slang_operation *commaSeq; - slang_operation *declOper = NULL; - slang_variable *resultVar; - - commaSeq = slang_operation_new(1); - commaSeq->type = SLANG_OPER_SEQUENCE; - assert(commaSeq->locals); - commaSeq->locals->outer_scope = oper->locals->outer_scope; - commaSeq->num_children = 3; - commaSeq->children = slang_operation_new(3); - /* allocate the return var */ - resultVar = slang_variable_scope_grow(commaSeq->locals); - /* - printf("Alloc __resultTmp in scope %p for retval of calling %s\n", - (void*)commaSeq->locals, (char *) fun->header.a_name); - */ - - resultVar->a_name = slang_atom_pool_atom(A->atoms, "__resultTmp"); - resultVar->type = fun->header.type; /* XXX copy? */ - resultVar->isTemp = GL_TRUE; - - /* child[0] = __resultTmp declaration */ - declOper = &commaSeq->children[0]; - declOper->type = SLANG_OPER_VARIABLE_DECL; - declOper->a_id = resultVar->a_name; - declOper->locals->outer_scope = commaSeq->locals; - - /* child[1] = function body */ - inlined = &commaSeq->children[1]; - inlined->locals->outer_scope = commaSeq->locals; - - /* child[2] = __resultTmp reference */ - returnOper = &commaSeq->children[2]; - returnOper->type = SLANG_OPER_IDENTIFIER; - returnOper->a_id = resultVar->a_name; - returnOper->locals->outer_scope = commaSeq->locals; - - top = commaSeq; - } - else { - top = inlined = slang_operation_new(1); - /* XXXX this may be inappropriate!!!! */ - inlined->locals->outer_scope = oper->locals->outer_scope; - } - - - assert(inlined->locals); - - /* Examine the parameters, look for inout/out params, look for possible - * substitutions, etc: - * param type behaviour - * in copy actual to local - * const in substitute param with actual - * out copy out - */ - substCount = 0; - for (i = 0; i < totalArgs; i++) { - slang_variable *p = fun->parameters->variables[i]; - /* - printf("Param %d: %s %s \n", i, - slang_type_qual_string(p->type.qualifier), - (char *) p->a_name); - */ - if (p->type.qualifier == SLANG_QUAL_INOUT || - p->type.qualifier == SLANG_QUAL_OUT) { - /* an output param */ - slang_operation *arg; - if (i < numArgs) - arg = &args[i]; - else - arg = returnOper; - paramMode[i] = SUBST; - - if (arg->type == SLANG_OPER_IDENTIFIER) - slang_resolve_variable(arg); - - /* replace parameter 'p' with argument 'arg' */ - substOld[substCount] = p; - substNew[substCount] = arg; /* will get copied */ - substCount++; - } - else if (p->type.qualifier == SLANG_QUAL_CONST) { - /* a constant input param */ - if (args[i].type == SLANG_OPER_IDENTIFIER || - args[i].type == SLANG_OPER_LITERAL_FLOAT || - args[i].type == SLANG_OPER_SUBSCRIPT) { - /* replace all occurances of this parameter variable with the - * actual argument variable or a literal. - */ - paramMode[i] = SUBST; - slang_resolve_variable(&args[i]); - substOld[substCount] = p; - substNew[substCount] = &args[i]; /* will get copied */ - substCount++; - } - else { - paramMode[i] = COPY_IN; - } - } - else { - paramMode[i] = COPY_IN; - } - assert(paramMode[i]); - } - - /* actual code inlining: */ - slang_operation_copy(inlined, fun->body); - - /*** XXX review this */ - assert(inlined->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE || - inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE); - inlined->type = SLANG_OPER_BLOCK_NEW_SCOPE; - -#if 0 - printf("======================= orig body code ======================\n"); - printf("=== params scope = %p\n", (void*) fun->parameters); - slang_print_tree(fun->body, 8); - printf("======================= copied code =========================\n"); - slang_print_tree(inlined, 8); -#endif - - /* do parameter substitution in inlined code: */ - slang_substitute(A, inlined, substCount, substOld, substNew, GL_FALSE); - -#if 0 - printf("======================= subst code ==========================\n"); - slang_print_tree(inlined, 8); - printf("=============================================================\n"); -#endif - - /* New prolog statements: (inserted before the inlined code) - * Copy the 'in' arguments. - */ - numCopyIn = 0; - for (i = 0; i < numArgs; i++) { - if (paramMode[i] == COPY_IN) { - slang_variable *p = fun->parameters->variables[i]; - /* declare parameter 'p' */ - slang_operation *decl = slang_operation_insert(&inlined->num_children, - &inlined->children, - numCopyIn); - - decl->type = SLANG_OPER_VARIABLE_DECL; - assert(decl->locals); - decl->locals->outer_scope = inlined->locals; - decl->a_id = p->a_name; - decl->num_children = 1; - decl->children = slang_operation_new(1); - - /* child[0] is the var's initializer */ - slang_operation_copy(&decl->children[0], args + i); - - /* add parameter 'p' to the local variable scope here */ - { - slang_variable *pCopy = slang_variable_scope_grow(inlined->locals); - pCopy->type = p->type; - pCopy->a_name = p->a_name; - pCopy->array_len = p->array_len; - } - - newScope = inlined->locals; - numCopyIn++; - } - } - - /* Now add copies of the function's local vars to the new variable scope */ - for (i = totalArgs; i < fun->parameters->num_variables; i++) { - slang_variable *p = fun->parameters->variables[i]; - slang_variable *pCopy = slang_variable_scope_grow(inlined->locals); - pCopy->type = p->type; - pCopy->a_name = p->a_name; - pCopy->array_len = p->array_len; - } - - - /* New epilog statements: - * 1. Create end of function label to jump to from return statements. - * 2. Copy the 'out' parameter vars - */ - { - slang_operation *lab = slang_operation_insert(&inlined->num_children, - &inlined->children, - inlined->num_children); - lab->type = SLANG_OPER_LABEL; - lab->label = A->curFuncEndLabel; - } - - for (i = 0; i < totalArgs; i++) { - if (paramMode[i] == COPY_OUT) { - const slang_variable *p = fun->parameters->variables[i]; - /* actualCallVar = outParam */ - /*if (i > 0 || !haveRetValue)*/ - slang_operation *ass = slang_operation_insert(&inlined->num_children, - &inlined->children, - inlined->num_children); - ass->type = SLANG_OPER_ASSIGN; - ass->num_children = 2; - ass->locals->outer_scope = inlined->locals; - ass->children = slang_operation_new(2); - ass->children[0] = args[i]; /*XXX copy */ - ass->children[1].type = SLANG_OPER_IDENTIFIER; - ass->children[1].a_id = p->a_name; - ass->children[1].locals->outer_scope = ass->locals; - } - } - - _slang_free(paramMode); - _slang_free(substOld); - _slang_free(substNew); - - /* Update scoping to use the new local vars instead of the - * original function's vars. This is especially important - * for nested inlining. - */ - if (newScope) - slang_replace_scope(inlined, fun->parameters, newScope); - -#if 0 - printf("Done Inline call to %s (total vars=%d nparams=%d)\n\n", - (char *) fun->header.a_name, - fun->parameters->num_variables, numArgs); - slang_print_tree(top, 0); -#endif - - /* pop */ - A->CurFunction = prevFunction; - - return top; -} - - -/** - * Insert declaration for "bool __notRetFlag" in given block operation. - * This is used when we can't emit "early" return statements in subroutines. - */ -static void -declare_return_flag(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_operation *decl; - - assert(oper->type == SLANG_OPER_BLOCK_NEW_SCOPE || - oper->type == SLANG_OPER_SEQUENCE); - - decl = slang_operation_insert_child(oper, 1); - - slang_generate_declaration(A, oper->locals, decl, - SLANG_SPEC_BOOL, "__notRetFlag", GL_TRUE); - - /*slang_print_tree(oper, 0);*/ -} - - -/** - * Recursively replace instances of the old node type with the new type. - */ -static void -replace_node_type(slang_operation *oper, slang_operation_type oldType, - slang_operation_type newType) -{ - GLuint i; - - if (oper->type == oldType) - oper->type = newType; - - for (i = 0; i < slang_oper_num_children(oper); i++) { - replace_node_type(slang_oper_child(oper, i), oldType, newType); - } -} - - - -/** - * Test if the given function body has an "early return". That is, there's - * a 'return' statement that's not the very last instruction in the body. - */ -static GLboolean -has_early_return(const slang_operation *funcBody) -{ - GLuint retCount = _slang_count_node_type(funcBody, SLANG_OPER_RETURN); - if (retCount == 0) - return GL_FALSE; - else if (retCount == 1 && _slang_is_tail_return(funcBody)) - return GL_FALSE; - else - return GL_TRUE; -} - - -/** - * Emit IR code for a function call. This does one of two things: - * 1. Inline the function's code - * 2. Create an IR for the function's body and create a real call to it. - */ -static slang_ir_node * -_slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, - slang_operation *oper, slang_operation *dest) -{ - slang_ir_node *n; - slang_operation *instance; - slang_label *prevFuncEndLabel; - char name[200]; - - prevFuncEndLabel = A->curFuncEndLabel; - _mesa_snprintf(name, sizeof(name), "__endOfFunc_%s_", (char *) fun->header.a_name); - A->curFuncEndLabel = _slang_label_new(name); - assert(A->curFuncEndLabel); - - /* - * 'instance' is basically a copy of the function's body with various - * transformations. - */ - - if (slang_is_asm_function(fun) && !dest) { - /* assemble assembly function - tree style */ - instance = slang_inline_asm_function(A, fun, oper); - } - else { - /* non-assembly function */ - /* We always generate an "inline-able" block of code here. - * We may either: - * 1. insert the inline code - * 2. Generate a call to the "inline" code as a subroutine - */ - const GLboolean earlyReturn = has_early_return(fun->body); - - if (earlyReturn && !A->EmitContReturn) { - A->UseReturnFlag = GL_TRUE; - } - - instance = slang_inline_function_call(A, fun, oper, dest); - if (!instance) - return NULL; - - if (earlyReturn) { - /* The function we're calling has one or more 'return' statements - * that prevent us from inlining the function's code. - * - * In this case, change the function's body type from - * SLANG_OPER_BLOCK_NEW_SCOPE to SLANG_OPER_NON_INLINED_CALL. - * During code emit this will result in a true subroutine call. - * - * Also, convert SLANG_OPER_RETURN_INLINED nodes to SLANG_OPER_RETURN. - */ - slang_operation *callOper; - - assert(instance->type == SLANG_OPER_BLOCK_NEW_SCOPE || - instance->type == SLANG_OPER_SEQUENCE); - - if (_slang_function_has_return_value(fun) && !dest) { - assert(instance->children[0].type == SLANG_OPER_VARIABLE_DECL); - assert(instance->children[2].type == SLANG_OPER_IDENTIFIER); - callOper = &instance->children[1]; - } - else { - callOper = instance; - } - - if (A->UseReturnFlag) { - /* Early returns not supported. Create a _returnFlag variable - * that's set upon 'return' and tested elsewhere to no-op any - * remaining instructions in the subroutine. - */ - assert(callOper->type == SLANG_OPER_BLOCK_NEW_SCOPE || - callOper->type == SLANG_OPER_SEQUENCE); - declare_return_flag(A, callOper); - } - else { - /* We can emit real 'return' statements. If we generated any - * 'inline return' statements during function instantiation, - * change them back to regular 'return' statements. - */ - replace_node_type(instance, SLANG_OPER_RETURN_INLINED, - SLANG_OPER_RETURN); - } - - callOper->type = SLANG_OPER_NON_INLINED_CALL; - callOper->fun = fun; - callOper->label = _slang_label_new_unique((char*) fun->header.a_name); - } - else { - /* If there are any 'return' statements remaining, they're at the - * very end of the function and can effectively become no-ops. - */ - replace_node_type(instance, SLANG_OPER_RETURN_INLINED, - SLANG_OPER_VOID); - } - } - - if (!instance) - return NULL; - - /* Replace the function call with the instance block (or new CALL stmt) */ - slang_operation_destruct(oper); - *oper = *instance; - _slang_free(instance); - -#if 0 - assert(instance->locals); - printf("*** Inlined code for call to %s:\n", (char*) fun->header.a_name); - slang_print_tree(oper, 10); - printf("\n"); -#endif - - n = _slang_gen_operation(A, oper); - - /*_slang_label_delete(A->curFuncEndLabel);*/ - A->curFuncEndLabel = prevFuncEndLabel; - - if (A->pragmas->Debug) { - char s[1000]; - _mesa_snprintf(s, sizeof(s), "Call/inline %s()", (char *) fun->header.a_name); - n->Comment = _slang_strdup(s); - } - - A->UseReturnFlag = GL_FALSE; - - return n; -} - - -static slang_asm_info * -slang_find_asm_info(const char *name) -{ - GLuint i; - for (i = 0; AsmInfo[i].Name; i++) { - if (strcmp(AsmInfo[i].Name, name) == 0) { - return AsmInfo + i; - } - } - return NULL; -} - - -/** - * Some write-masked assignments are simple, but others are hard. - * Simple example: - * vec3 v; - * v.xy = vec2(a, b); - * Hard example: - * vec3 v; - * v.zy = vec2(a, b); - * this gets transformed/swizzled into: - * v.zy = vec2(a, b).*yx* (* = don't care) - * This function helps to determine simple vs. non-simple. - */ -static GLboolean -_slang_simple_writemask(GLuint writemask, GLuint swizzle) -{ - switch (writemask) { - case WRITEMASK_X: - return GET_SWZ(swizzle, 0) == SWIZZLE_X; - case WRITEMASK_Y: - return GET_SWZ(swizzle, 1) == SWIZZLE_Y; - case WRITEMASK_Z: - return GET_SWZ(swizzle, 2) == SWIZZLE_Z; - case WRITEMASK_W: - return GET_SWZ(swizzle, 3) == SWIZZLE_W; - case WRITEMASK_XY: - return (GET_SWZ(swizzle, 0) == SWIZZLE_X) - && (GET_SWZ(swizzle, 1) == SWIZZLE_Y); - case WRITEMASK_XYZ: - return (GET_SWZ(swizzle, 0) == SWIZZLE_X) - && (GET_SWZ(swizzle, 1) == SWIZZLE_Y) - && (GET_SWZ(swizzle, 2) == SWIZZLE_Z); - case WRITEMASK_XYZW: - return swizzle == SWIZZLE_NOOP; - default: - return GL_FALSE; - } -} - - -/** - * Convert the given swizzle into a writemask. In some cases this - * is trivial, in other cases, we'll need to also swizzle the right - * hand side to put components in the right places. - * See comment above for more info. - * XXX this function could be simplified and should probably be renamed. - * \param swizzle the incoming swizzle - * \param writemaskOut returns the writemask - * \param swizzleOut swizzle to apply to the right-hand-side - * \return GL_FALSE for simple writemasks, GL_TRUE for non-simple - */ -static GLboolean -swizzle_to_writemask(slang_assemble_ctx *A, GLuint swizzle, - GLuint *writemaskOut, GLuint *swizzleOut) -{ - GLuint mask = 0x0, newSwizzle[4]; - GLint i, size; - - /* make new dst writemask, compute size */ - for (i = 0; i < 4; i++) { - const GLuint swz = GET_SWZ(swizzle, i); - if (swz == SWIZZLE_NIL) { - /* end */ - break; - } - assert(swz <= 3); - - if (swizzle != SWIZZLE_XXXX && - swizzle != SWIZZLE_YYYY && - swizzle != SWIZZLE_ZZZZ && - swizzle != SWIZZLE_WWWW && - (mask & (1 << swz))) { - /* a channel can't be specified twice (ex: ".xyyz") */ - slang_info_log_error(A->log, "Invalid writemask '%s'", - _mesa_swizzle_string(swizzle, 0, 0)); - return GL_FALSE; - } - - mask |= (1 << swz); - } - assert(mask <= 0xf); - size = i; /* number of components in mask/swizzle */ - - *writemaskOut = mask; - - /* make new src swizzle, by inversion */ - for (i = 0; i < 4; i++) { - newSwizzle[i] = i; /*identity*/ - } - for (i = 0; i < size; i++) { - const GLuint swz = GET_SWZ(swizzle, i); - newSwizzle[swz] = i; - } - *swizzleOut = MAKE_SWIZZLE4(newSwizzle[0], - newSwizzle[1], - newSwizzle[2], - newSwizzle[3]); - - if (_slang_simple_writemask(mask, *swizzleOut)) { - if (size >= 1) - assert(GET_SWZ(*swizzleOut, 0) == SWIZZLE_X); - if (size >= 2) - assert(GET_SWZ(*swizzleOut, 1) == SWIZZLE_Y); - if (size >= 3) - assert(GET_SWZ(*swizzleOut, 2) == SWIZZLE_Z); - if (size >= 4) - assert(GET_SWZ(*swizzleOut, 3) == SWIZZLE_W); - return GL_TRUE; - } - else - return GL_FALSE; -} - - -#if 0 /* not used, but don't remove just yet */ -/** - * Recursively traverse 'oper' to produce a swizzle mask in the event - * of any vector subscripts and swizzle suffixes. - * Ex: for "vec4 v", "v[2].x" resolves to v.z - */ -static GLuint -resolve_swizzle(const slang_operation *oper) -{ - if (oper->type == SLANG_OPER_FIELD) { - /* writemask from .xyzw suffix */ - slang_swizzle swz; - if (_slang_is_swizzle((char*) oper->a_id, 4, &swz)) { - GLuint swizzle = MAKE_SWIZZLE4(swz.swizzle[0], - swz.swizzle[1], - swz.swizzle[2], - swz.swizzle[3]); - GLuint child_swizzle = resolve_swizzle(&oper->children[0]); - GLuint s = _slang_swizzle_swizzle(child_swizzle, swizzle); - return s; - } - else - return SWIZZLE_XYZW; - } - else if (oper->type == SLANG_OPER_SUBSCRIPT && - oper->children[1].type == SLANG_OPER_LITERAL_INT) { - /* writemask from [index] */ - GLuint child_swizzle = resolve_swizzle(&oper->children[0]); - GLuint i = (GLuint) oper->children[1].literal[0]; - GLuint swizzle; - GLuint s; - switch (i) { - case 0: - swizzle = SWIZZLE_XXXX; - break; - case 1: - swizzle = SWIZZLE_YYYY; - break; - case 2: - swizzle = SWIZZLE_ZZZZ; - break; - case 3: - swizzle = SWIZZLE_WWWW; - break; - default: - swizzle = SWIZZLE_XYZW; - } - s = _slang_swizzle_swizzle(child_swizzle, swizzle); - return s; - } - else { - return SWIZZLE_XYZW; - } -} -#endif - - -#if 0 -/** - * Recursively descend through swizzle nodes to find the node's storage info. - */ -static slang_ir_storage * -get_store(const slang_ir_node *n) -{ - if (n->Opcode == IR_SWIZZLE) { - return get_store(n->Children[0]); - } - return n->Store; -} -#endif - - -/** - * Generate IR tree for an asm instruction/operation such as: - * __asm vec4_dot __retVal.x, v1, v2; - */ -static slang_ir_node * -_slang_gen_asm(slang_assemble_ctx *A, slang_operation *oper, - slang_operation *dest) -{ - const slang_asm_info *info; - slang_ir_node *kids[3], *n; - GLuint j, firstOperand; - - assert(oper->type == SLANG_OPER_ASM); - - info = slang_find_asm_info((char *) oper->a_id); - if (!info) { - _mesa_problem(NULL, "undefined __asm function %s\n", - (char *) oper->a_id); - assert(info); - return NULL; - } - assert(info->NumParams <= 3); - - if (info->NumParams == oper->num_children) { - /* Storage for result is not specified. - * Children[0], [1], [2] are the operands. - */ - firstOperand = 0; - } - else { - /* Storage for result (child[0]) is specified. - * Children[1], [2], [3] are the operands. - */ - firstOperand = 1; - } - - /* assemble child(ren) */ - kids[0] = kids[1] = kids[2] = NULL; - for (j = 0; j < info->NumParams; j++) { - kids[j] = _slang_gen_operation(A, &oper->children[firstOperand + j]); - if (!kids[j]) - return NULL; - } - - n = new_node3(info->Opcode, kids[0], kids[1], kids[2]); - - if (firstOperand) { - /* Setup n->Store to be a particular location. Otherwise, storage - * for the result (a temporary) will be allocated later. - */ - slang_operation *dest_oper; - slang_ir_node *n0; - - dest_oper = &oper->children[0]; - - n0 = _slang_gen_operation(A, dest_oper); - if (!n0) - return NULL; - - assert(!n->Store); - n->Store = n0->Store; - - assert(n->Store->File != PROGRAM_UNDEFINED || n->Store->Parent); - - _slang_free(n0); - } - - return n; -} - - -#if 0 -static void -print_funcs(struct slang_function_scope_ *scope, const char *name) -{ - GLuint i; - for (i = 0; i < scope->num_functions; i++) { - slang_function *f = &scope->functions[i]; - if (!name || strcmp(name, (char*) f->header.a_name) == 0) - printf(" %s (%d args)\n", name, f->param_count); - - } - if (scope->outer_scope) - print_funcs(scope->outer_scope, name); -} -#endif - - -/** - * Find a function of the given name, taking 'numArgs' arguments. - * This is the function we'll try to call when there is no exact match - * between function parameters and call arguments. - * - * XXX we should really create a list of candidate functions and try - * all of them... - */ -static slang_function * -_slang_find_function_by_argc(slang_function_scope *scope, - const char *name, int numArgs) -{ - while (scope) { - GLuint i; - for (i = 0; i < scope->num_functions; i++) { - slang_function *f = &scope->functions[i]; - if (strcmp(name, (char*) f->header.a_name) == 0) { - int haveRetValue = _slang_function_has_return_value(f); - if (numArgs == f->param_count - haveRetValue) - return f; - } - } - scope = scope->outer_scope; - } - - return NULL; -} - - -static slang_function * -_slang_find_function_by_max_argc(slang_function_scope *scope, - const char *name) -{ - slang_function *maxFunc = NULL; - GLuint maxArgs = 0; - - while (scope) { - GLuint i; - for (i = 0; i < scope->num_functions; i++) { - slang_function *f = &scope->functions[i]; - if (strcmp(name, (char*) f->header.a_name) == 0) { - if (f->param_count > maxArgs) { - maxArgs = f->param_count; - maxFunc = f; - } - } - } - scope = scope->outer_scope; - } - - return maxFunc; -} - - -/** - * Generate a new slang_function which is a constructor for a user-defined - * struct type. - */ -static slang_function * -_slang_make_struct_constructor(slang_assemble_ctx *A, slang_struct *str) -{ - const GLint numFields = str->fields->num_variables; - slang_function *fun = slang_function_new(SLANG_FUNC_CONSTRUCTOR); - - /* function header (name, return type) */ - fun->header.a_name = str->a_name; - fun->header.type.qualifier = SLANG_QUAL_NONE; - fun->header.type.specifier.type = SLANG_SPEC_STRUCT; - fun->header.type.specifier._struct = str; - - /* function parameters (= struct's fields) */ - { - GLint i; - for (i = 0; i < numFields; i++) { - /* - printf("Field %d: %s\n", i, (char*) str->fields->variables[i]->a_name); - */ - slang_variable *p = slang_variable_scope_grow(fun->parameters); - *p = *str->fields->variables[i]; /* copy the variable and type */ - p->type.qualifier = SLANG_QUAL_CONST; - } - fun->param_count = fun->parameters->num_variables; - } - - /* Add __retVal to params */ - { - slang_variable *p = slang_variable_scope_grow(fun->parameters); - slang_atom a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); - assert(a_retVal); - p->a_name = a_retVal; - p->type = fun->header.type; - p->type.qualifier = SLANG_QUAL_OUT; - fun->param_count++; - } - - /* function body is: - * block: - * declare T; - * T.f1 = p1; - * T.f2 = p2; - * ... - * T.fn = pn; - * return T; - */ - { - slang_variable_scope *scope; - slang_variable *var; - GLint i; - - fun->body = slang_operation_new(1); - fun->body->type = SLANG_OPER_BLOCK_NEW_SCOPE; - fun->body->num_children = numFields + 2; - fun->body->children = slang_operation_new(numFields + 2); - - scope = fun->body->locals; - scope->outer_scope = fun->parameters; - - /* create local var 't' */ - var = slang_variable_scope_grow(scope); - var->a_name = slang_atom_pool_atom(A->atoms, "t"); - var->type = fun->header.type; - - /* declare t */ - { - slang_operation *decl; - - decl = &fun->body->children[0]; - decl->type = SLANG_OPER_VARIABLE_DECL; - decl->locals = _slang_variable_scope_new(scope); - decl->a_id = var->a_name; - } - - /* assign params to fields of t */ - for (i = 0; i < numFields; i++) { - slang_operation *assign = &fun->body->children[1 + i]; - - assign->type = SLANG_OPER_ASSIGN; - assign->locals = _slang_variable_scope_new(scope); - assign->num_children = 2; - assign->children = slang_operation_new(2); - - { - slang_operation *lhs = &assign->children[0]; - - lhs->type = SLANG_OPER_FIELD; - lhs->locals = _slang_variable_scope_new(scope); - lhs->num_children = 1; - lhs->children = slang_operation_new(1); - lhs->a_id = str->fields->variables[i]->a_name; - - lhs->children[0].type = SLANG_OPER_IDENTIFIER; - lhs->children[0].a_id = var->a_name; - lhs->children[0].locals = _slang_variable_scope_new(scope); - -#if 0 - lhs->children[1].num_children = 1; - lhs->children[1].children = slang_operation_new(1); - lhs->children[1].children[0].type = SLANG_OPER_IDENTIFIER; - lhs->children[1].children[0].a_id = str->fields->variables[i]->a_name; - lhs->children[1].children->locals = _slang_variable_scope_new(scope); -#endif - } - - { - slang_operation *rhs = &assign->children[1]; - - rhs->type = SLANG_OPER_IDENTIFIER; - rhs->locals = _slang_variable_scope_new(scope); - rhs->a_id = str->fields->variables[i]->a_name; - } - } - - /* return t; */ - { - slang_operation *ret = &fun->body->children[numFields + 1]; - - ret->type = SLANG_OPER_RETURN; - ret->locals = _slang_variable_scope_new(scope); - ret->num_children = 1; - ret->children = slang_operation_new(1); - ret->children[0].type = SLANG_OPER_IDENTIFIER; - ret->children[0].a_id = var->a_name; - ret->children[0].locals = _slang_variable_scope_new(scope); - } - } - /* - slang_print_function(fun, 1); - */ - return fun; -} - - -/** - * Find/create a function (constructor) for the given structure name. - */ -static slang_function * -_slang_locate_struct_constructor(slang_assemble_ctx *A, const char *name) -{ - unsigned int i; - for (i = 0; i < A->space.structs->num_structs; i++) { - slang_struct *str = &A->space.structs->structs[i]; - if (strcmp(name, (const char *) str->a_name) == 0) { - /* found a structure type that matches the function name */ - if (!str->constructor) { - /* create the constructor function now */ - str->constructor = _slang_make_struct_constructor(A, str); - } - return str->constructor; - } - } - return NULL; -} - - -/** - * Generate a new slang_function to satisfy a call to an array constructor. - * Ex: float[3](1., 2., 3.) - */ -static slang_function * -_slang_make_array_constructor(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_type_specifier_type baseType; - slang_function *fun; - int num_elements; - - fun = slang_function_new(SLANG_FUNC_CONSTRUCTOR); - if (!fun) - return NULL; - - baseType = slang_type_specifier_type_from_string((char *) oper->a_id); - - num_elements = oper->num_children; - - /* function header, return type */ - { - fun->header.a_name = oper->a_id; - fun->header.type.qualifier = SLANG_QUAL_NONE; - fun->header.type.specifier.type = SLANG_SPEC_ARRAY; - fun->header.type.specifier._array = - slang_type_specifier_new(baseType, NULL, NULL); - fun->header.type.array_len = num_elements; - } - - /* function parameters (= number of elements) */ - { - GLint i; - for (i = 0; i < num_elements; i++) { - /* - printf("Field %d: %s\n", i, (char*) str->fields->variables[i]->a_name); - */ - slang_variable *p = slang_variable_scope_grow(fun->parameters); - char name[10]; - _mesa_snprintf(name, sizeof(name), "p%d", i); - p->a_name = slang_atom_pool_atom(A->atoms, name); - p->type.qualifier = SLANG_QUAL_CONST; - p->type.specifier.type = baseType; - } - fun->param_count = fun->parameters->num_variables; - } - - /* Add __retVal to params */ - { - slang_variable *p = slang_variable_scope_grow(fun->parameters); - slang_atom a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); - assert(a_retVal); - p->a_name = a_retVal; - p->type = fun->header.type; - p->type.qualifier = SLANG_QUAL_OUT; - p->type.specifier.type = baseType; - fun->param_count++; - } - - /* function body is: - * block: - * declare T; - * T[0] = p0; - * T[1] = p1; - * ... - * T[n] = pn; - * return T; - */ - { - slang_variable_scope *scope; - slang_variable *var; - GLint i; - - fun->body = slang_operation_new(1); - fun->body->type = SLANG_OPER_BLOCK_NEW_SCOPE; - fun->body->num_children = num_elements + 2; - fun->body->children = slang_operation_new(num_elements + 2); - - scope = fun->body->locals; - scope->outer_scope = fun->parameters; - - /* create local var 't' */ - var = slang_variable_scope_grow(scope); - var->a_name = slang_atom_pool_atom(A->atoms, "ttt"); - var->type = fun->header.type;/*XXX copy*/ - - /* declare t */ - { - slang_operation *decl; - - decl = &fun->body->children[0]; - decl->type = SLANG_OPER_VARIABLE_DECL; - decl->locals = _slang_variable_scope_new(scope); - decl->a_id = var->a_name; - } - - /* assign params to elements of t */ - for (i = 0; i < num_elements; i++) { - slang_operation *assign = &fun->body->children[1 + i]; - - assign->type = SLANG_OPER_ASSIGN; - assign->locals = _slang_variable_scope_new(scope); - assign->num_children = 2; - assign->children = slang_operation_new(2); - - { - slang_operation *lhs = &assign->children[0]; - - lhs->type = SLANG_OPER_SUBSCRIPT; - lhs->locals = _slang_variable_scope_new(scope); - lhs->num_children = 2; - lhs->children = slang_operation_new(2); - - lhs->children[0].type = SLANG_OPER_IDENTIFIER; - lhs->children[0].a_id = var->a_name; - lhs->children[0].locals = _slang_variable_scope_new(scope); - - lhs->children[1].type = SLANG_OPER_LITERAL_INT; - lhs->children[1].literal[0] = (GLfloat) i; - } - - { - slang_operation *rhs = &assign->children[1]; - - rhs->type = SLANG_OPER_IDENTIFIER; - rhs->locals = _slang_variable_scope_new(scope); - rhs->a_id = fun->parameters->variables[i]->a_name; - } - } - - /* return t; */ - { - slang_operation *ret = &fun->body->children[num_elements + 1]; - - ret->type = SLANG_OPER_RETURN; - ret->locals = _slang_variable_scope_new(scope); - ret->num_children = 1; - ret->children = slang_operation_new(1); - ret->children[0].type = SLANG_OPER_IDENTIFIER; - ret->children[0].a_id = var->a_name; - ret->children[0].locals = _slang_variable_scope_new(scope); - } - } - - /* - slang_print_function(fun, 1); - */ - - return fun; -} - - -static GLboolean -_slang_is_vec_mat_type(const char *name) -{ - static const char *vecmat_types[] = { - "float", "int", "bool", - "vec2", "vec3", "vec4", - "ivec2", "ivec3", "ivec4", - "bvec2", "bvec3", "bvec4", - "mat2", "mat3", "mat4", - "mat2x3", "mat2x4", "mat3x2", "mat3x4", "mat4x2", "mat4x3", - NULL - }; - int i; - for (i = 0; vecmat_types[i]; i++) - if (strcmp(name, vecmat_types[i]) == 0) - return GL_TRUE; - return GL_FALSE; -} - - -/** - * Assemble a function call, given a particular function name. - * \param name the function's name (operators like '*' are possible). - */ -static slang_ir_node * -_slang_gen_function_call_name(slang_assemble_ctx *A, const char *name, - slang_operation *oper, slang_operation *dest) -{ - slang_operation *params = oper->children; - const GLuint param_count = oper->num_children; - slang_atom atom; - slang_function *fun; - slang_ir_node *n; - - atom = slang_atom_pool_atom(A->atoms, name); - if (atom == SLANG_ATOM_NULL) - return NULL; - - if (oper->array_constructor) { - /* this needs special handling */ - fun = _slang_make_array_constructor(A, oper); - } - else { - /* Try to find function by name and exact argument type matching */ - GLboolean error = GL_FALSE; - fun = _slang_function_locate(A->space.funcs, atom, params, param_count, - &A->space, A->atoms, A->log, &error); - if (error) { - slang_info_log_error(A->log, - "Function '%s' not found (check argument types)", - name); - return NULL; - } - } - - if (!fun) { - /* Next, try locating a constructor function for a user-defined type */ - fun = _slang_locate_struct_constructor(A, name); - } - - /* - * At this point, some heuristics are used to try to find a function - * that matches the calling signature by means of casting or "unrolling" - * of constructors. - */ - - if (!fun && _slang_is_vec_mat_type(name)) { - /* Next, if this call looks like a vec() or mat() constructor call, - * try "unwinding" the args to satisfy a constructor. - */ - fun = _slang_find_function_by_max_argc(A->space.funcs, name); - if (fun) { - if (!_slang_adapt_call(oper, fun, &A->space, A->atoms, A->log)) { - slang_info_log_error(A->log, - "Function '%s' not found (check argument types)", - name); - return NULL; - } - } - } - - if (!fun && _slang_is_vec_mat_type(name)) { - /* Next, try casting args to the types of the formal parameters */ - int numArgs = oper->num_children; - fun = _slang_find_function_by_argc(A->space.funcs, name, numArgs); - if (!fun || !_slang_cast_func_params(oper, fun, &A->space, A->atoms, A->log)) { - slang_info_log_error(A->log, - "Function '%s' not found (check argument types)", - name); - return NULL; - } - assert(fun); - } - - if (!fun) { - slang_info_log_error(A->log, - "Function '%s' not found (check argument types)", - name); - return NULL; - } - - if (!fun->body) { - /* The function body may be in another compilation unit. - * We'll try concatenating the shaders and recompile at link time. - */ - A->UnresolvedRefs = GL_TRUE; - return new_node1(IR_NOP, NULL); - } - - /* type checking to be sure function's return type matches 'dest' type */ - if (dest) { - slang_typeinfo t0; - - slang_typeinfo_construct(&t0); - typeof_operation(A, dest, &t0); - - if (!slang_type_specifier_equal(&t0.spec, &fun->header.type.specifier)) { - slang_info_log_error(A->log, - "Incompatible type returned by call to '%s'", - name); - return NULL; - } - } - - n = _slang_gen_function_call(A, fun, oper, dest); - - if (n && !n->Store && !dest - && fun->header.type.specifier.type != SLANG_SPEC_VOID) { - /* setup n->Store for the result of the function call */ - GLint size = _slang_sizeof_type_specifier(&fun->header.type.specifier); - n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size); - /*printf("Alloc storage for function result, size %d \n", size);*/ - } - - if (oper->array_constructor) { - /* free the temporary array constructor function now */ - slang_function_destruct(fun); - } - - return n; -} - - -static slang_ir_node * -_slang_gen_method_call(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_atom *a_length = slang_atom_pool_atom(A->atoms, "length"); - slang_ir_node *n; - slang_variable *var; - - /* NOTE: In GLSL 1.20, there's only one kind of method - * call: array.length(). Anything else is an error. - */ - if (oper->a_id != a_length) { - slang_info_log_error(A->log, - "Undefined method call '%s'", (char *) oper->a_id); - return NULL; - } - - /* length() takes no arguments */ - if (oper->num_children > 0) { - slang_info_log_error(A->log, "Invalid arguments to length() method"); - return NULL; - } - - /* lookup the object/variable */ - var = _slang_variable_locate(oper->locals, oper->a_obj, GL_TRUE); - if (!var || var->type.specifier.type != SLANG_SPEC_ARRAY) { - slang_info_log_error(A->log, - "Undefined object '%s'", (char *) oper->a_obj); - return NULL; - } - - /* Create a float/literal IR node encoding the array length */ - n = new_node0(IR_FLOAT); - if (n) { - n->Value[0] = (float) _slang_array_length(var); - n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, 1); - } - return n; -} - - -static GLboolean -_slang_is_constant_cond(const slang_operation *oper, GLboolean *value) -{ - if (oper->type == SLANG_OPER_LITERAL_FLOAT || - oper->type == SLANG_OPER_LITERAL_INT || - oper->type == SLANG_OPER_LITERAL_BOOL) { - if (oper->literal[0]) - *value = GL_TRUE; - else - *value = GL_FALSE; - return GL_TRUE; - } - else if (oper->type == SLANG_OPER_EXPRESSION && - oper->num_children == 1) { - return _slang_is_constant_cond(&oper->children[0], value); - } - return GL_FALSE; -} - - -/** - * Test if an operation is a scalar or boolean. - */ -static GLboolean -_slang_is_scalar_or_boolean(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_typeinfo type; - GLint size; - - slang_typeinfo_construct(&type); - typeof_operation(A, oper, &type); - size = _slang_sizeof_type_specifier(&type.spec); - slang_typeinfo_destruct(&type); - return size == 1; -} - - -/** - * Test if an operation is boolean. - */ -static GLboolean -_slang_is_boolean(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_typeinfo type; - GLboolean isBool; - - slang_typeinfo_construct(&type); - typeof_operation(A, oper, &type); - isBool = (type.spec.type == SLANG_SPEC_BOOL); - slang_typeinfo_destruct(&type); - return isBool; -} - - -/** - * Check if a loop contains a 'continue' statement. - * Stop looking if we find a nested loop. - */ -static GLboolean -_slang_loop_contains_continue(const slang_operation *oper) -{ - switch (oper->type) { - case SLANG_OPER_CONTINUE: - return GL_TRUE; - case SLANG_OPER_FOR: - case SLANG_OPER_DO: - case SLANG_OPER_WHILE: - /* stop upon finding a nested loop */ - return GL_FALSE; - default: - /* recurse */ - { - GLuint i; - for (i = 0; i < oper->num_children; i++) { - const slang_operation *child = slang_oper_child_const(oper, i); - if (_slang_loop_contains_continue(child)) - return GL_TRUE; - } - } - return GL_FALSE; - } -} - - -/** - * Check if a loop contains a 'continue' or 'break' statement. - * Stop looking if we find a nested loop. - */ -static GLboolean -_slang_loop_contains_continue_or_break(const slang_operation *oper) -{ - switch (oper->type) { - case SLANG_OPER_CONTINUE: - case SLANG_OPER_BREAK: - return GL_TRUE; - case SLANG_OPER_FOR: - case SLANG_OPER_DO: - case SLANG_OPER_WHILE: - /* stop upon finding a nested loop */ - return GL_FALSE; - default: - /* recurse */ - { - GLuint i; - for (i = 0; i < oper->num_children; i++) { - const slang_operation *child = slang_oper_child_const(oper, i); - if (_slang_loop_contains_continue_or_break(child)) - return GL_TRUE; - } - } - return GL_FALSE; - } -} - - -/** - * Replace 'break' and 'continue' statements inside a do and while loops. - * This is a recursive helper function used by - * _slang_gen_do/while_without_continue(). - */ -static void -replace_break_and_cont(slang_assemble_ctx *A, slang_operation *oper) -{ - switch (oper->type) { - case SLANG_OPER_BREAK: - /* replace 'break' with "_notBreakFlag = false; break" */ - { - slang_operation *block = oper; - block->type = SLANG_OPER_BLOCK_NEW_SCOPE; - slang_operation_add_children(block, 2); - { - slang_operation *assign = slang_oper_child(block, 0); - assign->type = SLANG_OPER_ASSIGN; - slang_operation_add_children(assign, 2); - { - slang_operation *lhs = slang_oper_child(assign, 0); - slang_operation_identifier(lhs, A, "_notBreakFlag"); - } - { - slang_operation *rhs = slang_oper_child(assign, 1); - slang_operation_literal_bool(rhs, GL_FALSE); - } - } - { - slang_operation *brk = slang_oper_child(block, 1); - brk->type = SLANG_OPER_BREAK; - assert(!brk->children); - } - } - break; - case SLANG_OPER_CONTINUE: - /* convert continue into a break */ - oper->type = SLANG_OPER_BREAK; - break; - case SLANG_OPER_FOR: - case SLANG_OPER_DO: - case SLANG_OPER_WHILE: - /* stop upon finding a nested loop */ - break; - default: - /* recurse */ - { - GLuint i; - for (i = 0; i < oper->num_children; i++) { - replace_break_and_cont(A, slang_oper_child(oper, i)); - } - } - } -} - - -/** - * Transform a while-loop so that continue statements are converted to breaks. - * Then do normal IR code generation. - * - * Before: - * - * while (LOOPCOND) { - * A; - * if (IFCOND) - * continue; - * B; - * break; - * C; - * } - * - * After: - * - * { - * bool _notBreakFlag = 1; - * while (_notBreakFlag && LOOPCOND) { - * do { - * A; - * if (IFCOND) { - * break; // was continue - * } - * B; - * _notBreakFlag = 0; // was - * break; // break - * C; - * } while (0) - * } - * } - */ -static slang_ir_node * -_slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_operation *top; - slang_operation *innerBody; - - assert(oper->type == SLANG_OPER_WHILE); - - top = slang_operation_new(1); - top->type = SLANG_OPER_BLOCK_NEW_SCOPE; - top->locals->outer_scope = oper->locals->outer_scope; - slang_operation_add_children(top, 2); - - /* declare: bool _notBreakFlag = true */ - { - slang_operation *condDecl = slang_oper_child(top, 0); - slang_generate_declaration(A, top->locals, condDecl, - SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); - } - - /* build outer while-loop: while (_notBreakFlag && LOOPCOND) { ... } */ - { - slang_operation *outerWhile = slang_oper_child(top, 1); - outerWhile->type = SLANG_OPER_WHILE; - slang_operation_add_children(outerWhile, 2); - - /* _notBreakFlag && LOOPCOND */ - { - slang_operation *cond = slang_oper_child(outerWhile, 0); - cond->type = SLANG_OPER_LOGICALAND; - slang_operation_add_children(cond, 2); - { - slang_operation *notBreak = slang_oper_child(cond, 0); - slang_operation_identifier(notBreak, A, "_notBreakFlag"); - } - { - slang_operation *origCond = slang_oper_child(cond, 1); - slang_operation_copy(origCond, slang_oper_child(oper, 0)); - } - } - - /* inner loop */ - { - slang_operation *innerDo = slang_oper_child(outerWhile, 1); - innerDo->type = SLANG_OPER_DO; - slang_operation_add_children(innerDo, 2); - - /* copy original do-loop body into inner do-loop's body */ - innerBody = slang_oper_child(innerDo, 0); - slang_operation_copy(innerBody, slang_oper_child(oper, 1)); - innerBody->locals->outer_scope = innerDo->locals; - - /* inner do-loop's condition is constant/false */ - { - slang_operation *constFalse = slang_oper_child(innerDo, 1); - slang_operation_literal_bool(constFalse, GL_FALSE); - } - } - } - - /* Finally, in innerBody, - * replace "break" with "_notBreakFlag = 0; break" - * replace "continue" with "break" - */ - replace_break_and_cont(A, innerBody); - - /*slang_print_tree(top, 0);*/ - - return _slang_gen_operation(A, top); - - return NULL; -} - - -/** - * Generate loop code using high-level IR_LOOP instruction - */ -static slang_ir_node * -_slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) -{ - /* - * LOOP: - * BREAK if !expr (child[0]) - * body code (child[1]) - */ - slang_ir_node *loop, *breakIf, *body; - GLboolean isConst, constTrue = GL_FALSE; - - if (!A->EmitContReturn) { - /* We don't want to emit CONT instructions. If this while-loop has - * a continue, translate it away. - */ - if (_slang_loop_contains_continue(slang_oper_child(oper, 1))) { - return _slang_gen_while_without_continue(A, oper); - } - } - - /* type-check expression */ - if (!_slang_is_boolean(A, &oper->children[0])) { - slang_info_log_error(A->log, "scalar/boolean expression expected for 'while'"); - return NULL; - } - - /* Check if loop condition is a constant */ - isConst = _slang_is_constant_cond(&oper->children[0], &constTrue); - - if (isConst && !constTrue) { - /* loop is never executed! */ - return new_node0(IR_NOP); - } - - /* Begin new loop */ - loop = new_loop(NULL); - - /* save loop state */ - push_loop(A, oper, loop); - - if (isConst && constTrue) { - /* while(nonzero constant), no conditional break */ - breakIf = NULL; - } - else { - slang_ir_node *cond - = new_cond(new_not(_slang_gen_operation(A, &oper->children[0]))); - breakIf = new_break_if_true(A, cond); - } - body = _slang_gen_operation(A, &oper->children[1]); - loop->Children[0] = new_seq(breakIf, body); - - /* Do infinite loop detection */ - /* loop->List is head of linked list of break/continue nodes */ - if (!loop->List && isConst && constTrue) { - /* infinite loop detected */ - pop_loop(A); - slang_info_log_error(A->log, "Infinite loop detected!"); - return NULL; - } - - /* restore loop state */ - pop_loop(A); - - return loop; -} - - -/** - * Transform a do-while-loop so that continue statements are converted to breaks. - * Then do normal IR code generation. - * - * Before: - * - * do { - * A; - * if (IFCOND) - * continue; - * B; - * break; - * C; - * } while (LOOPCOND); - * - * After: - * - * { - * bool _notBreakFlag = 1; - * do { - * do { - * A; - * if (IFCOND) { - * break; // was continue - * } - * B; - * _notBreakFlag = 0; // was - * break; // break - * C; - * } while (0) - * } while (_notBreakFlag && LOOPCOND); - * } - */ -static slang_ir_node * -_slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_operation *top; - slang_operation *innerBody; - - assert(oper->type == SLANG_OPER_DO); - - top = slang_operation_new(1); - top->type = SLANG_OPER_BLOCK_NEW_SCOPE; - top->locals->outer_scope = oper->locals->outer_scope; - slang_operation_add_children(top, 2); - - /* declare: bool _notBreakFlag = true */ - { - slang_operation *condDecl = slang_oper_child(top, 0); - slang_generate_declaration(A, top->locals, condDecl, - SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); - } - - /* build outer do-loop: do { ... } while (_notBreakFlag && LOOPCOND) */ - { - slang_operation *outerDo = slang_oper_child(top, 1); - outerDo->type = SLANG_OPER_DO; - slang_operation_add_children(outerDo, 2); - - /* inner do-loop */ - { - slang_operation *innerDo = slang_oper_child(outerDo, 0); - innerDo->type = SLANG_OPER_DO; - slang_operation_add_children(innerDo, 2); - - /* copy original do-loop body into inner do-loop's body */ - innerBody = slang_oper_child(innerDo, 0); - slang_operation_copy(innerBody, slang_oper_child(oper, 0)); - innerBody->locals->outer_scope = innerDo->locals; - - /* inner do-loop's condition is constant/false */ - { - slang_operation *constFalse = slang_oper_child(innerDo, 1); - slang_operation_literal_bool(constFalse, GL_FALSE); - } - } - - /* _notBreakFlag && LOOPCOND */ - { - slang_operation *cond = slang_oper_child(outerDo, 1); - cond->type = SLANG_OPER_LOGICALAND; - slang_operation_add_children(cond, 2); - { - slang_operation *notBreak = slang_oper_child(cond, 0); - slang_operation_identifier(notBreak, A, "_notBreakFlag"); - } - { - slang_operation *origCond = slang_oper_child(cond, 1); - slang_operation_copy(origCond, slang_oper_child(oper, 1)); - } - } - } - - /* Finally, in innerBody, - * replace "break" with "_notBreakFlag = 0; break" - * replace "continue" with "break" - */ - replace_break_and_cont(A, innerBody); - - /*slang_print_tree(top, 0);*/ - - return _slang_gen_operation(A, top); -} - - -/** - * Generate IR tree for a do-while loop using high-level LOOP, IF instructions. - */ -static slang_ir_node * -_slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) -{ - /* - * LOOP: - * body code (child[0]) - * tail code: - * BREAK if !expr (child[1]) - */ - slang_ir_node *loop; - GLboolean isConst, constTrue; - - if (!A->EmitContReturn) { - /* We don't want to emit CONT instructions. If this do-loop has - * a continue, translate it away. - */ - if (_slang_loop_contains_continue(slang_oper_child(oper, 0))) { - return _slang_gen_do_without_continue(A, oper); - } - } - - /* type-check expression */ - if (!_slang_is_boolean(A, &oper->children[1])) { - slang_info_log_error(A->log, "scalar/boolean expression expected for 'do/while'"); - return NULL; - } - - loop = new_loop(NULL); - - /* save loop state */ - push_loop(A, oper, loop); - - /* loop body: */ - loop->Children[0] = _slang_gen_operation(A, &oper->children[0]); - - /* Check if loop condition is a constant */ - isConst = _slang_is_constant_cond(&oper->children[1], &constTrue); - if (isConst && constTrue) { - /* do { } while(1) ==> no conditional break */ - loop->Children[1] = NULL; /* no tail code */ - } - else { - slang_ir_node *cond - = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); - loop->Children[1] = new_break_if_true(A, cond); - } - - /* XXX we should do infinite loop detection, as above */ - - /* restore loop state */ - pop_loop(A); - - return loop; -} - - -/** - * Recursively count the number of operations rooted at 'oper'. - * This gives some kind of indication of the size/complexity of an operation. - */ -static GLuint -sizeof_operation(const slang_operation *oper) -{ - if (oper) { - GLuint count = 1; /* me */ - GLuint i; - for (i = 0; i < oper->num_children; i++) { - count += sizeof_operation(&oper->children[i]); - } - return count; - } - else { - return 0; - } -} - - -/** - * Determine if a for-loop can be unrolled. - * At this time, only a rather narrow class of for loops can be unrolled. - * See code for details. - * When a loop can't be unrolled because it's too large we'll emit a - * message to the log. - */ -static GLboolean -_slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) -{ - GLuint bodySize; - GLint start, end; - const char *varName; - slang_atom varId; - - if (oper->type != SLANG_OPER_FOR) - return GL_FALSE; - - assert(oper->num_children == 4); - - if (_slang_loop_contains_continue_or_break(slang_oper_child_const(oper, 3))) - return GL_FALSE; - - /* children[0] must be either "int i=constant" or "i=constant" */ - if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { - slang_variable *var; - - if (oper->children[0].children[0].type != SLANG_OPER_VARIABLE_DECL) - return GL_FALSE; - - varId = oper->children[0].children[0].a_id; - - var = _slang_variable_locate(oper->children[0].children[0].locals, - varId, GL_TRUE); - if (!var) - return GL_FALSE; - if (!var->initializer) - return GL_FALSE; - if (var->initializer->type != SLANG_OPER_LITERAL_INT) - return GL_FALSE; - start = (GLint) var->initializer->literal[0]; - } - else if (oper->children[0].type == SLANG_OPER_EXPRESSION) { - if (oper->children[0].children[0].type != SLANG_OPER_ASSIGN) - return GL_FALSE; - if (oper->children[0].children[0].children[0].type != SLANG_OPER_IDENTIFIER) - return GL_FALSE; - if (oper->children[0].children[0].children[1].type != SLANG_OPER_LITERAL_INT) - return GL_FALSE; - - varId = oper->children[0].children[0].children[0].a_id; - - start = (GLint) oper->children[0].children[0].children[1].literal[0]; - } - else { - return GL_FALSE; - } - - /* children[1] must be "i<constant" */ - if (oper->children[1].type != SLANG_OPER_EXPRESSION) - return GL_FALSE; - if (oper->children[1].children[0].type != SLANG_OPER_LESS) - return GL_FALSE; - if (oper->children[1].children[0].children[0].type != SLANG_OPER_IDENTIFIER) - return GL_FALSE; - if (oper->children[1].children[0].children[1].type != SLANG_OPER_LITERAL_INT) - return GL_FALSE; - - end = (GLint) oper->children[1].children[0].children[1].literal[0]; - - /* children[2] must be "i++" or "++i" */ - if (oper->children[2].type != SLANG_OPER_POSTINCREMENT && - oper->children[2].type != SLANG_OPER_PREINCREMENT) - return GL_FALSE; - if (oper->children[2].children[0].type != SLANG_OPER_IDENTIFIER) - return GL_FALSE; - - /* make sure the same variable name is used in all places */ - if ((oper->children[1].children[0].children[0].a_id != varId) || - (oper->children[2].children[0].a_id != varId)) - return GL_FALSE; - - varName = (const char *) varId; - - /* children[3], the loop body, can't be too large */ - bodySize = sizeof_operation(&oper->children[3]); - if (bodySize > MAX_FOR_LOOP_UNROLL_BODY_SIZE) { - slang_info_log_print(A->log, - "Note: 'for (%s ... )' body is too large/complex" - " to unroll", - varName); - return GL_FALSE; - } - - if (start >= end) - return GL_FALSE; /* degenerate case */ - - if ((GLuint)(end - start) > MAX_FOR_LOOP_UNROLL_ITERATIONS) { - slang_info_log_print(A->log, - "Note: 'for (%s=%d; %s<%d; ++%s)' is too" - " many iterations to unroll", - varName, start, varName, end, varName); - return GL_FALSE; - } - - if ((end - start) * bodySize > MAX_FOR_LOOP_UNROLL_COMPLEXITY) { - slang_info_log_print(A->log, - "Note: 'for (%s=%d; %s<%d; ++%s)' will generate" - " too much code to unroll", - varName, start, varName, end, varName); - return GL_FALSE; - } - - return GL_TRUE; /* we can unroll the loop */ -} - - -/** - * Unroll a for-loop. - * First we determine the number of iterations to unroll. - * Then for each iteration: - * make a copy of the loop body - * replace instances of the loop variable with the current iteration value - * generate IR code for the body - * \return pointer to generated IR code or NULL if error, out of memory, etc. - */ -static slang_ir_node * -_slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) -{ - GLint start, end, iter; - slang_ir_node *n, *root = NULL; - slang_atom varId; - - if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { - /* for (int i=0; ... */ - slang_variable *var; - - varId = oper->children[0].children[0].a_id; - var = _slang_variable_locate(oper->children[0].children[0].locals, - varId, GL_TRUE); - assert(var); - start = (GLint) var->initializer->literal[0]; - } - else { - /* for (i=0; ... */ - varId = oper->children[0].children[0].children[0].a_id; - start = (GLint) oper->children[0].children[0].children[1].literal[0]; - } - - end = (GLint) oper->children[1].children[0].children[1].literal[0]; - - for (iter = start; iter < end; iter++) { - slang_operation *body; - - /* make a copy of the loop body */ - body = slang_operation_new(1); - if (!body) - return NULL; - - if (!slang_operation_copy(body, &oper->children[3])) - return NULL; - - /* in body, replace instances of 'varId' with literal 'iter' */ - { - slang_variable *oldVar; - slang_operation *newOper; - - oldVar = _slang_variable_locate(oper->locals, varId, GL_TRUE); - if (!oldVar) { - /* undeclared loop variable */ - slang_operation_delete(body); - return NULL; - } - - newOper = slang_operation_new(1); - newOper->type = SLANG_OPER_LITERAL_INT; - newOper->literal_size = 1; - newOper->literal[0] = (GLfloat) iter; - - /* replace instances of the loop variable with newOper */ - slang_substitute(A, body, 1, &oldVar, &newOper, GL_FALSE); - } - - /* do IR codegen for body */ - n = _slang_gen_operation(A, body); - if (!n) - return NULL; - - root = new_seq(root, n); - - slang_operation_delete(body); - } - - return root; -} - - -/** - * Replace 'continue' statement with 'break' inside a for-loop. - * This is a recursive helper function used by _slang_gen_for_without_continue(). - */ -static void -replace_continue_with_break(slang_assemble_ctx *A, slang_operation *oper) -{ - switch (oper->type) { - case SLANG_OPER_CONTINUE: - oper->type = SLANG_OPER_BREAK; - break; - case SLANG_OPER_FOR: - case SLANG_OPER_DO: - case SLANG_OPER_WHILE: - /* stop upon finding a nested loop */ - break; - default: - /* recurse */ - { - GLuint i; - for (i = 0; i < oper->num_children; i++) { - replace_continue_with_break(A, slang_oper_child(oper, i)); - } - } - } -} - - -/** - * Transform a for-loop so that continue statements are converted to breaks. - * Then do normal IR code generation. - * - * Before: - * - * for (INIT; LOOPCOND; INCR) { - * A; - * if (IFCOND) { - * continue; - * } - * B; - * } - * - * After: - * - * { - * bool _condFlag = 1; - * for (INIT; _condFlag; ) { - * for ( ; _condFlag = LOOPCOND; INCR) { - * A; - * if (IFCOND) { - * break; - * } - * B; - * } - * if (_condFlag) - * INCR; - * } - * } - */ -static slang_ir_node * -_slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_operation *top; - slang_operation *outerFor, *innerFor, *init, *cond, *incr; - slang_operation *lhs, *rhs; - - assert(oper->type == SLANG_OPER_FOR); - - top = slang_operation_new(1); - top->type = SLANG_OPER_BLOCK_NEW_SCOPE; - top->locals->outer_scope = oper->locals->outer_scope; - slang_operation_add_children(top, 2); - - /* declare: bool _condFlag = true */ - { - slang_operation *condDecl = slang_oper_child(top, 0); - slang_generate_declaration(A, top->locals, condDecl, - SLANG_SPEC_BOOL, "_condFlag", GL_TRUE); - } - - /* build outer loop: for (INIT; _condFlag; ) { */ - outerFor = slang_oper_child(top, 1); - outerFor->type = SLANG_OPER_FOR; - slang_operation_add_children(outerFor, 4); - - init = slang_oper_child(outerFor, 0); - slang_operation_copy(init, slang_oper_child(oper, 0)); - - cond = slang_oper_child(outerFor, 1); - cond->type = SLANG_OPER_IDENTIFIER; - cond->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); - - incr = slang_oper_child(outerFor, 2); - incr->type = SLANG_OPER_VOID; - - /* body of the outer loop */ - { - slang_operation *block = slang_oper_child(outerFor, 3); - - slang_operation_add_children(block, 2); - block->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; - - /* build inner loop: for ( ; _condFlag = LOOPCOND; INCR) { */ - { - innerFor = slang_oper_child(block, 0); - - /* make copy of orig loop */ - slang_operation_copy(innerFor, oper); - assert(innerFor->type == SLANG_OPER_FOR); - innerFor->locals->outer_scope = block->locals; - - init = slang_oper_child(innerFor, 0); - init->type = SLANG_OPER_VOID; /* leak? */ - - cond = slang_oper_child(innerFor, 1); - slang_operation_destruct(cond); - cond->type = SLANG_OPER_ASSIGN; - cond->locals = _slang_variable_scope_new(innerFor->locals); - slang_operation_add_children(cond, 2); - - lhs = slang_oper_child(cond, 0); - lhs->type = SLANG_OPER_IDENTIFIER; - lhs->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); - - rhs = slang_oper_child(cond, 1); - slang_operation_copy(rhs, slang_oper_child(oper, 1)); - } - - /* if (_condFlag) INCR; */ - { - slang_operation *ifop = slang_oper_child(block, 1); - ifop->type = SLANG_OPER_IF; - slang_operation_add_children(ifop, 2); - - /* re-use cond node build above */ - slang_operation_copy(slang_oper_child(ifop, 0), cond); - - /* incr node from original for-loop operation */ - slang_operation_copy(slang_oper_child(ifop, 1), - slang_oper_child(oper, 2)); - } - - /* finally, replace "continue" with "break" in the inner for-loop */ - replace_continue_with_break(A, slang_oper_child(innerFor, 3)); - } - - return _slang_gen_operation(A, top); -} - - - -/** - * Generate IR for a for-loop. Unrolling will be done when possible. - */ -static slang_ir_node * -_slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) -{ - GLboolean unroll; - - if (!A->EmitContReturn) { - /* We don't want to emit CONT instructions. If this for-loop has - * a continue, translate it away. - */ - if (_slang_loop_contains_continue(slang_oper_child(oper, 3))) { - return _slang_gen_for_without_continue(A, oper); - } - } - - unroll = _slang_can_unroll_for_loop(A, oper); - if (unroll) { - slang_ir_node *code = _slang_unroll_for_loop(A, oper); - if (code) - return code; - } - - assert(oper->type == SLANG_OPER_FOR); - - /* conventional for-loop code generation */ - { - /* - * init code (child[0]) - * LOOP: - * BREAK if !expr (child[1]) - * body code (child[3]) - * tail code: - * incr code (child[2]) // XXX continue here - */ - slang_ir_node *loop, *cond, *breakIf, *body, *init, *incr; - init = _slang_gen_operation(A, &oper->children[0]); - loop = new_loop(NULL); - - /* save loop state */ - push_loop(A, oper, loop); - - cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); - breakIf = new_break_if_true(A, cond); - body = _slang_gen_operation(A, &oper->children[3]); - incr = _slang_gen_operation(A, &oper->children[2]); - - loop->Children[0] = new_seq(breakIf, body); - loop->Children[1] = incr; /* tail code */ - - /* restore loop state */ - pop_loop(A); - - return new_seq(init, loop); - } -} - - -static slang_ir_node * -_slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper) -{ - slang_ir_node *n, *cont, *incr = NULL, *loopNode; - - assert(oper->type == SLANG_OPER_CONTINUE); - loopNode = current_loop_ir(A); - assert(loopNode); - assert(loopNode->Opcode == IR_LOOP); - - cont = new_node0(IR_CONT); - if (cont) { - cont->Parent = loopNode; - /* insert this node at head of linked list of cont/break instructions */ - cont->List = loopNode->List; - loopNode->List = cont; - } - - n = new_seq(incr, cont); - return n; -} - - -/** - * Determine if the given operation is of a specific type. - */ -static GLboolean -is_operation_type(const slang_operation *oper, slang_operation_type type) -{ - if (oper->type == type) - return GL_TRUE; - else if ((oper->type == SLANG_OPER_BLOCK_NEW_SCOPE || - oper->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) && - oper->num_children == 1) - return is_operation_type(&oper->children[0], type); - else - return GL_FALSE; -} - - -/** - * Generate IR tree for an if/then/else conditional using high-level - * IR_IF instruction. - */ -static slang_ir_node * -_slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) -{ - /* - * eval expr (child[0]) - * IF expr THEN - * if-body code - * ELSE - * else-body code - * ENDIF - */ - const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]); - slang_ir_node *ifNode, *cond, *ifBody, *elseBody; - GLboolean isConst, constTrue; - - /* type-check expression */ - if (!_slang_is_boolean(A, &oper->children[0])) { - slang_info_log_error(A->log, "boolean expression expected for 'if'"); - return NULL; - } - - if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) { - slang_info_log_error(A->log, "scalar/boolean expression expected for 'if'"); - return NULL; - } - - isConst = _slang_is_constant_cond(&oper->children[0], &constTrue); - if (isConst) { - if (constTrue) { - /* if (true) ... */ - return _slang_gen_operation(A, &oper->children[1]); - } - else { - /* if (false) ... */ - return _slang_gen_operation(A, &oper->children[2]); - } - } - - cond = _slang_gen_operation(A, &oper->children[0]); - cond = new_cond(cond); - - if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK) - && !haveElseClause) { - /* Special case: generate a conditional break */ - ifBody = new_break_if_true(A, cond); - return ifBody; - } - else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE) - && !haveElseClause - && current_loop_oper(A) - && current_loop_oper(A)->type != SLANG_OPER_FOR) { - /* Special case: generate a conditional continue */ - ifBody = new_cont_if_true(A, cond); - return ifBody; - } - else { - /* general case */ - ifBody = _slang_gen_operation(A, &oper->children[1]); - if (haveElseClause) - elseBody = _slang_gen_operation(A, &oper->children[2]); - else - elseBody = NULL; - ifNode = new_if(cond, ifBody, elseBody); - return ifNode; - } -} - - - -static slang_ir_node * -_slang_gen_not(slang_assemble_ctx * A, const slang_operation *oper) -{ - slang_ir_node *n; - - assert(oper->type == SLANG_OPER_NOT); - - /* type-check expression */ - if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) { - slang_info_log_error(A->log, - "scalar/boolean expression expected for '!'"); - return NULL; - } - - n = _slang_gen_operation(A, &oper->children[0]); - if (n) - return new_not(n); - else - return NULL; -} - - -static slang_ir_node * -_slang_gen_xor(slang_assemble_ctx * A, const slang_operation *oper) -{ - slang_ir_node *n1, *n2; - - assert(oper->type == SLANG_OPER_LOGICALXOR); - - if (!_slang_is_scalar_or_boolean(A, &oper->children[0]) || - !_slang_is_scalar_or_boolean(A, &oper->children[0])) { - slang_info_log_error(A->log, - "scalar/boolean expressions expected for '^^'"); - return NULL; - } - - n1 = _slang_gen_operation(A, &oper->children[0]); - if (!n1) - return NULL; - n2 = _slang_gen_operation(A, &oper->children[1]); - if (!n2) - return NULL; - return new_node2(IR_NOTEQUAL, n1, n2); -} - - -/** - * Generate IR node for storage of a temporary of given size. - */ -static slang_ir_node * -_slang_gen_temporary(GLint size) -{ - slang_ir_storage *store; - slang_ir_node *n = NULL; - - store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -2, size); - if (store) { - n = new_node0(IR_VAR_DECL); - if (n) { - n->Store = store; - } - else { - _slang_free(store); - } - } - return n; -} - - -/** - * Generate program constants for an array. - * Ex: const vec2[3] v = vec2[3](vec2(1,1), vec2(2,2), vec2(3,3)); - * This will allocate and initialize three vector constants, storing - * the array in constant memory, not temporaries like a non-const array. - * This can also be used for uniform array initializers. - * \return GL_TRUE for success, GL_FALSE if failure (semantic error, etc). - */ -static GLboolean -make_constant_array(slang_assemble_ctx *A, - slang_variable *var, - slang_operation *initializer) -{ - struct gl_program *prog = A->program; - const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier); - const char *varName = (char *) var->a_name; - const GLuint numElements = initializer->num_children; - GLint size; - GLuint i, j; - GLfloat *values; - - if (!var->store) { - var->store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -6, -6); - } - size = var->store->Size; - - assert(var->type.qualifier == SLANG_QUAL_CONST || - var->type.qualifier == SLANG_QUAL_UNIFORM); - assert(initializer->type == SLANG_OPER_CALL); - assert(initializer->array_constructor); - - values = (GLfloat *) malloc(numElements * 4 * sizeof(GLfloat)); - - /* convert constructor params into ordinary floats */ - for (i = 0; i < numElements; i++) { - const slang_operation *op = &initializer->children[i]; - if (op->type != SLANG_OPER_LITERAL_FLOAT) { - /* unsupported type for this optimization */ - free(values); - return GL_FALSE; - } - for (j = 0; j < op->literal_size; j++) { - values[i * 4 + j] = op->literal[j]; - } - for ( ; j < 4; j++) { - values[i * 4 + j] = 0.0f; - } - } - - /* slightly different paths for constants vs. uniforms */ - if (var->type.qualifier == SLANG_QUAL_UNIFORM) { - var->store->File = PROGRAM_UNIFORM; - var->store->Index = _mesa_add_uniform(prog->Parameters, varName, - size, datatype, values); - } - else { - var->store->File = PROGRAM_CONSTANT; - var->store->Index = _mesa_add_named_constant(prog->Parameters, varName, - values, size); - } - assert(var->store->Size == size); - - free(values); - - return GL_TRUE; -} - - - -/** - * Generate IR node for allocating/declaring a variable (either a local or - * a global). - * Generally, this involves allocating an slang_ir_storage instance for the - * variable, choosing a register file (temporary, constant, etc). - * For ordinary variables we do not yet allocate storage though. We do that - * when we find the first actual use of the variable to avoid allocating temp - * regs that will never get used. - * At this time, uniforms are always allocated space in this function. - * - * \param initializer Optional initializer expression for the variable. - */ -static slang_ir_node * -_slang_gen_var_decl(slang_assemble_ctx *A, slang_variable *var, - slang_operation *initializer) -{ - const char *varName = (const char *) var->a_name; - const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier); - slang_ir_node *varDecl, *n; - slang_ir_storage *store; - GLint arrayLen, size, totalSize; /* if array then totalSize > size */ - gl_register_file file; - - /*assert(!var->declared);*/ - var->declared = GL_TRUE; - - /* determine GPU register file for simple cases */ - if (is_sampler_type(&var->type)) { - file = PROGRAM_SAMPLER; - } - else if (var->type.qualifier == SLANG_QUAL_UNIFORM) { - file = PROGRAM_UNIFORM; - } - else { - file = PROGRAM_TEMPORARY; - } - - size = _slang_sizeof_type_specifier(&var->type.specifier); - if (size <= 0) { - slang_info_log_error(A->log, "invalid declaration for '%s'", varName); - return NULL; - } - - arrayLen = _slang_array_length(var); - totalSize = _slang_array_size(size, arrayLen); - - /* Allocate IR node for the declaration */ - varDecl = new_node0(IR_VAR_DECL); - if (!varDecl) - return NULL; - - /* Allocate slang_ir_storage for this variable if needed. - * Note that we may not actually allocate a constant or temporary register - * until later. - */ - if (!var->store) { - GLint index = -7; /* TBD / unknown */ - var->store = _slang_new_ir_storage(file, index, totalSize); - if (!var->store) - return NULL; /* out of memory */ - } - - /* set the IR node's Var and Store pointers */ - varDecl->Var = var; - varDecl->Store = var->store; - - - store = var->store; - - /* if there's an initializer, generate IR for the expression */ - if (initializer) { - slang_ir_node *varRef, *init; - - if (var->type.qualifier == SLANG_QUAL_CONST) { - /* if the variable is const, the initializer must be a const - * expression as well. - */ -#if 0 - if (!_slang_is_constant_expr(initializer)) { - slang_info_log_error(A->log, - "initializer for %s not constant", varName); - return NULL; - } -#endif - } - - if (var->type.qualifier == SLANG_QUAL_UNIFORM && - !A->allow_uniform_initializers) { - slang_info_log_error(A->log, - "initializer for uniform %s not allowed", - varName); - return NULL; - } - - /* IR for the variable we're initializing */ - varRef = new_var(A, var); - if (!varRef) { - slang_info_log_error(A->log, "out of memory"); - return NULL; - } - - /* constant-folding, etc here */ - _slang_simplify(initializer, &A->space, A->atoms); - - /* look for simple constant-valued variables and uniforms */ - if (var->type.qualifier == SLANG_QUAL_CONST || - var->type.qualifier == SLANG_QUAL_UNIFORM) { - - if (initializer->type == SLANG_OPER_CALL && - initializer->array_constructor) { - /* array initializer */ - if (make_constant_array(A, var, initializer)) - return varRef; - } - else if (initializer->type == SLANG_OPER_LITERAL_FLOAT || - initializer->type == SLANG_OPER_LITERAL_INT) { - /* simple float/vector initializer */ - if (store->File == PROGRAM_UNIFORM) { - store->Index = _mesa_add_uniform(A->program->Parameters, - varName, - totalSize, datatype, - initializer->literal); - store->Swizzle = _slang_var_swizzle(size, 0); - return varRef; - } -#if 0 - else { - store->File = PROGRAM_CONSTANT; - store->Index = _mesa_add_named_constant(A->program->Parameters, - varName, - initializer->literal, - totalSize); - store->Swizzle = _slang_var_swizzle(size, 0); - return varRef; - } -#endif - } - } - - /* IR for initializer */ - init = _slang_gen_operation(A, initializer); - if (!init) - return NULL; - - /* XXX remove this when type checking is added above */ - if (init->Store && init->Store->Size != totalSize) { - slang_info_log_error(A->log, "invalid assignment (wrong types)"); - return NULL; - } - - /* assign RHS to LHS */ - n = new_node2(IR_COPY, varRef, init); - n = new_seq(varDecl, n); - } - else { - /* no initializer */ - n = varDecl; - } - - if (store->File == PROGRAM_UNIFORM && store->Index < 0) { - /* always need to allocate storage for uniforms at this point */ - store->Index = _mesa_add_uniform(A->program->Parameters, varName, - totalSize, datatype, NULL); - store->Swizzle = _slang_var_swizzle(size, 0); - } - -#if 0 - printf("%s var %p %s store=%p index=%d size=%d\n", - __FUNCTION__, (void *) var, (char *) varName, - (void *) store, store->Index, store->Size); -#endif - - return n; -} - - -/** - * Generate code for a selection expression: b ? x : y - * XXX In some cases we could implement a selection expression - * with an LRP instruction (use the boolean as the interpolant). - * Otherwise, we use an IF/ELSE/ENDIF construct. - */ -static slang_ir_node * -_slang_gen_select(slang_assemble_ctx *A, slang_operation *oper) -{ - slang_ir_node *cond, *ifNode, *trueExpr, *falseExpr, *trueNode, *falseNode; - slang_ir_node *tmpDecl, *tmpVar, *tree; - slang_typeinfo type0, type1, type2; - int size, isBool, isEqual; - - assert(oper->type == SLANG_OPER_SELECT); - assert(oper->num_children == 3); - - /* type of children[0] must be boolean */ - slang_typeinfo_construct(&type0); - typeof_operation(A, &oper->children[0], &type0); - isBool = (type0.spec.type == SLANG_SPEC_BOOL); - slang_typeinfo_destruct(&type0); - if (!isBool) { - slang_info_log_error(A->log, "selector type is not boolean"); - return NULL; - } - - slang_typeinfo_construct(&type1); - slang_typeinfo_construct(&type2); - typeof_operation(A, &oper->children[1], &type1); - typeof_operation(A, &oper->children[2], &type2); - isEqual = slang_type_specifier_equal(&type1.spec, &type2.spec); - slang_typeinfo_destruct(&type1); - slang_typeinfo_destruct(&type2); - if (!isEqual) { - slang_info_log_error(A->log, "incompatible types for ?: operator"); - return NULL; - } - - /* size of x or y's type */ - size = _slang_sizeof_type_specifier(&type1.spec); - assert(size > 0); - - /* temporary var */ - tmpDecl = _slang_gen_temporary(size); - - /* the condition (child 0) */ - cond = _slang_gen_operation(A, &oper->children[0]); - cond = new_cond(cond); - - /* if-true body (child 1) */ - tmpVar = new_node0(IR_VAR); - tmpVar->Store = tmpDecl->Store; - trueExpr = _slang_gen_operation(A, &oper->children[1]); - trueNode = new_node2(IR_COPY, tmpVar, trueExpr); - - /* if-false body (child 2) */ - tmpVar = new_node0(IR_VAR); - tmpVar->Store = tmpDecl->Store; - falseExpr = _slang_gen_operation(A, &oper->children[2]); - falseNode = new_node2(IR_COPY, tmpVar, falseExpr); - - ifNode = new_if(cond, trueNode, falseNode); - - /* tmp var value */ - tmpVar = new_node0(IR_VAR); - tmpVar->Store = tmpDecl->Store; - - tree = new_seq(ifNode, tmpVar); - tree = new_seq(tmpDecl, tree); - - /*_slang_print_ir_tree(tree, 10);*/ - return tree; -} - - -/** - * Generate code for &&. - */ -static slang_ir_node * -_slang_gen_logical_and(slang_assemble_ctx *A, slang_operation *oper) -{ - /* rewrite "a && b" as "a ? b : false" */ - slang_operation *select; - slang_ir_node *n; - - select = slang_operation_new(1); - select->type = SLANG_OPER_SELECT; - slang_operation_add_children(select, 3); - - slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); - slang_operation_copy(slang_oper_child(select, 1), &oper->children[1]); - slang_operation_literal_bool(slang_oper_child(select, 2), GL_FALSE); - - n = _slang_gen_select(A, select); - return n; -} - - -/** - * Generate code for ||. - */ -static slang_ir_node * -_slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper) -{ - /* rewrite "a || b" as "a ? true : b" */ - slang_operation *select; - slang_ir_node *n; - - select = slang_operation_new(1); - select->type = SLANG_OPER_SELECT; - slang_operation_add_children(select, 3); - - slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); - slang_operation_literal_bool(slang_oper_child(select, 1), GL_TRUE); - slang_operation_copy(slang_oper_child(select, 2), &oper->children[1]); - - n = _slang_gen_select(A, select); - return n; -} - - -/** - * Generate IR tree for a return statement. - */ -static slang_ir_node * -_slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) -{ - assert(oper->type == SLANG_OPER_RETURN); - return new_return(A->curFuncEndLabel); -} - - -#if 0 -/** - * Determine if the given operation/expression is const-valued. - */ -static GLboolean -_slang_is_constant_expr(const slang_operation *oper) -{ - slang_variable *var; - GLuint i; - - switch (oper->type) { - case SLANG_OPER_IDENTIFIER: - var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); - if (var && var->type.qualifier == SLANG_QUAL_CONST) - return GL_TRUE; - return GL_FALSE; - default: - for (i = 0; i < oper->num_children; i++) { - if (!_slang_is_constant_expr(&oper->children[i])) - return GL_FALSE; - } - return GL_TRUE; - } -} -#endif - - -/** - * Check if an assignment of type t1 to t0 is legal. - * XXX more cases needed. - */ -static GLboolean -_slang_assignment_compatible(slang_assemble_ctx *A, - slang_operation *op0, - slang_operation *op1) -{ - slang_typeinfo t0, t1; - GLuint sz0, sz1; - - if (op0->type == SLANG_OPER_POSTINCREMENT || - op0->type == SLANG_OPER_POSTDECREMENT) { - return GL_FALSE; - } - - slang_typeinfo_construct(&t0); - typeof_operation(A, op0, &t0); - - slang_typeinfo_construct(&t1); - typeof_operation(A, op1, &t1); - - sz0 = _slang_sizeof_type_specifier(&t0.spec); - sz1 = _slang_sizeof_type_specifier(&t1.spec); - -#if 1 - if (sz0 != sz1) { - /*printf("assignment size mismatch %u vs %u\n", sz0, sz1);*/ - return GL_FALSE; - } -#endif - - if (t0.spec.type == SLANG_SPEC_STRUCT && - t1.spec.type == SLANG_SPEC_STRUCT && - t0.spec._struct->a_name != t1.spec._struct->a_name) - return GL_FALSE; - - if (t0.spec.type == SLANG_SPEC_FLOAT && - t1.spec.type == SLANG_SPEC_BOOL) - return GL_FALSE; - -#if 0 /* not used just yet - causes problems elsewhere */ - if (t0.spec.type == SLANG_SPEC_INT && - t1.spec.type == SLANG_SPEC_FLOAT) - return GL_FALSE; -#endif - - if (t0.spec.type == SLANG_SPEC_BOOL && - t1.spec.type == SLANG_SPEC_FLOAT) - return GL_FALSE; - - if (t0.spec.type == SLANG_SPEC_BOOL && - t1.spec.type == SLANG_SPEC_INT) - return GL_FALSE; - - return GL_TRUE; -} - - -/** - * Generate IR tree for a local variable declaration. - * Basically do some error checking and call _slang_gen_var_decl(). - */ -static slang_ir_node * -_slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper) -{ - const char *varName = (char *) oper->a_id; - slang_variable *var; - slang_ir_node *varDecl; - slang_operation *initializer; - - assert(oper->type == SLANG_OPER_VARIABLE_DECL); - assert(oper->num_children <= 1); - - - /* lookup the variable by name */ - var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); - if (!var) - return NULL; /* "shouldn't happen" */ - - if (var->type.qualifier == SLANG_QUAL_ATTRIBUTE || - var->type.qualifier == SLANG_QUAL_VARYING || - var->type.qualifier == SLANG_QUAL_UNIFORM) { - /* can't declare attribute/uniform vars inside functions */ - slang_info_log_error(A->log, - "local variable '%s' cannot be an attribute/uniform/varying", - varName); - return NULL; - } - -#if 0 - if (v->declared) { - slang_info_log_error(A->log, "variable '%s' redeclared", varName); - return NULL; - } -#endif - - /* check if the var has an initializer */ - if (oper->num_children > 0) { - assert(oper->num_children == 1); - initializer = &oper->children[0]; - } - else if (var->initializer) { - initializer = var->initializer; - } - else { - initializer = NULL; - } - - if (initializer) { - /* check/compare var type and initializer type */ - if (!_slang_assignment_compatible(A, oper, initializer)) { - slang_info_log_error(A->log, "incompatible types in assignment"); - return NULL; - } - } - else { - if (var->type.qualifier == SLANG_QUAL_CONST) { - slang_info_log_error(A->log, - "const-qualified variable '%s' requires initializer", - varName); - return NULL; - } - } - - /* Generate IR node */ - varDecl = _slang_gen_var_decl(A, var, initializer); - if (!varDecl) - return NULL; - - return varDecl; -} - - -/** - * Generate IR tree for a reference to a variable (such as in an expression). - * This is different from a variable declaration. - */ -static slang_ir_node * -_slang_gen_variable(slang_assemble_ctx * A, slang_operation *oper) -{ - /* If there's a variable associated with this oper (from inlining) - * use it. Otherwise, use the oper's var id. - */ - slang_atom name = oper->var ? oper->var->a_name : oper->a_id; - slang_variable *var = _slang_variable_locate(oper->locals, name, GL_TRUE); - slang_ir_node *n; - if (!var || !var->declared) { - /* Geometry shaders set gl_VerticesIn at link time - * so we need to wait with resolving this variable - * until then */ - if (A->program->Target == MESA_GEOMETRY_PROGRAM && - !strcmp((char*)name, "gl_VerticesIn") ){ - A->UnresolvedRefs = GL_TRUE; - return NULL; - } - slang_info_log_error(A->log, "undefined variable '%s'", (char *) name); - return NULL; - } - n = new_var(A, var); - return n; -} - - - -/** - * Return the number of components actually named by the swizzle. - * Recall that swizzles may have undefined/don't-care values. - */ -static GLuint -swizzle_size(GLuint swizzle) -{ - GLuint size = 0, i; - for (i = 0; i < 4; i++) { - GLuint swz = GET_SWZ(swizzle, i); - size += (swz <= 3); - } - return size; -} - - -static slang_ir_node * -_slang_gen_swizzle(slang_ir_node *child, GLuint swizzle) -{ - slang_ir_node *n = new_node1(IR_SWIZZLE, child); - assert(child); - if (n) { - assert(!n->Store); - n->Store = _slang_new_ir_storage_relative(0, - swizzle_size(swizzle), - child->Store); - assert(n->Store); - n->Store->Swizzle = swizzle; - } - return n; -} - - -static GLboolean -is_store_writable(const slang_assemble_ctx *A, const slang_ir_storage *store) -{ - while (store->Parent) - store = store->Parent; - - if (!(store->File == PROGRAM_OUTPUT || - store->File == PROGRAM_TEMPORARY || - (store->File == PROGRAM_VARYING && - (A->program->Target == GL_VERTEX_PROGRAM_ARB || - A->program->Target == MESA_GEOMETRY_PROGRAM)))) { - return GL_FALSE; - } - else { - return GL_TRUE; - } -} - - -/** - * Walk up an IR storage path to compute the final swizzle. - * This is used when we find an expression such as "foo.xz.yx". - */ -static GLuint -root_swizzle(const slang_ir_storage *st) -{ - GLuint swizzle = st->Swizzle; - while (st->Parent) { - st = st->Parent; - swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); - } - return swizzle; -} - - -/** - * Generate IR tree for an assignment (=). - */ -static slang_ir_node * -_slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) -{ - slang_operation *pred = NULL; - slang_ir_node *n = NULL; - - if (oper->children[0].type == SLANG_OPER_IDENTIFIER) { - /* Check that var is writeable */ - const char *varName = (char *) oper->children[0].a_id; - slang_variable *var - = _slang_variable_locate(oper->children[0].locals, - oper->children[0].a_id, GL_TRUE); - if (!var) { - slang_info_log_error(A->log, "undefined variable '%s'", varName); - return NULL; - } - - if (var->type.qualifier == SLANG_QUAL_CONST || - var->type.qualifier == SLANG_QUAL_ATTRIBUTE || - var->type.qualifier == SLANG_QUAL_UNIFORM || - (var->type.qualifier == SLANG_QUAL_VARYING && - A->program->Target == GL_FRAGMENT_PROGRAM_ARB)) { - slang_info_log_error(A->log, - "illegal assignment to read-only variable '%s'", - varName); - return NULL; - } - - /* check if we need to predicate this assignment based on __notRetFlag */ - if ((var->is_global || - var->type.qualifier == SLANG_QUAL_OUT || - var->type.qualifier == SLANG_QUAL_INOUT) && A->UseReturnFlag) { - /* create predicate, used below */ - pred = slang_operation_new(1); - pred->type = SLANG_OPER_IDENTIFIER; - pred->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); - pred->locals->outer_scope = oper->locals->outer_scope; - } - } - - if (oper->children[0].type == SLANG_OPER_IDENTIFIER && - oper->children[1].type == SLANG_OPER_CALL) { - /* Special case of: x = f(a, b) - * Replace with f(a, b, x) (where x == hidden __retVal out param) - * - * XXX this could be even more effective if we could accomodate - * cases such as "v.x = f();" - would help with typical vertex - * transformation. - */ - n = _slang_gen_function_call_name(A, - (const char *) oper->children[1].a_id, - &oper->children[1], &oper->children[0]); - } - else { - slang_ir_node *lhs, *rhs; - - /* lhs and rhs type checking */ - if (!_slang_assignment_compatible(A, - &oper->children[0], - &oper->children[1])) { - slang_info_log_error(A->log, "incompatible types in assignment"); - return NULL; - } - - lhs = _slang_gen_operation(A, &oper->children[0]); - if (!lhs) { - return NULL; - } - - if (!lhs->Store) { - slang_info_log_error(A->log, - "invalid left hand side for assignment"); - return NULL; - } - - /* check that lhs is writable */ - if (!is_store_writable(A, lhs->Store)) { - slang_info_log_error(A->log, - "illegal assignment to read-only l-value"); - return NULL; - } - - rhs = _slang_gen_operation(A, &oper->children[1]); - if (lhs && rhs) { - /* convert lhs swizzle into writemask */ - const GLuint swizzle = root_swizzle(lhs->Store); - GLuint writemask, newSwizzle = 0x0; - if (!swizzle_to_writemask(A, swizzle, &writemask, &newSwizzle)) { - /* Non-simple writemask, need to swizzle right hand side in - * order to put components into the right place. - */ - rhs = _slang_gen_swizzle(rhs, newSwizzle); - } - n = new_node2(IR_COPY, lhs, rhs); - } - else { - return NULL; - } - } - - if (n && pred) { - /* predicate the assignment code on __notRetFlag */ - slang_ir_node *top, *cond; - - cond = _slang_gen_operation(A, pred); - top = new_if(cond, n, NULL); - return top; - } - return n; -} - - -/** - * Generate IR tree for referencing a field in a struct (or basic vector type) - */ -static slang_ir_node * -_slang_gen_struct_field(slang_assemble_ctx * A, slang_operation *oper) -{ - slang_typeinfo ti; - - /* type of struct */ - slang_typeinfo_construct(&ti); - typeof_operation(A, &oper->children[0], &ti); - - if (_slang_type_is_vector(ti.spec.type)) { - /* the field should be a swizzle */ - const GLuint rows = _slang_type_dim(ti.spec.type); - slang_swizzle swz; - slang_ir_node *n; - GLuint swizzle; - if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { - slang_info_log_error(A->log, "Bad swizzle"); - return NULL; - } - swizzle = MAKE_SWIZZLE4(swz.swizzle[0], - swz.swizzle[1], - swz.swizzle[2], - swz.swizzle[3]); - - n = _slang_gen_operation(A, &oper->children[0]); - /* create new parent node with swizzle */ - if (n) - n = _slang_gen_swizzle(n, swizzle); - return n; - } - else if ( ti.spec.type == SLANG_SPEC_FLOAT - || ti.spec.type == SLANG_SPEC_INT - || ti.spec.type == SLANG_SPEC_BOOL) { - const GLuint rows = 1; - slang_swizzle swz; - slang_ir_node *n; - GLuint swizzle; - if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { - slang_info_log_error(A->log, "Bad swizzle"); - } - swizzle = MAKE_SWIZZLE4(swz.swizzle[0], - swz.swizzle[1], - swz.swizzle[2], - swz.swizzle[3]); - n = _slang_gen_operation(A, &oper->children[0]); - /* create new parent node with swizzle */ - n = _slang_gen_swizzle(n, swizzle); - return n; - } - else { - /* the field is a structure member (base.field) */ - /* oper->children[0] is the base */ - /* oper->a_id is the field name */ - slang_ir_node *base, *n; - slang_typeinfo field_ti; - GLint fieldSize, fieldOffset = -1; - - /* type of field */ - slang_typeinfo_construct(&field_ti); - typeof_operation(A, oper, &field_ti); - - fieldSize = _slang_sizeof_type_specifier(&field_ti.spec); - if (fieldSize > 0) - fieldOffset = _slang_field_offset(&ti.spec, oper->a_id); - - if (fieldSize == 0 || fieldOffset < 0) { - const char *structName; - if (ti.spec._struct) - structName = (char *) ti.spec._struct->a_name; - else - structName = "unknown"; - slang_info_log_error(A->log, - "\"%s\" is not a member of struct \"%s\"", - (char *) oper->a_id, structName); - return NULL; - } - assert(fieldSize >= 0); - - base = _slang_gen_operation(A, &oper->children[0]); - if (!base) { - /* error msg should have already been logged */ - return NULL; - } - - n = new_node1(IR_FIELD, base); - if (!n) - return NULL; - - n->Field = (char *) oper->a_id; - - /* Store the field's offset in storage->Index */ - n->Store = _slang_new_ir_storage(base->Store->File, - fieldOffset, - fieldSize); - - return n; - } -} - - -/** - * Gen code for array indexing. - */ -static slang_ir_node * -_slang_gen_array_element(slang_assemble_ctx * A, slang_operation *oper) -{ - slang_typeinfo array_ti; - - /* get array's type info */ - slang_typeinfo_construct(&array_ti); - typeof_operation(A, &oper->children[0], &array_ti); - - if (_slang_type_is_vector(array_ti.spec.type)) { - /* indexing a simple vector type: "vec4 v; v[0]=p;" */ - /* translate the index into a swizzle/writemask: "v.x=p" */ - const GLuint max = _slang_type_dim(array_ti.spec.type); - GLint index; - slang_ir_node *n; - - index = (GLint) oper->children[1].literal[0]; - if (oper->children[1].type != SLANG_OPER_LITERAL_INT || - index >= (GLint) max) { -#if 0 - slang_info_log_error(A->log, "Invalid array index for vector type"); - printf("type = %d\n", oper->children[1].type); - printf("index = %d, max = %d\n", index, max); - printf("array = %s\n", (char*)oper->children[0].a_id); - printf("index = %s\n", (char*)oper->children[1].a_id); - return NULL; -#else - index = 0; -#endif - } - - n = _slang_gen_operation(A, &oper->children[0]); - if (n) { - /* use swizzle to access the element */ - GLuint swizzle = MAKE_SWIZZLE4(SWIZZLE_X + index, - SWIZZLE_NIL, - SWIZZLE_NIL, - SWIZZLE_NIL); - n = _slang_gen_swizzle(n, swizzle); - } - return n; - } - else { - /* conventional array */ - slang_typeinfo elem_ti; - slang_ir_node *elem, *array, *index; - GLint elemSize, arrayLen; - - /* size of array element */ - slang_typeinfo_construct(&elem_ti); - typeof_operation(A, oper, &elem_ti); - elemSize = _slang_sizeof_type_specifier(&elem_ti.spec); - - if (_slang_type_is_matrix(array_ti.spec.type)) - arrayLen = _slang_type_dim(array_ti.spec.type); - else - arrayLen = array_ti.array_len; - - slang_typeinfo_destruct(&array_ti); - slang_typeinfo_destruct(&elem_ti); - - if (elemSize <= 0) { - /* unknown var or type */ - slang_info_log_error(A->log, "Undefined variable or type"); - return NULL; - } - - array = _slang_gen_operation(A, &oper->children[0]); - index = _slang_gen_operation(A, &oper->children[1]); - if (array && index) { - /* bounds check */ - GLint constIndex = -1; - if (index->Opcode == IR_FLOAT) { - constIndex = (int) index->Value[0]; - if (constIndex < 0 || constIndex >= arrayLen) { - slang_info_log_error(A->log, - "Array index out of bounds (index=%d size=%d)", - constIndex, arrayLen); - _slang_free_ir_tree(array); - _slang_free_ir_tree(index); - return NULL; - } - } - - if (!array->Store) { - slang_info_log_error(A->log, "Invalid array"); - return NULL; - } - - elem = new_node2(IR_ELEMENT, array, index); - - /* The storage info here will be updated during code emit */ - elem->Store = _slang_new_ir_storage(array->Store->File, - array->Store->Index, - elemSize); - elem->Store->Swizzle = _slang_var_swizzle(elemSize, 0); - return elem; - } - else { - _slang_free_ir_tree(array); - _slang_free_ir_tree(index); - return NULL; - } - } -} - - -static slang_ir_node * -_slang_gen_compare(slang_assemble_ctx *A, slang_operation *oper, - slang_ir_opcode opcode) -{ - slang_typeinfo t0, t1; - slang_ir_node *n; - - slang_typeinfo_construct(&t0); - typeof_operation(A, &oper->children[0], &t0); - - slang_typeinfo_construct(&t1); - typeof_operation(A, &oper->children[0], &t1); - - if (t0.spec.type == SLANG_SPEC_ARRAY || - t1.spec.type == SLANG_SPEC_ARRAY) { - slang_info_log_error(A->log, "Illegal array comparison"); - return NULL; - } - - if (oper->type != SLANG_OPER_EQUAL && - oper->type != SLANG_OPER_NOTEQUAL) { - /* <, <=, >, >= can only be used with scalars */ - if ((t0.spec.type != SLANG_SPEC_INT && - t0.spec.type != SLANG_SPEC_FLOAT) || - (t1.spec.type != SLANG_SPEC_INT && - t1.spec.type != SLANG_SPEC_FLOAT)) { - slang_info_log_error(A->log, "Incompatible type(s) for inequality operator"); - return NULL; - } - } - - n = new_node2(opcode, - _slang_gen_operation(A, &oper->children[0]), - _slang_gen_operation(A, &oper->children[1])); - - /* result is a bool (size 1) */ - n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); - - return n; -} - - -#if 0 -static void -print_vars(slang_variable_scope *s) -{ - int i; - printf("vars: "); - for (i = 0; i < s->num_variables; i++) { - printf("%s %d, \n", - (char*) s->variables[i]->a_name, - s->variables[i]->declared); - } - - printf("\n"); -} -#endif - - -#if 0 -static void -_slang_undeclare_vars(slang_variable_scope *locals) -{ - if (locals->num_variables > 0) { - int i; - for (i = 0; i < locals->num_variables; i++) { - slang_variable *v = locals->variables[i]; - printf("undeclare %s at %p\n", (char*) v->a_name, v); - v->declared = GL_FALSE; - } - } -} -#endif - - -/** - * Generate IR tree for a slang_operation (AST node) - */ -static slang_ir_node * -_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) -{ - switch (oper->type) { - case SLANG_OPER_BLOCK_NEW_SCOPE: - { - slang_ir_node *n; - - _slang_push_var_table(A->vartable); - - oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; /* temp change */ - n = _slang_gen_operation(A, oper); - oper->type = SLANG_OPER_BLOCK_NEW_SCOPE; /* restore */ - - _slang_pop_var_table(A->vartable); - - /*_slang_undeclare_vars(oper->locals);*/ - /*print_vars(oper->locals);*/ - - if (n) - n = new_node1(IR_SCOPE, n); - return n; - } - break; - - case SLANG_OPER_BLOCK_NO_NEW_SCOPE: - /* list of operations */ - if (oper->num_children > 0) - { - slang_ir_node *n, *tree = NULL; - GLuint i; - - for (i = 0; i < oper->num_children; i++) { - n = _slang_gen_operation(A, &oper->children[i]); - if (!n) { - _slang_free_ir_tree(tree); - return NULL; /* error must have occured */ - } - tree = new_seq(tree, n); - } - - return tree; - } - else { - return new_node0(IR_NOP); - } - - case SLANG_OPER_EXPRESSION: - return _slang_gen_operation(A, &oper->children[0]); - - case SLANG_OPER_FOR: - return _slang_gen_for(A, oper); - case SLANG_OPER_DO: - return _slang_gen_do(A, oper); - case SLANG_OPER_WHILE: - return _slang_gen_while(A, oper); - case SLANG_OPER_BREAK: - if (!current_loop_oper(A)) { - slang_info_log_error(A->log, "'break' not in loop"); - return NULL; - } - return new_break(current_loop_ir(A)); - case SLANG_OPER_CONTINUE: - if (!current_loop_oper(A)) { - slang_info_log_error(A->log, "'continue' not in loop"); - return NULL; - } - return _slang_gen_continue(A, oper); - case SLANG_OPER_DISCARD: - return new_node0(IR_KILL); - - case SLANG_OPER_EQUAL: - return _slang_gen_compare(A, oper, IR_EQUAL); - case SLANG_OPER_NOTEQUAL: - return _slang_gen_compare(A, oper, IR_NOTEQUAL); - case SLANG_OPER_GREATER: - return _slang_gen_compare(A, oper, IR_SGT); - case SLANG_OPER_LESS: - return _slang_gen_compare(A, oper, IR_SLT); - case SLANG_OPER_GREATEREQUAL: - return _slang_gen_compare(A, oper, IR_SGE); - case SLANG_OPER_LESSEQUAL: - return _slang_gen_compare(A, oper, IR_SLE); - case SLANG_OPER_ADD: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_function_call_name(A, "+", oper, NULL); - return n; - } - case SLANG_OPER_SUBTRACT: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_function_call_name(A, "-", oper, NULL); - return n; - } - case SLANG_OPER_MULTIPLY: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_function_call_name(A, "*", oper, NULL); - return n; - } - case SLANG_OPER_DIVIDE: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_function_call_name(A, "/", oper, NULL); - return n; - } - case SLANG_OPER_MINUS: - { - slang_ir_node *n; - assert(oper->num_children == 1); - n = _slang_gen_function_call_name(A, "-", oper, NULL); - return n; - } - case SLANG_OPER_PLUS: - /* +expr --> do nothing */ - return _slang_gen_operation(A, &oper->children[0]); - case SLANG_OPER_VARIABLE_DECL: - return _slang_gen_declaration(A, oper); - case SLANG_OPER_ASSIGN: - return _slang_gen_assignment(A, oper); - case SLANG_OPER_ADDASSIGN: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_function_call_name(A, "+=", oper, NULL); - return n; - } - case SLANG_OPER_SUBASSIGN: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_function_call_name(A, "-=", oper, NULL); - return n; - } - break; - case SLANG_OPER_MULASSIGN: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_function_call_name(A, "*=", oper, NULL); - return n; - } - case SLANG_OPER_DIVASSIGN: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_function_call_name(A, "/=", oper, NULL); - return n; - } - case SLANG_OPER_LOGICALAND: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_logical_and(A, oper); - return n; - } - case SLANG_OPER_LOGICALOR: - { - slang_ir_node *n; - assert(oper->num_children == 2); - n = _slang_gen_logical_or(A, oper); - return n; - } - case SLANG_OPER_LOGICALXOR: - return _slang_gen_xor(A, oper); - case SLANG_OPER_NOT: - return _slang_gen_not(A, oper); - case SLANG_OPER_SELECT: /* b ? x : y */ - { - slang_ir_node *n; - assert(oper->num_children == 3); - n = _slang_gen_select(A, oper); - return n; - } - - case SLANG_OPER_ASM: - return _slang_gen_asm(A, oper, NULL); - case SLANG_OPER_CALL: - return _slang_gen_function_call_name(A, (const char *) oper->a_id, - oper, NULL); - case SLANG_OPER_METHOD: - return _slang_gen_method_call(A, oper); - case SLANG_OPER_RETURN: - return _slang_gen_return(A, oper); - case SLANG_OPER_RETURN_INLINED: - return _slang_gen_return(A, oper); - case SLANG_OPER_LABEL: - return new_label(oper->label); - case SLANG_OPER_IDENTIFIER: - return _slang_gen_variable(A, oper); - case SLANG_OPER_IF: - return _slang_gen_if(A, oper); - case SLANG_OPER_FIELD: - return _slang_gen_struct_field(A, oper); - case SLANG_OPER_SUBSCRIPT: - return _slang_gen_array_element(A, oper); - case SLANG_OPER_LITERAL_FLOAT: - /* fall-through */ - case SLANG_OPER_LITERAL_INT: - /* fall-through */ - case SLANG_OPER_LITERAL_BOOL: - return new_float_literal(oper->literal, oper->literal_size); - - case SLANG_OPER_POSTINCREMENT: /* var++ */ - { - slang_ir_node *n; - assert(oper->num_children == 1); - n = _slang_gen_function_call_name(A, "__postIncr", oper, NULL); - return n; - } - case SLANG_OPER_POSTDECREMENT: /* var-- */ - { - slang_ir_node *n; - assert(oper->num_children == 1); - n = _slang_gen_function_call_name(A, "__postDecr", oper, NULL); - return n; - } - case SLANG_OPER_PREINCREMENT: /* ++var */ - { - slang_ir_node *n; - assert(oper->num_children == 1); - n = _slang_gen_function_call_name(A, "++", oper, NULL); - return n; - } - case SLANG_OPER_PREDECREMENT: /* --var */ - { - slang_ir_node *n; - assert(oper->num_children == 1); - n = _slang_gen_function_call_name(A, "--", oper, NULL); - return n; - } - - case SLANG_OPER_NON_INLINED_CALL: - case SLANG_OPER_SEQUENCE: - { - slang_ir_node *tree = NULL; - GLuint i; - for (i = 0; i < oper->num_children; i++) { - slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]); - tree = new_seq(tree, n); - if (n) - tree->Store = n->Store; - } - if (oper->type == SLANG_OPER_NON_INLINED_CALL) { - tree = new_function_call(tree, oper->label); - } - return tree; - } - - case SLANG_OPER_NONE: - case SLANG_OPER_VOID: - /* returning NULL here would generate an error */ - return new_node0(IR_NOP); - - default: - _mesa_problem(NULL, "bad node type %d in _slang_gen_operation", - oper->type); - return new_node0(IR_NOP); - } - - return NULL; -} - - -/** - * Check if the given type specifier is a rectangular texture sampler. - */ -static GLboolean -is_rect_sampler_spec(const slang_type_specifier *spec) -{ - while (spec->_array) { - spec = spec->_array; - } - return spec->type == SLANG_SPEC_SAMPLER_RECT || - spec->type == SLANG_SPEC_SAMPLER_RECT_SHADOW; -} - - - -/** - * Called by compiler when a global variable has been parsed/compiled. - * Here we examine the variable's type to determine what kind of register - * storage will be used. - * - * A uniform such as "gl_Position" will become the register specification - * (PROGRAM_OUTPUT, VERT_RESULT_HPOS). Or, uniform "gl_FogFragCoord" - * will be (PROGRAM_INPUT, FRAG_ATTRIB_FOGC). - * - * Samplers are interesting. For "uniform sampler2D tex;" we'll specify - * (PROGRAM_SAMPLER, index) where index is resolved at link-time to an - * actual texture unit (as specified by the user calling glUniform1i()). - */ -GLboolean -_slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var, - slang_unit_type type) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_program *prog = A->program; - const char *varName = (char *) var->a_name; - GLboolean success = GL_TRUE; - slang_ir_storage *store = NULL; - int dbg = 0; - const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier); - const GLint size = _slang_sizeof_type_specifier(&var->type.specifier); - const GLint arrayLen = _slang_array_length(var); - const GLint totalSize = _slang_array_size(size, arrayLen); - GLint texIndex = sampler_to_texture_index(var->type.specifier.type); - - var->is_global = GL_TRUE; - - /* check for sampler2D arrays */ - if (texIndex == -1 && var->type.specifier._array) - texIndex = sampler_to_texture_index(var->type.specifier._array->type); - - if (texIndex != -1) { - /* This is a texture sampler variable... - * store->File = PROGRAM_SAMPLER - * store->Index = sampler number (0..7, typically) - * store->Size = texture type index (1D, 2D, 3D, cube, etc) - */ - if (var->initializer) { - slang_info_log_error(A->log, "illegal assignment to '%s'", varName); - return GL_FALSE; - } -#if FEATURE_es2_glsl /* XXX should use FEATURE_texture_rect */ - /* disallow rect samplers */ - if (ctx->API == API_OPENGLES2 && - is_rect_sampler_spec(&var->type.specifier)) { - slang_info_log_error(A->log, "invalid sampler type for '%s'", varName); - return GL_FALSE; - } -#else - (void) is_rect_sampler_spec; /* silence warning */ - (void) ctx; -#endif - { - GLint sampNum = _mesa_add_sampler(prog->Parameters, varName, datatype); - store = _slang_new_ir_storage_sampler(sampNum, texIndex, totalSize); - - /* If we have a sampler array, then we need to allocate the - * additional samplers to ensure we don't allocate them elsewhere. - * We can't directly use _mesa_add_sampler() as that checks the - * varName and gets a match, so we call _mesa_add_parameter() - * directly and use the last sampler number from the call above. - */ - if (arrayLen > 0) { - GLint a = arrayLen - 1; - GLint i; - for (i = 0; i < a; i++) { - GLfloat value = (GLfloat)(i + sampNum + 1); - (void) _mesa_add_parameter(prog->Parameters, PROGRAM_SAMPLER, - varName, 1, datatype, &value, NULL, 0x0); - } - } - } - if (dbg) printf("SAMPLER "); - } - else if (var->type.qualifier == SLANG_QUAL_UNIFORM) { - /* Uniform variable */ - const GLuint swizzle = _slang_var_swizzle(totalSize, 0); - - if (prog) { - /* user-defined uniform */ - if (datatype == GL_NONE) { - if ((var->type.specifier.type == SLANG_SPEC_ARRAY && - var->type.specifier._array->type == SLANG_SPEC_STRUCT) || - (var->type.specifier.type == SLANG_SPEC_STRUCT)) { - /* temporary work-around */ - GLenum datatype = GL_FLOAT; - GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName, - totalSize, datatype, NULL); - store = _slang_new_ir_storage_swz(PROGRAM_UNIFORM, uniformLoc, - totalSize, swizzle); - - if (arrayLen > 0) { - GLint a = arrayLen - 1; - GLint i; - for (i = 0; i < a; i++) { - GLfloat value = (GLfloat)(i + uniformLoc + 1); - (void) _mesa_add_parameter(prog->Parameters, PROGRAM_UNIFORM, - varName, 1, datatype, &value, NULL, 0x0); - } - } - - /* XXX what we need to do is unroll the struct into its - * basic types, creating a uniform variable for each. - * For example: - * struct foo { - * vec3 a; - * vec4 b; - * }; - * uniform foo f; - * - * Should produce uniforms: - * "f.a" (GL_FLOAT_VEC3) - * "f.b" (GL_FLOAT_VEC4) - */ - - if (var->initializer) { - slang_info_log_error(A->log, - "unsupported initializer for uniform '%s'", varName); - return GL_FALSE; - } - } - else { - slang_info_log_error(A->log, - "invalid datatype for uniform variable %s", - varName); - return GL_FALSE; - } - } - else { - /* non-struct uniform */ - if (!_slang_gen_var_decl(A, var, var->initializer)) - return GL_FALSE; - store = var->store; - } - } - else { - /* pre-defined uniform, like gl_ModelviewMatrix */ - /* We know it's a uniform, but don't allocate storage unless - * it's really used. - */ - store = _slang_new_ir_storage_swz(PROGRAM_STATE_VAR, -1, - totalSize, swizzle); - } - if (dbg) printf("UNIFORM (sz %d) ", totalSize); - } - else if (var->type.qualifier == SLANG_QUAL_VARYING) { - /* varyings must be float, vec or mat */ - if (!_slang_type_is_float_vec_mat(var->type.specifier.type) && - var->type.specifier.type != SLANG_SPEC_ARRAY) { - slang_info_log_error(A->log, - "varying '%s' must be float/vector/matrix", - varName); - return GL_FALSE; - } - - if (var->initializer) { - slang_info_log_error(A->log, "illegal initializer for varying '%s'", - varName); - return GL_FALSE; - } - - if (prog) { - /* user-defined varying */ - GLbitfield flags; - GLint varyingLoc; - GLuint swizzle; - - flags = 0x0; - if (var->type.centroid == SLANG_CENTROID) - flags |= PROG_PARAM_BIT_CENTROID; - if (var->type.variant == SLANG_INVARIANT) - flags |= PROG_PARAM_BIT_INVARIANT; - - varyingLoc = _mesa_add_varying(prog->Varying, varName, - totalSize, GL_NONE, flags); - swizzle = _slang_var_swizzle(size, 0); - store = _slang_new_ir_storage_swz(PROGRAM_VARYING, varyingLoc, - totalSize, swizzle); - } - else { - /* pre-defined varying, like gl_Color or gl_TexCoord */ - if (type == SLANG_UNIT_FRAGMENT_BUILTIN) { - /* fragment program input */ - GLuint swizzle; - GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB, - &swizzle, NULL); - assert(index >= 0); - assert(index < FRAG_ATTRIB_MAX); - store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, - size, swizzle); - } else if (type == SLANG_UNIT_VERTEX_BUILTIN) { - /* vertex program output */ - GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB); - GLuint swizzle = _slang_var_swizzle(size, 0); - assert(index >= 0); - assert(index < VERT_RESULT_MAX); - assert(type == SLANG_UNIT_VERTEX_BUILTIN); - store = _slang_new_ir_storage_swz(PROGRAM_OUTPUT, index, - size, swizzle); - } else { - /* geometry program input */ - GLboolean is_array = GL_FALSE; - GLuint swizzle; - GLint index = _slang_input_index(varName, MESA_GEOMETRY_PROGRAM, - &swizzle, &is_array); - if (index < 0) { - /* geometry program output */ - index = _slang_output_index(varName, MESA_GEOMETRY_PROGRAM); - swizzle = _slang_var_swizzle(size, 0); - - assert(index >= 0); - assert(index < GEOM_RESULT_MAX); - - store = _slang_new_ir_storage_swz(PROGRAM_OUTPUT, index, - size, swizzle); - } else { - assert(index >= 0); - /* assert(index < GEOM_ATTRIB_MAX); */ - if (is_array) - store = _slang_new_ir_storage_2d(PROGRAM_INPUT, 0, index, - size, swizzle); - else - store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, - size, swizzle); - } - } - if (dbg) printf("V/F "); - } - if (dbg) printf("VARYING "); - } - else if (var->type.qualifier == SLANG_QUAL_ATTRIBUTE) { - GLuint swizzle; - GLint index; - /* attributes must be float, vec or mat */ - if (!_slang_type_is_float_vec_mat(var->type.specifier.type)) { - slang_info_log_error(A->log, - "attribute '%s' must be float/vector/matrix", - varName); - return GL_FALSE; - } - - if (prog) { - /* user-defined vertex attribute */ - const GLint attr = -1; /* unknown */ - swizzle = _slang_var_swizzle(size, 0); - index = _mesa_add_attribute(prog->Attributes, varName, - size, datatype, attr); - assert(index >= 0); - index = VERT_ATTRIB_GENERIC0 + index; - } - else { - /* pre-defined vertex attrib */ - index = _slang_input_index(varName, GL_VERTEX_PROGRAM_ARB, &swizzle, NULL); - assert(index >= 0); - } - store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, size, swizzle); - if (dbg) printf("ATTRIB "); - } - else if (var->type.qualifier == SLANG_QUAL_FIXEDINPUT) { - GLuint swizzle = SWIZZLE_XYZW; /* silence compiler warning */ - if (type == SLANG_UNIT_FRAGMENT_BUILTIN) { - GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB, - &swizzle, NULL); - store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, size, swizzle); - } else if (type == SLANG_UNIT_GEOMETRY_BUILTIN) { - GLboolean is_array; - GLint index = _slang_input_index(varName, MESA_GEOMETRY_PROGRAM, - &swizzle, &is_array); - if (is_array) - store = _slang_new_ir_storage_2d(PROGRAM_INPUT, 0, index, size, swizzle); - else - store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, size, swizzle); - } - if (dbg) printf("INPUT "); - } - else if (var->type.qualifier == SLANG_QUAL_FIXEDOUTPUT) { - if (type == SLANG_UNIT_VERTEX_BUILTIN) { - GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB); - store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size); - } else if (type == SLANG_UNIT_FRAGMENT_BUILTIN) { - GLint index = _slang_output_index(varName, GL_FRAGMENT_PROGRAM_ARB); - GLint specialSize = 4; /* treat all fragment outputs as float[4] */ - assert(type == SLANG_UNIT_FRAGMENT_BUILTIN); - store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, specialSize); - } else { - GLint index = _slang_output_index(varName, MESA_GEOMETRY_PROGRAM); - GLint specialSize = 4; /* treat all fragment outputs as float[4] */ - assert(type == SLANG_UNIT_GEOMETRY_BUILTIN); - store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, specialSize); - } - if (dbg) printf("OUTPUT "); - } - else if (var->type.qualifier == SLANG_QUAL_CONST && !prog) { - /* pre-defined global constant, like gl_MaxLights */ - store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size); - if (dbg) printf("CONST "); - } - else { - /* ordinary variable (may be const) */ - slang_ir_node *n; - - /* IR node to declare the variable */ - n = _slang_gen_var_decl(A, var, var->initializer); - - /* emit GPU instructions */ - success = _slang_emit_code(n, A->vartable, A->program, A->pragmas, GL_FALSE, A->log); - - _slang_free_ir_tree(n); - } - - if (dbg) printf("GLOBAL VAR %s idx %d\n", (char*) var->a_name, - store ? store->Index : -2); - - if (store) - var->store = store; /* save var's storage info */ - - var->declared = GL_TRUE; - - return success; -} - - -/** - * Produce an IR tree from a function AST (fun->body). - * Then call the code emitter to convert the IR tree into gl_program - * instructions. - */ -GLboolean -_slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) -{ - slang_ir_node *n; - GLboolean success = GL_TRUE; - - if (strcmp((char *) fun->header.a_name, "main") != 0) { - /* we only really generate code for main, all other functions get - * inlined or codegen'd upon an actual call. - */ -#if 0 - /* do some basic error checking though */ - if (fun->header.type.specifier.type != SLANG_SPEC_VOID) { - /* check that non-void functions actually return something */ - slang_operation *op - = _slang_find_node_type(fun->body, SLANG_OPER_RETURN); - if (!op) { - slang_info_log_error(A->log, - "function \"%s\" has no return statement", - (char *) fun->header.a_name); - printf( - "function \"%s\" has no return statement\n", - (char *) fun->header.a_name); - return GL_FALSE; - } - } -#endif - return GL_TRUE; /* not an error */ - } - -#if 0 - printf("\n*********** codegen_function %s\n", (char *) fun->header.a_name); - slang_print_function(fun, 1); -#endif - - /* should have been allocated earlier: */ - assert(A->program->Parameters ); - assert(A->program->Varying); - assert(A->vartable); - - A->LoopDepth = 0; - A->UseReturnFlag = GL_FALSE; - A->CurFunction = fun; - - /* fold constant expressions, etc. */ - _slang_simplify(fun->body, &A->space, A->atoms); - -#if 0 - printf("\n*********** simplified %s\n", (char *) fun->header.a_name); - slang_print_function(fun, 1); -#endif - - /* Create an end-of-function label */ - A->curFuncEndLabel = _slang_label_new("__endOfFunc__main"); - - /* push new vartable scope */ - _slang_push_var_table(A->vartable); - - /* Generate IR tree for the function body code */ - n = _slang_gen_operation(A, fun->body); - if (n) - n = new_node1(IR_SCOPE, n); - - /* pop vartable, restore previous */ - _slang_pop_var_table(A->vartable); - - if (!n) { - /* XXX record error */ - return GL_FALSE; - } - - /* append an end-of-function-label to IR tree */ - n = new_seq(n, new_label(A->curFuncEndLabel)); - - /*_slang_label_delete(A->curFuncEndLabel);*/ - A->curFuncEndLabel = NULL; - -#if 0 - printf("************* New AST for %s *****\n", (char*)fun->header.a_name); - slang_print_function(fun, 1); -#endif -#if 0 - printf("************* IR for %s *******\n", (char*)fun->header.a_name); - _slang_print_ir_tree(n, 0); -#endif -#if 0 - printf("************* End codegen function ************\n\n"); -#endif - - if (A->UnresolvedRefs) { - /* Can't codegen at this time. - * At link time we'll concatenate all the vertex shaders and/or all - * the fragment shaders and try recompiling. - */ - return GL_TRUE; - } - - /* Emit program instructions */ - success = _slang_emit_code(n, A->vartable, A->program, A->pragmas, GL_TRUE, A->log); - _slang_free_ir_tree(n); - - /* free codegen context */ - /* - free(A->codegen); - */ - - return success; -} - diff --git a/src/mesa/slang/slang_codegen.h b/src/mesa/slang/slang_codegen.h deleted file mode 100644 index ff0279bbfe..0000000000 --- a/src/mesa/slang/slang_codegen.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#ifndef SLANG_CODEGEN_H -#define SLANG_CODEGEN_H - - -#include "main/glheader.h" -#include "slang_compile.h" -#include "slang_compile_variable.h" -#include "slang_typeinfo.h" -#include "slang_utility.h" - -struct slang_function_; - -#define MAX_LOOP_DEPTH 30 - - -typedef struct slang_assemble_ctx_ -{ - slang_atom_pool *atoms; - slang_name_space space; - struct gl_program *program; - struct gl_sl_pragmas *pragmas; - slang_var_table *vartable; - slang_info_log *log; - GLboolean allow_uniform_initializers; - - /* current loop stack */ - const slang_operation *LoopOperStack[MAX_LOOP_DEPTH]; - struct slang_ir_node_ *LoopIRStack[MAX_LOOP_DEPTH]; - GLuint LoopDepth; - - /* current function */ - struct slang_function_ *CurFunction; - struct slang_label_ *curFuncEndLabel; - GLboolean UseReturnFlag; - - GLboolean UnresolvedRefs; - GLboolean EmitContReturn; -} slang_assemble_ctx; - - -extern GLuint -_slang_sizeof_type_specifier(const slang_type_specifier *spec); - -extern GLboolean -_slang_codegen_function(slang_assemble_ctx *A , struct slang_function_ *fun); - -extern GLboolean -_slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var, - slang_unit_type type); - - -#endif /* SLANG_CODEGEN_H */ diff --git a/src/mesa/slang/slang_compile.c b/src/mesa/slang/slang_compile.c deleted file mode 100644 index de1bb56cd9..0000000000 --- a/src/mesa/slang/slang_compile.c +++ /dev/null @@ -1,3103 +0,0 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * Copyright (C) 2008 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_compile.c - * slang front-end compiler - * \author Michal Krol - */ - -#include "main/imports.h" -#include "main/context.h" -#include "program/program.h" -#include "program/programopt.h" -#include "program/prog_optimize.h" -#include "program/prog_print.h" -#include "program/prog_parameter.h" -#include "../../glsl/pp/sl_pp_public.h" -#include "../../glsl/pp/sl_pp_purify.h" -#include "../../glsl/cl/sl_cl_parse.h" -#include "slang_codegen.h" -#include "slang_compile.h" -#include "slang_storage.h" -#include "slang_log.h" -#include "slang_mem.h" -#include "slang_vartable.h" -#include "slang_simplify.h" - -/* - * This is a straightforward implementation of the slang front-end - * compiler. Lots of error-checking functionality is missing but - * every well-formed shader source should compile successfully and - * execute as expected. However, some semantically ill-formed shaders - * may be accepted resulting in undefined behaviour. - */ - - -/** re-defined below, should be the same though */ -#define TYPE_SPECIFIER_COUNT 36 - - -/** - * Check if the given identifier is legal. - */ -static GLboolean -legal_identifier(slang_atom name) -{ - /* "gl_" is a reserved prefix */ - if (strncmp((char *) name, "gl_", 3) == 0) { - return GL_FALSE; - } - return GL_TRUE; -} - - -/* - * slang_code_unit - */ - -GLvoid -_slang_code_unit_ctr(slang_code_unit * self, - struct slang_code_object_ * object) -{ - _slang_variable_scope_ctr(&self->vars); - _slang_function_scope_ctr(&self->funs); - _slang_struct_scope_ctr(&self->structs); - self->object = object; -} - -GLvoid -_slang_code_unit_dtr(slang_code_unit * self) -{ - slang_variable_scope_destruct(&self->vars); - slang_function_scope_destruct(&self->funs); - slang_struct_scope_destruct(&self->structs); -} - -/* - * slang_code_object - */ - -GLvoid -_slang_code_object_ctr(slang_code_object * self) -{ - GLuint i; - - for (i = 0; i < SLANG_BUILTIN_TOTAL; i++) - _slang_code_unit_ctr(&self->builtin[i], self); - _slang_code_unit_ctr(&self->unit, self); - slang_atom_pool_construct(&self->atompool); -} - -GLvoid -_slang_code_object_dtr(slang_code_object * self) -{ - GLuint i; - - for (i = 0; i < SLANG_BUILTIN_TOTAL; i++) - _slang_code_unit_dtr(&self->builtin[i]); - _slang_code_unit_dtr(&self->unit); - slang_atom_pool_destruct(&self->atompool); -} - - -/* slang_parse_ctx */ - -typedef struct slang_parse_ctx_ -{ - const unsigned char *I; - slang_info_log *L; - int parsing_builtin; - GLboolean global_scope; /**< Is object being declared a global? */ - slang_atom_pool *atoms; - slang_unit_type type; /**< Vertex vs. Fragment */ - GLuint version; /**< user-specified (or default) #version */ -} slang_parse_ctx; - -/* slang_output_ctx */ - -typedef struct slang_output_ctx_ -{ - slang_variable_scope *vars; - slang_function_scope *funs; - slang_struct_scope *structs; - struct gl_program *program; - struct gl_sl_pragmas *pragmas; - slang_var_table *vartable; - GLuint default_precision[TYPE_SPECIFIER_COUNT]; - GLboolean allow_precision; - GLboolean allow_invariant; - GLboolean allow_centroid; - GLboolean allow_array_types; /* float[] syntax */ -} slang_output_ctx; - -/* _slang_compile() */ - - -/* Debugging aid, print file/line where parsing error is detected */ -#define RETURN0 \ - do { \ - if (0) \ - printf("slang error at %s:%d\n", __FILE__, __LINE__); \ - return 0; \ - } while (0) - - -static void -parse_identifier_str(slang_parse_ctx * C, char **id) -{ - *id = (char *) C->I; - C->I += strlen(*id) + 1; -} - -static slang_atom -parse_identifier(slang_parse_ctx * C) -{ - const char *id; - - id = (const char *) C->I; - C->I += strlen(id) + 1; - return slang_atom_pool_atom(C->atoms, id); -} - -static int -is_hex_digit(char c) -{ - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); -} - -static int -parse_general_number(slang_parse_ctx *ctx, float *number) -{ - char *flt = NULL; - - if (*ctx->I == '0') { - int value = 0; - const unsigned char *pi; - - if (ctx->I[1] == 'x' || ctx->I[1] == 'X') { - ctx->I += 2; - if (!is_hex_digit(*ctx->I)) { - return 0; - } - do { - int digit; - - if (*ctx->I >= '0' && *ctx->I <= '9') { - digit = (int)(*ctx->I - '0'); - } else if (*ctx->I >= 'a' && *ctx->I <= 'f') { - digit = (int)(*ctx->I - 'a') + 10; - } else { - digit = (int)(*ctx->I - 'A') + 10; - } - value = value * 0x10 + digit; - ctx->I++; - } while (is_hex_digit(*ctx->I)); - if (*ctx->I != '\0') { - return 0; - } - ctx->I++; - *number = (float)value; - return 1; - } - - pi = ctx->I; - pi++; - while (*pi >= '0' && *pi <= '7') { - int digit; - - digit = (int)(*pi - '0'); - value = value * 010 + digit; - pi++; - } - if (*pi == '\0') { - pi++; - ctx->I = pi; - *number = (float)value; - return 1; - } - } - - parse_identifier_str(ctx, &flt); - flt = _mesa_strdup(flt); - if (!flt) { - return 0; - } - if (flt[strlen(flt) - 1] == 'f' || flt[strlen(flt) - 1] == 'F') { - flt[strlen(flt) - 1] = '\0'; - } - *number = _mesa_strtof(flt, (char **)NULL); - free(flt); - - return 1; -} - -static int -parse_number(slang_parse_ctx * C, int *number) -{ - const int radix = (int) (*C->I++); - - if (radix == 1) { - float f = 0.0f; - - parse_general_number(C, &f); - *number = (int)f; - } else { - *number = 0; - while (*C->I != '\0') { - int digit; - if (*C->I >= '0' && *C->I <= '9') - digit = (int) (*C->I - '0'); - else if (*C->I >= 'A' && *C->I <= 'Z') - digit = (int) (*C->I - 'A') + 10; - else - digit = (int) (*C->I - 'a') + 10; - *number = *number * radix + digit; - C->I++; - } - C->I++; - } - if (*number > 65535) - slang_info_log_warning(C->L, "%d: literal integer overflow.", *number); - return 1; -} - -static int -parse_float(slang_parse_ctx * C, float *number) -{ - if (*C->I == 1) { - C->I++; - parse_general_number(C, number); - } else { - char *integral = NULL; - char *fractional = NULL; - char *exponent = NULL; - char *whole = NULL; - - parse_identifier_str(C, &integral); - parse_identifier_str(C, &fractional); - parse_identifier_str(C, &exponent); - - whole = (char *) _slang_alloc((strlen(integral) + - strlen(fractional) + - strlen(exponent) + 3) * sizeof(char)); - if (whole == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - - slang_string_copy(whole, integral); - slang_string_concat(whole, "."); - slang_string_concat(whole, fractional); - slang_string_concat(whole, "E"); - slang_string_concat(whole, exponent); - - *number = _mesa_strtof(whole, (char **) NULL); - - _slang_free(whole); - } - - return 1; -} - -/* revision number - increment after each change affecting emitted output */ -#define REVISION 5 - -static int -check_revision(slang_parse_ctx * C) -{ - if (*C->I != REVISION) { - slang_info_log_error(C->L, "Internal compiler error."); - RETURN0; - } - C->I++; - return 1; -} - -static int parse_statement(slang_parse_ctx *, slang_output_ctx *, - slang_operation *); -static int parse_expression(slang_parse_ctx *, slang_output_ctx *, - slang_operation *); -static int parse_type_specifier(slang_parse_ctx *, slang_output_ctx *, - slang_type_specifier *); -static int -parse_type_array_size(slang_parse_ctx *C, - slang_output_ctx *O, - GLint *array_len); - -static GLboolean -parse_array_len(slang_parse_ctx * C, slang_output_ctx * O, GLuint * len) -{ - slang_operation array_size; - slang_name_space space; - GLboolean result; - - if (!slang_operation_construct(&array_size)) - return GL_FALSE; - if (!parse_expression(C, O, &array_size)) { - slang_operation_destruct(&array_size); - return GL_FALSE; - } - - space.funcs = O->funs; - space.structs = O->structs; - space.vars = O->vars; - - /* evaluate compile-time expression which is array size */ - _slang_simplify(&array_size, &space, C->atoms); - - if (array_size.type == SLANG_OPER_LITERAL_INT) { - result = GL_TRUE; - *len = (GLint) array_size.literal[0]; - } else if (array_size.type == SLANG_OPER_IDENTIFIER) { - slang_variable *var = _slang_variable_locate(array_size.locals, array_size.a_id, GL_TRUE); - if (!var) { - slang_info_log_error(C->L, "undefined variable '%s'", - (char *) array_size.a_id); - result = GL_FALSE; - } else if (var->type.qualifier == SLANG_QUAL_CONST && - var->type.specifier.type == SLANG_SPEC_INT) { - if (var->initializer && - var->initializer->type == SLANG_OPER_LITERAL_INT) { - *len = (GLint) var->initializer->literal[0]; - result = GL_TRUE; - } else { - slang_info_log_error(C->L, "unable to parse array size declaration"); - result = GL_FALSE; - } - } else { - slang_info_log_error(C->L, "unable to parse array size declaration"); - result = GL_FALSE; - } - } else { - result = GL_FALSE; - } - - slang_operation_destruct(&array_size); - return result; -} - -static GLboolean -calculate_var_size(slang_parse_ctx * C, slang_output_ctx * O, - slang_variable * var) -{ - slang_storage_aggregate agg; - - if (!slang_storage_aggregate_construct(&agg)) - return GL_FALSE; - if (!_slang_aggregate_variable(&agg, &var->type.specifier, var->array_len, - O->funs, O->structs, O->vars, C->atoms)) { - slang_storage_aggregate_destruct(&agg); - return GL_FALSE; - } - var->size = _slang_sizeof_aggregate(&agg); - slang_storage_aggregate_destruct(&agg); - return GL_TRUE; -} - -static void -promote_type_to_array(slang_parse_ctx *C, - slang_fully_specified_type *type, - GLint array_len) -{ - slang_type_specifier *baseType = - slang_type_specifier_new(type->specifier.type, NULL, NULL); - - type->specifier.type = SLANG_SPEC_ARRAY; - type->specifier._array = baseType; - type->array_len = array_len; -} - - -static GLboolean -convert_to_array(slang_parse_ctx * C, slang_variable * var, - const slang_type_specifier * sp) -{ - /* sized array - mark it as array, copy the specifier to the array element - * and parse the expression */ - var->type.specifier.type = SLANG_SPEC_ARRAY; - var->type.specifier._array = (slang_type_specifier *) - _slang_alloc(sizeof(slang_type_specifier)); - if (var->type.specifier._array == NULL) { - slang_info_log_memory(C->L); - return GL_FALSE; - } - slang_type_specifier_ctr(var->type.specifier._array); - return slang_type_specifier_copy(var->type.specifier._array, sp); -} - -/* structure field */ -#define FIELD_NONE 0 -#define FIELD_NEXT 1 -#define FIELD_ARRAY 2 - -static GLboolean -parse_struct_field_var(slang_parse_ctx * C, slang_output_ctx * O, - slang_variable * var, slang_atom a_name, - const slang_type_specifier * sp, - GLuint array_len) -{ - var->a_name = a_name; - if (var->a_name == SLANG_ATOM_NULL) - return GL_FALSE; - - switch (*C->I++) { - case FIELD_NONE: - if (array_len != -1) { - if (!convert_to_array(C, var, sp)) - return GL_FALSE; - var->array_len = array_len; - } - else { - if (!slang_type_specifier_copy(&var->type.specifier, sp)) - return GL_FALSE; - } - break; - case FIELD_ARRAY: - if (array_len != -1) - return GL_FALSE; - if (!convert_to_array(C, var, sp)) - return GL_FALSE; - if (!parse_array_len(C, O, &var->array_len)) - return GL_FALSE; - break; - default: - return GL_FALSE; - } - - return calculate_var_size(C, O, var); -} - -static int -parse_struct_field(slang_parse_ctx * C, slang_output_ctx * O, - slang_struct * st, slang_type_specifier * sp) -{ - slang_output_ctx o = *O; - GLint array_len; - - o.structs = st->structs; - if (!parse_type_specifier(C, &o, sp)) - RETURN0; - if (!parse_type_array_size(C, &o, &array_len)) - RETURN0; - - do { - slang_atom a_name; - slang_variable *var = slang_variable_scope_grow(st->fields); - if (!var) { - slang_info_log_memory(C->L); - RETURN0; - } - a_name = parse_identifier(C); - if (_slang_variable_locate(st->fields, a_name, GL_FALSE)) { - slang_info_log_error(C->L, "duplicate field '%s'", (char *) a_name); - RETURN0; - } - - if (!parse_struct_field_var(C, &o, var, a_name, sp, array_len)) - RETURN0; - } - while (*C->I++ != FIELD_NONE); - - return 1; -} - -static int -parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) -{ - slang_atom a_name; - const char *name; - - /* parse struct name (if any) and make sure it is unique in current scope */ - a_name = parse_identifier(C); - if (a_name == SLANG_ATOM_NULL) - RETURN0; - - name = slang_atom_pool_id(C->atoms, a_name); - if (name[0] != '\0' - && slang_struct_scope_find(O->structs, a_name, 0) != NULL) { - slang_info_log_error(C->L, "%s: duplicate type name.", name); - RETURN0; - } - - /* set-up a new struct */ - *st = (slang_struct *) _slang_alloc(sizeof(slang_struct)); - if (*st == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - if (!slang_struct_construct(*st)) { - _slang_free(*st); - *st = NULL; - slang_info_log_memory(C->L); - RETURN0; - } - (**st).a_name = a_name; - (**st).structs->outer_scope = O->structs; - - /* parse individual struct fields */ - do { - slang_type_specifier sp; - - slang_type_specifier_ctr(&sp); - if (!parse_struct_field(C, O, *st, &sp)) { - slang_type_specifier_dtr(&sp); - RETURN0; - } - slang_type_specifier_dtr(&sp); - } - while (*C->I++ != FIELD_NONE); - - /* if named struct, copy it to current scope */ - if (name[0] != '\0') { - slang_struct *s; - - O->structs->structs = - (slang_struct *) _slang_realloc(O->structs->structs, - O->structs->num_structs - * sizeof(slang_struct), - (O->structs->num_structs + 1) - * sizeof(slang_struct)); - if (O->structs->structs == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - s = &O->structs->structs[O->structs->num_structs]; - if (!slang_struct_construct(s)) - RETURN0; - O->structs->num_structs++; - if (!slang_struct_copy(s, *st)) - RETURN0; - } - - return 1; -} - - -/* invariant qualifer */ -#define TYPE_VARIANT 90 -#define TYPE_INVARIANT 91 - -static int -parse_type_variant(slang_parse_ctx * C, slang_type_variant *variant) -{ - GLuint invariant = *C->I++; - switch (invariant) { - case TYPE_VARIANT: - *variant = SLANG_VARIANT; - return 1; - case TYPE_INVARIANT: - *variant = SLANG_INVARIANT; - return 1; - default: - RETURN0; - } -} - - -/* centroid qualifer */ -#define TYPE_CENTER 95 -#define TYPE_CENTROID 96 - -static int -parse_type_centroid(slang_parse_ctx * C, slang_type_centroid *centroid) -{ - GLuint c = *C->I++; - switch (c) { - case TYPE_CENTER: - *centroid = SLANG_CENTER; - return 1; - case TYPE_CENTROID: - *centroid = SLANG_CENTROID; - return 1; - default: - RETURN0; - } -} - - -/* Layout qualifiers */ -#define LAYOUT_QUALIFIER_NONE 0 -#define LAYOUT_QUALIFIER_UPPER_LEFT 1 -#define LAYOUT_QUALIFIER_PIXEL_CENTER_INTEGER 2 - -static int -parse_layout_qualifiers(slang_parse_ctx * C, slang_layout_qualifier *layout) -{ - *layout = 0x0; - - /* the layout qualifiers come as a list of LAYOUT_QUALIFER_x tokens, - * terminated by LAYOUT_QUALIFIER_NONE. - */ - while (1) { - GLuint c = *C->I++; - switch (c) { - case LAYOUT_QUALIFIER_NONE: - /* end of list of qualifiers */ - return 1; - case LAYOUT_QUALIFIER_UPPER_LEFT: - *layout |= SLANG_LAYOUT_UPPER_LEFT_BIT; - break; - case LAYOUT_QUALIFIER_PIXEL_CENTER_INTEGER: - *layout |= SLANG_LAYOUT_PIXEL_CENTER_INTEGER_BIT; - break; - default: - assert(0 && "Bad layout qualifier"); - } - } -} - - -/* type qualifier */ -#define TYPE_QUALIFIER_NONE 0 -#define TYPE_QUALIFIER_CONST 1 -#define TYPE_QUALIFIER_ATTRIBUTE 2 -#define TYPE_QUALIFIER_VARYING 3 -#define TYPE_QUALIFIER_UNIFORM 4 -#define TYPE_QUALIFIER_FIXEDOUTPUT 5 -#define TYPE_QUALIFIER_FIXEDINPUT 6 - -static int -parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual) -{ - GLuint qualifier = *C->I++; - switch (qualifier) { - case TYPE_QUALIFIER_NONE: - *qual = SLANG_QUAL_NONE; - break; - case TYPE_QUALIFIER_CONST: - *qual = SLANG_QUAL_CONST; - break; - case TYPE_QUALIFIER_ATTRIBUTE: - *qual = SLANG_QUAL_ATTRIBUTE; - break; - case TYPE_QUALIFIER_VARYING: - *qual = SLANG_QUAL_VARYING; - break; - case TYPE_QUALIFIER_UNIFORM: - *qual = SLANG_QUAL_UNIFORM; - break; - case TYPE_QUALIFIER_FIXEDOUTPUT: - *qual = SLANG_QUAL_FIXEDOUTPUT; - break; - case TYPE_QUALIFIER_FIXEDINPUT: - *qual = SLANG_QUAL_FIXEDINPUT; - break; - default: - RETURN0; - } - return 1; -} - -/* type specifier */ -#define TYPE_SPECIFIER_VOID 0 -#define TYPE_SPECIFIER_BOOL 1 -#define TYPE_SPECIFIER_BVEC2 2 -#define TYPE_SPECIFIER_BVEC3 3 -#define TYPE_SPECIFIER_BVEC4 4 -#define TYPE_SPECIFIER_INT 5 -#define TYPE_SPECIFIER_IVEC2 6 -#define TYPE_SPECIFIER_IVEC3 7 -#define TYPE_SPECIFIER_IVEC4 8 -#define TYPE_SPECIFIER_FLOAT 9 -#define TYPE_SPECIFIER_VEC2 10 -#define TYPE_SPECIFIER_VEC3 11 -#define TYPE_SPECIFIER_VEC4 12 -#define TYPE_SPECIFIER_MAT2 13 -#define TYPE_SPECIFIER_MAT3 14 -#define TYPE_SPECIFIER_MAT4 15 -#define TYPE_SPECIFIER_SAMPLER1D 16 -#define TYPE_SPECIFIER_SAMPLER2D 17 -#define TYPE_SPECIFIER_SAMPLER3D 18 -#define TYPE_SPECIFIER_SAMPLERCUBE 19 -#define TYPE_SPECIFIER_SAMPLER1DSHADOW 20 -#define TYPE_SPECIFIER_SAMPLER2DSHADOW 21 -#define TYPE_SPECIFIER_SAMPLER2DRECT 22 -#define TYPE_SPECIFIER_SAMPLER2DRECTSHADOW 23 -#define TYPE_SPECIFIER_STRUCT 24 -#define TYPE_SPECIFIER_TYPENAME 25 -#define TYPE_SPECIFIER_MAT23 26 -#define TYPE_SPECIFIER_MAT32 27 -#define TYPE_SPECIFIER_MAT24 28 -#define TYPE_SPECIFIER_MAT42 29 -#define TYPE_SPECIFIER_MAT34 30 -#define TYPE_SPECIFIER_MAT43 31 -#define TYPE_SPECIFIER_SAMPLER_1D_ARRAY 32 -#define TYPE_SPECIFIER_SAMPLER_2D_ARRAY 33 -#define TYPE_SPECIFIER_SAMPLER_1D_ARRAY_SHADOW 34 -#define TYPE_SPECIFIER_SAMPLER_2D_ARRAY_SHADOW 35 -#define TYPE_SPECIFIER_COUNT 36 - -static int -parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, - slang_type_specifier * spec) -{ - int type = *C->I++; - switch (type) { - case TYPE_SPECIFIER_VOID: - spec->type = SLANG_SPEC_VOID; - break; - case TYPE_SPECIFIER_BOOL: - spec->type = SLANG_SPEC_BOOL; - break; - case TYPE_SPECIFIER_BVEC2: - spec->type = SLANG_SPEC_BVEC2; - break; - case TYPE_SPECIFIER_BVEC3: - spec->type = SLANG_SPEC_BVEC3; - break; - case TYPE_SPECIFIER_BVEC4: - spec->type = SLANG_SPEC_BVEC4; - break; - case TYPE_SPECIFIER_INT: - spec->type = SLANG_SPEC_INT; - break; - case TYPE_SPECIFIER_IVEC2: - spec->type = SLANG_SPEC_IVEC2; - break; - case TYPE_SPECIFIER_IVEC3: - spec->type = SLANG_SPEC_IVEC3; - break; - case TYPE_SPECIFIER_IVEC4: - spec->type = SLANG_SPEC_IVEC4; - break; - case TYPE_SPECIFIER_FLOAT: - spec->type = SLANG_SPEC_FLOAT; - break; - case TYPE_SPECIFIER_VEC2: - spec->type = SLANG_SPEC_VEC2; - break; - case TYPE_SPECIFIER_VEC3: - spec->type = SLANG_SPEC_VEC3; - break; - case TYPE_SPECIFIER_VEC4: - spec->type = SLANG_SPEC_VEC4; - break; - case TYPE_SPECIFIER_MAT2: - spec->type = SLANG_SPEC_MAT2; - break; - case TYPE_SPECIFIER_MAT3: - spec->type = SLANG_SPEC_MAT3; - break; - case TYPE_SPECIFIER_MAT4: - spec->type = SLANG_SPEC_MAT4; - break; - case TYPE_SPECIFIER_MAT23: - spec->type = SLANG_SPEC_MAT23; - break; - case TYPE_SPECIFIER_MAT32: - spec->type = SLANG_SPEC_MAT32; - break; - case TYPE_SPECIFIER_MAT24: - spec->type = SLANG_SPEC_MAT24; - break; - case TYPE_SPECIFIER_MAT42: - spec->type = SLANG_SPEC_MAT42; - break; - case TYPE_SPECIFIER_MAT34: - spec->type = SLANG_SPEC_MAT34; - break; - case TYPE_SPECIFIER_MAT43: - spec->type = SLANG_SPEC_MAT43; - break; - case TYPE_SPECIFIER_SAMPLER1D: - spec->type = SLANG_SPEC_SAMPLER_1D; - break; - case TYPE_SPECIFIER_SAMPLER2D: - spec->type = SLANG_SPEC_SAMPLER_2D; - break; - case TYPE_SPECIFIER_SAMPLER3D: - spec->type = SLANG_SPEC_SAMPLER_3D; - break; - case TYPE_SPECIFIER_SAMPLERCUBE: - spec->type = SLANG_SPEC_SAMPLER_CUBE; - break; - case TYPE_SPECIFIER_SAMPLER2DRECT: - spec->type = SLANG_SPEC_SAMPLER_RECT; - break; - case TYPE_SPECIFIER_SAMPLER1DSHADOW: - spec->type = SLANG_SPEC_SAMPLER_1D_SHADOW; - break; - case TYPE_SPECIFIER_SAMPLER2DSHADOW: - spec->type = SLANG_SPEC_SAMPLER_2D_SHADOW; - break; - case TYPE_SPECIFIER_SAMPLER2DRECTSHADOW: - spec->type = SLANG_SPEC_SAMPLER_RECT_SHADOW; - break; - case TYPE_SPECIFIER_SAMPLER_1D_ARRAY: - spec->type = SLANG_SPEC_SAMPLER_1D_ARRAY; - break; - case TYPE_SPECIFIER_SAMPLER_2D_ARRAY: - spec->type = SLANG_SPEC_SAMPLER_2D_ARRAY; - break; - case TYPE_SPECIFIER_SAMPLER_1D_ARRAY_SHADOW: - spec->type = SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW; - break; - case TYPE_SPECIFIER_SAMPLER_2D_ARRAY_SHADOW: - spec->type = SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW; - break; - case TYPE_SPECIFIER_STRUCT: - spec->type = SLANG_SPEC_STRUCT; - if (!parse_struct(C, O, &spec->_struct)) - RETURN0; - break; - case TYPE_SPECIFIER_TYPENAME: - spec->type = SLANG_SPEC_STRUCT; - { - slang_atom a_name; - slang_struct *stru; - - a_name = parse_identifier(C); - if (a_name == NULL) - RETURN0; - - stru = slang_struct_scope_find(O->structs, a_name, 1); - if (stru == NULL) { - slang_info_log_error(C->L, "undeclared type name '%s'", - slang_atom_pool_id(C->atoms, a_name)); - RETURN0; - } - - spec->_struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); - if (spec->_struct == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - if (!slang_struct_construct(spec->_struct)) { - _slang_free(spec->_struct); - spec->_struct = NULL; - RETURN0; - } - if (!slang_struct_copy(spec->_struct, stru)) - RETURN0; - } - break; - default: - RETURN0; - } - return 1; -} - -#define TYPE_SPECIFIER_NONARRAY 0 -#define TYPE_SPECIFIER_ARRAY 1 - -static int -parse_type_array_size(slang_parse_ctx *C, - slang_output_ctx *O, - GLint *array_len) -{ - GLuint size; - - switch (*C->I++) { - case TYPE_SPECIFIER_NONARRAY: - *array_len = -1; /* -1 = not an array */ - break; - case TYPE_SPECIFIER_ARRAY: - if (!parse_array_len(C, O, &size)) - RETURN0; - *array_len = (GLint) size; - break; - default: - assert(0); - RETURN0; - } - return 1; -} - -#define PRECISION_DEFAULT 0 -#define PRECISION_LOW 1 -#define PRECISION_MEDIUM 2 -#define PRECISION_HIGH 3 - -static int -parse_type_precision(slang_parse_ctx *C, - slang_type_precision *precision) -{ - GLint prec = *C->I++; - switch (prec) { - case PRECISION_DEFAULT: - *precision = SLANG_PREC_DEFAULT; - return 1; - case PRECISION_LOW: - *precision = SLANG_PREC_LOW; - return 1; - case PRECISION_MEDIUM: - *precision = SLANG_PREC_MEDIUM; - return 1; - case PRECISION_HIGH: - *precision = SLANG_PREC_HIGH; - return 1; - default: - RETURN0; - } -} - - -/* parameter qualifier */ -#define PARAM_QUALIFIER_IN 0 -#define PARAM_QUALIFIER_OUT 1 -#define PARAM_QUALIFIER_INOUT 2 -#define PARAM_QUALIFIER_NONE 3 -static int -parse_varying_qualifier(slang_parse_ctx * C, slang_fully_specified_type *type) -{ - int param_qual = *C->I++; - - if (type->qualifier != SLANG_QUAL_VARYING && - param_qual != PARAM_QUALIFIER_NONE) { - slang_info_log_error(C->L, "Invalid type qualifier."); - RETURN0; - } - switch (param_qual) { - case PARAM_QUALIFIER_IN: - case PARAM_QUALIFIER_NONE: - type->varying_kind = SLANG_VARYING_IN; - break; - case PARAM_QUALIFIER_OUT: - type->varying_kind = SLANG_VARYING_OUT; - break; - case PARAM_QUALIFIER_INOUT: - slang_info_log_error(C->L, "Invalid type qualifier."); - RETURN0; - break; - default: - RETURN0; - } - return 1; -} - -static int -parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, - slang_fully_specified_type * type) -{ - if (!parse_layout_qualifiers(C, &type->layout)) - RETURN0; - - if (!parse_type_variant(C, &type->variant)) - RETURN0; - - if (!parse_type_centroid(C, &type->centroid)) - RETURN0; - - if (!parse_type_qualifier(C, &type->qualifier)) - RETURN0; - - if (!parse_varying_qualifier(C, type)) - RETURN0; - - if (!parse_type_precision(C, &type->precision)) - RETURN0; - - if (!parse_type_specifier(C, O, &type->specifier)) - RETURN0; - - if (!parse_type_array_size(C, O, &type->array_len)) - RETURN0; - - if (!O->allow_invariant && type->variant == SLANG_INVARIANT) { - slang_info_log_error(C->L, - "'invariant' keyword not allowed (perhaps set #version 120)"); - RETURN0; - } - - if (!O->allow_centroid && type->centroid == SLANG_CENTROID) { - slang_info_log_error(C->L, - "'centroid' keyword not allowed (perhaps set #version 120)"); - RETURN0; - } - else if (type->centroid == SLANG_CENTROID && - type->qualifier != SLANG_QUAL_VARYING) { - slang_info_log_error(C->L, - "'centroid' keyword only allowed for varying vars"); - RETURN0; - } - - - /* need this? - if (type->qualifier != SLANG_QUAL_VARYING && - type->variant == SLANG_INVARIANT) { - slang_info_log_error(C->L, - "invariant qualifer only allowed for varying vars"); - RETURN0; - } - */ - - if (O->allow_precision) { - if (type->precision == SLANG_PREC_DEFAULT) { - assert(type->specifier.type < TYPE_SPECIFIER_COUNT); - /* use the default precision for this datatype */ - type->precision = O->default_precision[type->specifier.type]; - } - } - else { - /* only default is allowed */ - if (type->precision != SLANG_PREC_DEFAULT) { - slang_info_log_error(C->L, "precision qualifiers not allowed"); - RETURN0; - } - } - - if (!O->allow_array_types && type->array_len >= 0) { - slang_info_log_error(C->L, "first-class array types not allowed"); - RETURN0; - } - - if (type->array_len >= 0) { - /* convert type to array type (ex: convert "int" to "array of int" */ - promote_type_to_array(C, type, type->array_len); - } - - return 1; -} - -/* operation */ -#define OP_END 0 -#define OP_BLOCK_BEGIN_NO_NEW_SCOPE 1 -#define OP_BLOCK_BEGIN_NEW_SCOPE 2 -#define OP_DECLARE 3 -#define OP_ASM 4 -#define OP_BREAK 5 -#define OP_CONTINUE 6 -#define OP_DISCARD 7 -#define OP_RETURN 8 -#define OP_EXPRESSION 9 -#define OP_IF 10 -#define OP_WHILE 11 -#define OP_DO 12 -#define OP_FOR 13 -#define OP_PUSH_VOID 14 -#define OP_PUSH_BOOL 15 -#define OP_PUSH_INT 16 -#define OP_PUSH_FLOAT 17 -#define OP_PUSH_IDENTIFIER 18 -#define OP_SEQUENCE 19 -#define OP_ASSIGN 20 -#define OP_ADDASSIGN 21 -#define OP_SUBASSIGN 22 -#define OP_MULASSIGN 23 -#define OP_DIVASSIGN 24 -/*#define OP_MODASSIGN 25*/ -/*#define OP_LSHASSIGN 26*/ -/*#define OP_RSHASSIGN 27*/ -/*#define OP_ORASSIGN 28*/ -/*#define OP_XORASSIGN 29*/ -/*#define OP_ANDASSIGN 30*/ -#define OP_SELECT 31 -#define OP_LOGICALOR 32 -#define OP_LOGICALXOR 33 -#define OP_LOGICALAND 34 -/*#define OP_BITOR 35*/ -/*#define OP_BITXOR 36*/ -/*#define OP_BITAND 37*/ -#define OP_EQUAL 38 -#define OP_NOTEQUAL 39 -#define OP_LESS 40 -#define OP_GREATER 41 -#define OP_LESSEQUAL 42 -#define OP_GREATEREQUAL 43 -/*#define OP_LSHIFT 44*/ -/*#define OP_RSHIFT 45*/ -#define OP_ADD 46 -#define OP_SUBTRACT 47 -#define OP_MULTIPLY 48 -#define OP_DIVIDE 49 -/*#define OP_MODULUS 50*/ -#define OP_PREINCREMENT 51 -#define OP_PREDECREMENT 52 -#define OP_PLUS 53 -#define OP_MINUS 54 -/*#define OP_COMPLEMENT 55*/ -#define OP_NOT 56 -#define OP_SUBSCRIPT 57 -#define OP_CALL 58 -#define OP_FIELD 59 -#define OP_POSTINCREMENT 60 -#define OP_POSTDECREMENT 61 -#define OP_PRECISION 62 -#define OP_METHOD 63 - - -/** - * When parsing a compound production, this function is used to parse the - * children. - * For example, a while-loop compound will have two children, the - * while condition expression and the loop body. So, this function will - * be called twice to parse those two sub-expressions. - * \param C the parsing context - * \param O the output context - * \param oper the operation we're parsing - * \param statement indicates whether parsing a statement, or expression - * \return 1 if success, 0 if error - */ -static int -parse_child_operation(slang_parse_ctx * C, slang_output_ctx * O, - slang_operation * oper, GLboolean statement) -{ - slang_operation *ch; - - /* grow child array */ - ch = slang_operation_grow(&oper->num_children, &oper->children); - if (statement) - return parse_statement(C, O, ch); - return parse_expression(C, O, ch); -} - -static int parse_declaration(slang_parse_ctx * C, slang_output_ctx * O); - -static int -parse_statement(slang_parse_ctx * C, slang_output_ctx * O, - slang_operation * oper) -{ - int op; - - oper->locals->outer_scope = O->vars; - - op = *C->I++; - switch (op) { - case OP_BLOCK_BEGIN_NO_NEW_SCOPE: - /* parse child statements, do not create new variable scope */ - oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; - while (*C->I != OP_END) - if (!parse_child_operation(C, O, oper, GL_TRUE)) - RETURN0; - C->I++; - break; - case OP_BLOCK_BEGIN_NEW_SCOPE: - /* parse child statements, create new variable scope */ - { - slang_output_ctx o = *O; - - oper->type = SLANG_OPER_BLOCK_NEW_SCOPE; - o.vars = oper->locals; - while (*C->I != OP_END) - if (!parse_child_operation(C, &o, oper, GL_TRUE)) - RETURN0; - C->I++; - } - break; - case OP_DECLARE: - /* local variable declaration, individual declarators are stored as - * children identifiers - */ - oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; - { - const unsigned int first_var = O->vars->num_variables; - - /* parse the declaration, note that there can be zero or more - * than one declarators - */ - if (!parse_declaration(C, O)) - RETURN0; - if (first_var < O->vars->num_variables) { - const unsigned int num_vars = O->vars->num_variables - first_var; - unsigned int i; - assert(oper->num_children == 0); - oper->num_children = num_vars; - oper->children = slang_operation_new(num_vars); - if (oper->children == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - for (i = first_var; i < O->vars->num_variables; i++) { - slang_operation *o = &oper->children[i - first_var]; - slang_variable *var = O->vars->variables[i]; - o->type = SLANG_OPER_VARIABLE_DECL; - o->locals->outer_scope = O->vars; - o->a_id = var->a_name; - - /* new/someday... - calculate_var_size(C, O, var); - */ - - if (!legal_identifier(o->a_id)) { - slang_info_log_error(C->L, "illegal variable name '%s'", - (char *) o->a_id); - RETURN0; - } - } - } - } - break; - case OP_ASM: - /* the __asm statement, parse the mnemonic and all its arguments - * as expressions - */ - oper->type = SLANG_OPER_ASM; - oper->a_id = parse_identifier(C); - if (oper->a_id == SLANG_ATOM_NULL) - RETURN0; - while (*C->I != OP_END) { - if (!parse_child_operation(C, O, oper, GL_FALSE)) - RETURN0; - } - C->I++; - break; - case OP_BREAK: - oper->type = SLANG_OPER_BREAK; - break; - case OP_CONTINUE: - oper->type = SLANG_OPER_CONTINUE; - break; - case OP_DISCARD: - oper->type = SLANG_OPER_DISCARD; - break; - case OP_RETURN: - oper->type = SLANG_OPER_RETURN; - if (!parse_child_operation(C, O, oper, GL_FALSE)) - RETURN0; - break; - case OP_EXPRESSION: - oper->type = SLANG_OPER_EXPRESSION; - if (!parse_child_operation(C, O, oper, GL_FALSE)) - RETURN0; - break; - case OP_IF: - oper->type = SLANG_OPER_IF; - if (!parse_child_operation(C, O, oper, GL_FALSE)) - RETURN0; - if (!parse_child_operation(C, O, oper, GL_TRUE)) - RETURN0; - if (!parse_child_operation(C, O, oper, GL_TRUE)) - RETURN0; - break; - case OP_WHILE: - { - slang_output_ctx o = *O; - - oper->type = SLANG_OPER_WHILE; - o.vars = oper->locals; - if (!parse_child_operation(C, &o, oper, GL_TRUE)) - RETURN0; - if (!parse_child_operation(C, &o, oper, GL_TRUE)) - RETURN0; - } - break; - case OP_DO: - oper->type = SLANG_OPER_DO; - if (!parse_child_operation(C, O, oper, GL_TRUE)) - RETURN0; - if (!parse_child_operation(C, O, oper, GL_FALSE)) - RETURN0; - break; - case OP_FOR: - { - slang_output_ctx o = *O; - - oper->type = SLANG_OPER_FOR; - o.vars = oper->locals; - if (!parse_child_operation(C, &o, oper, GL_TRUE)) - RETURN0; - if (!parse_child_operation(C, &o, oper, GL_TRUE)) - RETURN0; - if (!parse_child_operation(C, &o, oper, GL_FALSE)) - RETURN0; - if (!parse_child_operation(C, &o, oper, GL_TRUE)) - RETURN0; - } - break; - case OP_PRECISION: - { - /* set default precision for a type in this scope */ - /* ignored at this time */ - int prec_qual = *C->I++; - int datatype = *C->I++; - (void) prec_qual; - (void) datatype; - } - break; - default: - /*printf("Unexpected operation %d\n", op);*/ - RETURN0; - } - return 1; -} - -static int -handle_nary_expression(slang_parse_ctx * C, slang_operation * op, - slang_operation ** ops, unsigned int *total_ops, - unsigned int n) -{ - unsigned int i; - - op->children = slang_operation_new(n); - if (op->children == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - op->num_children = n; - - for (i = 0; i < n; i++) { - slang_operation_destruct(&op->children[i]); - op->children[i] = (*ops)[*total_ops - (n + 1 - i)]; - } - - (*ops)[*total_ops - (n + 1)] = (*ops)[*total_ops - 1]; - *total_ops -= n; - - *ops = (slang_operation *) - _slang_realloc(*ops, - (*total_ops + n) * sizeof(slang_operation), - *total_ops * sizeof(slang_operation)); - if (*ops == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - return 1; -} - -static int -is_constructor_name(const char *name, slang_atom a_name, - slang_struct_scope * structs) -{ - if (slang_type_specifier_type_from_string(name) != SLANG_SPEC_VOID) - return 1; - return slang_struct_scope_find(structs, a_name, 1) != NULL; -} - -#define FUNCTION_CALL_NONARRAY 0 -#define FUNCTION_CALL_ARRAY 1 - -static int -parse_expression(slang_parse_ctx * C, slang_output_ctx * O, - slang_operation * oper) -{ - slang_operation *ops = NULL; - unsigned int num_ops = 0; - int number; - - while (*C->I != OP_END) { - slang_operation *op; - const unsigned int op_code = *C->I++; - - /* allocate default operation, becomes a no-op if not used */ - ops = (slang_operation *) - _slang_realloc(ops, - num_ops * sizeof(slang_operation), - (num_ops + 1) * sizeof(slang_operation)); - if (ops == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - op = &ops[num_ops]; - if (!slang_operation_construct(op)) { - slang_info_log_memory(C->L); - RETURN0; - } - num_ops++; - op->locals->outer_scope = O->vars; - - switch (op_code) { - case OP_PUSH_VOID: - op->type = SLANG_OPER_VOID; - break; - case OP_PUSH_BOOL: - op->type = SLANG_OPER_LITERAL_BOOL; - if (!parse_number(C, &number)) - RETURN0; - op->literal[0] = - op->literal[1] = - op->literal[2] = - op->literal[3] = (GLfloat) number; - op->literal_size = 1; - break; - case OP_PUSH_INT: - op->type = SLANG_OPER_LITERAL_INT; - if (!parse_number(C, &number)) - RETURN0; - op->literal[0] = - op->literal[1] = - op->literal[2] = - op->literal[3] = (GLfloat) number; - op->literal_size = 1; - break; - case OP_PUSH_FLOAT: - op->type = SLANG_OPER_LITERAL_FLOAT; - if (!parse_float(C, &op->literal[0])) - RETURN0; - op->literal[1] = - op->literal[2] = - op->literal[3] = op->literal[0]; - op->literal_size = 1; - break; - case OP_PUSH_IDENTIFIER: - op->type = SLANG_OPER_IDENTIFIER; - op->a_id = parse_identifier(C); - if (op->a_id == SLANG_ATOM_NULL) - RETURN0; - break; - case OP_SEQUENCE: - op->type = SLANG_OPER_SEQUENCE; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_ASSIGN: - op->type = SLANG_OPER_ASSIGN; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_ADDASSIGN: - op->type = SLANG_OPER_ADDASSIGN; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_SUBASSIGN: - op->type = SLANG_OPER_SUBASSIGN; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_MULASSIGN: - op->type = SLANG_OPER_MULASSIGN; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_DIVASSIGN: - op->type = SLANG_OPER_DIVASSIGN; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - /*case OP_MODASSIGN: */ - /*case OP_LSHASSIGN: */ - /*case OP_RSHASSIGN: */ - /*case OP_ORASSIGN: */ - /*case OP_XORASSIGN: */ - /*case OP_ANDASSIGN: */ - case OP_SELECT: - op->type = SLANG_OPER_SELECT; - if (!handle_nary_expression(C, op, &ops, &num_ops, 3)) - RETURN0; - break; - case OP_LOGICALOR: - op->type = SLANG_OPER_LOGICALOR; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_LOGICALXOR: - op->type = SLANG_OPER_LOGICALXOR; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_LOGICALAND: - op->type = SLANG_OPER_LOGICALAND; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - /*case OP_BITOR: */ - /*case OP_BITXOR: */ - /*case OP_BITAND: */ - case OP_EQUAL: - op->type = SLANG_OPER_EQUAL; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_NOTEQUAL: - op->type = SLANG_OPER_NOTEQUAL; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_LESS: - op->type = SLANG_OPER_LESS; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_GREATER: - op->type = SLANG_OPER_GREATER; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_LESSEQUAL: - op->type = SLANG_OPER_LESSEQUAL; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_GREATEREQUAL: - op->type = SLANG_OPER_GREATEREQUAL; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - /*case OP_LSHIFT: */ - /*case OP_RSHIFT: */ - case OP_ADD: - op->type = SLANG_OPER_ADD; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_SUBTRACT: - op->type = SLANG_OPER_SUBTRACT; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_MULTIPLY: - op->type = SLANG_OPER_MULTIPLY; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_DIVIDE: - op->type = SLANG_OPER_DIVIDE; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - /*case OP_MODULUS: */ - case OP_PREINCREMENT: - op->type = SLANG_OPER_PREINCREMENT; - if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - RETURN0; - break; - case OP_PREDECREMENT: - op->type = SLANG_OPER_PREDECREMENT; - if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - RETURN0; - break; - case OP_PLUS: - op->type = SLANG_OPER_PLUS; - if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - RETURN0; - break; - case OP_MINUS: - op->type = SLANG_OPER_MINUS; - if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - RETURN0; - break; - case OP_NOT: - op->type = SLANG_OPER_NOT; - if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - RETURN0; - break; - /*case OP_COMPLEMENT: */ - case OP_SUBSCRIPT: - op->type = SLANG_OPER_SUBSCRIPT; - if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - RETURN0; - break; - case OP_METHOD: - op->type = SLANG_OPER_METHOD; - op->a_obj = parse_identifier(C); - if (op->a_obj == SLANG_ATOM_NULL) - RETURN0; - - op->a_id = parse_identifier(C); - if (op->a_id == SLANG_ATOM_NULL) - RETURN0; - - assert(*C->I == OP_END); - C->I++; - - while (*C->I != OP_END) - if (!parse_child_operation(C, O, op, GL_FALSE)) - RETURN0; - C->I++; -#if 0 - /* don't lookup the method (not yet anyway) */ - if (!C->parsing_builtin - && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) { - const char *id; - - id = slang_atom_pool_id(C->atoms, op->a_id); - if (!is_constructor_name(id, op->a_id, O->structs)) { - slang_info_log_error(C->L, "%s: undeclared function name.", id); - RETURN0; - } - } -#endif - break; - case OP_CALL: - { - GLboolean array_constructor = GL_FALSE; - GLint array_constructor_size = 0; - - op->type = SLANG_OPER_CALL; - op->a_id = parse_identifier(C); - if (op->a_id == SLANG_ATOM_NULL) - RETURN0; - switch (*C->I++) { - case FUNCTION_CALL_NONARRAY: - /* Nothing to do. */ - break; - case FUNCTION_CALL_ARRAY: - /* Calling an array constructor. For example: - * float[3](1.1, 2.2, 3.3); - */ - if (!O->allow_array_types) { - slang_info_log_error(C->L, - "array constructors not allowed " - "in this GLSL version"); - RETURN0; - } - else { - /* parse the array constructor size */ - slang_operation array_size; - array_constructor = GL_TRUE; - slang_operation_construct(&array_size); - if (!parse_expression(C, O, &array_size)) { - slang_operation_destruct(&array_size); - return GL_FALSE; - } - if (array_size.type != SLANG_OPER_LITERAL_INT) { - slang_info_log_error(C->L, - "constructor array size is not an integer"); - slang_operation_destruct(&array_size); - RETURN0; - } - array_constructor_size = (int) array_size.literal[0]; - op->array_constructor = GL_TRUE; - slang_operation_destruct(&array_size); - } - break; - default: - assert(0); - RETURN0; - } - while (*C->I != OP_END) - if (!parse_child_operation(C, O, op, GL_FALSE)) - RETURN0; - C->I++; - - if (array_constructor && - array_constructor_size != op->num_children) { - slang_info_log_error(C->L, "number of parameters to array" - " constructor does not match array size"); - RETURN0; - } - - if (!C->parsing_builtin - && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) { - const char *id; - - id = slang_atom_pool_id(C->atoms, op->a_id); - if (!is_constructor_name(id, op->a_id, O->structs)) { - slang_info_log_error(C->L, "%s: undeclared function name.", id); - RETURN0; - } - } - } - break; - case OP_FIELD: - op->type = SLANG_OPER_FIELD; - op->a_id = parse_identifier(C); - if (op->a_id == SLANG_ATOM_NULL) - RETURN0; - if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - RETURN0; - break; - case OP_POSTINCREMENT: - op->type = SLANG_OPER_POSTINCREMENT; - if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - RETURN0; - break; - case OP_POSTDECREMENT: - op->type = SLANG_OPER_POSTDECREMENT; - if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - RETURN0; - break; - default: - RETURN0; - } - } - C->I++; - - slang_operation_destruct(oper); - *oper = *ops; /* struct copy */ - _slang_free(ops); - - return 1; -} - -/* function parameter array presence */ -#define PARAMETER_ARRAY_NOT_PRESENT 0 -#define PARAMETER_ARRAY_PRESENT 1 - -static int -parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, - slang_variable * param) -{ - int param_qual, precision_qual; - - /* parse and validate the parameter's type qualifiers (there can be - * two at most) because not all combinations are valid - */ - if (!parse_type_qualifier(C, ¶m->type.qualifier)) - RETURN0; - - param_qual = *C->I++; - switch (param_qual) { - case PARAM_QUALIFIER_IN: - if (param->type.qualifier != SLANG_QUAL_CONST - && param->type.qualifier != SLANG_QUAL_NONE) { - slang_info_log_error(C->L, "Invalid type qualifier."); - RETURN0; - } - break; - case PARAM_QUALIFIER_OUT: - if (param->type.qualifier == SLANG_QUAL_NONE) - param->type.qualifier = SLANG_QUAL_OUT; - else { - slang_info_log_error(C->L, "Invalid type qualifier."); - RETURN0; - } - break; - case PARAM_QUALIFIER_INOUT: - if (param->type.qualifier == SLANG_QUAL_NONE) - param->type.qualifier = SLANG_QUAL_INOUT; - else { - slang_info_log_error(C->L, "Invalid type qualifier."); - RETURN0; - } - break; - case PARAM_QUALIFIER_NONE: - /* like IN but doesn't throw error */ - break; - default: - RETURN0; - } - - /* parse precision qualifier (lowp, mediump, highp */ - precision_qual = *C->I++; - /* ignored at this time */ - (void) precision_qual; - - /* parse parameter's type specifier and name */ - if (!parse_type_specifier(C, O, ¶m->type.specifier)) - RETURN0; - if (!parse_type_array_size(C, O, ¶m->type.array_len)) - RETURN0; - param->a_name = parse_identifier(C); - if (param->a_name == SLANG_ATOM_NULL) - RETURN0; - - /* first-class array - */ - if (param->type.array_len >= 0) { - slang_type_specifier p; - - slang_type_specifier_ctr(&p); - if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) { - slang_type_specifier_dtr(&p); - RETURN0; - } - if (!convert_to_array(C, param, &p)) { - slang_type_specifier_dtr(&p); - RETURN0; - } - slang_type_specifier_dtr(&p); - param->array_len = param->type.array_len; - } - - /* if the parameter is an array, parse its size (the size must be - * explicitly defined - */ - if (*C->I++ == PARAMETER_ARRAY_PRESENT) { - slang_type_specifier p; - - if (param->type.array_len >= 0) { - slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); - RETURN0; - } - slang_type_specifier_ctr(&p); - if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) { - slang_type_specifier_dtr(&p); - RETURN0; - } - if (!convert_to_array(C, param, &p)) { - slang_type_specifier_dtr(&p); - RETURN0; - } - slang_type_specifier_dtr(&p); - if (!parse_array_len(C, O, ¶m->array_len)) - RETURN0; - } - -#if 0 - /* calculate the parameter size */ - if (!calculate_var_size(C, O, param)) - RETURN0; -#endif - /* TODO: allocate the local address here? */ - return 1; -} - -/* function type */ -#define FUNCTION_ORDINARY 0 -#define FUNCTION_CONSTRUCTOR 1 -#define FUNCTION_OPERATOR 2 - -/* function parameter */ -#define PARAMETER_NONE 0 -#define PARAMETER_NEXT 1 - -/* operator type */ -#define OPERATOR_ADDASSIGN 1 -#define OPERATOR_SUBASSIGN 2 -#define OPERATOR_MULASSIGN 3 -#define OPERATOR_DIVASSIGN 4 -/*#define OPERATOR_MODASSIGN 5*/ -/*#define OPERATOR_LSHASSIGN 6*/ -/*#define OPERATOR_RSHASSIGN 7*/ -/*#define OPERATOR_ANDASSIGN 8*/ -/*#define OPERATOR_XORASSIGN 9*/ -/*#define OPERATOR_ORASSIGN 10*/ -#define OPERATOR_LOGICALXOR 11 -/*#define OPERATOR_BITOR 12*/ -/*#define OPERATOR_BITXOR 13*/ -/*#define OPERATOR_BITAND 14*/ -#define OPERATOR_LESS 15 -#define OPERATOR_GREATER 16 -#define OPERATOR_LESSEQUAL 17 -#define OPERATOR_GREATEREQUAL 18 -/*#define OPERATOR_LSHIFT 19*/ -/*#define OPERATOR_RSHIFT 20*/ -#define OPERATOR_MULTIPLY 21 -#define OPERATOR_DIVIDE 22 -/*#define OPERATOR_MODULUS 23*/ -#define OPERATOR_INCREMENT 24 -#define OPERATOR_DECREMENT 25 -#define OPERATOR_PLUS 26 -#define OPERATOR_MINUS 27 -/*#define OPERATOR_COMPLEMENT 28*/ -#define OPERATOR_NOT 29 - -static const struct -{ - unsigned int o_code; - const char *o_name; -} operator_names[] = { - {OPERATOR_INCREMENT, "++"}, - {OPERATOR_ADDASSIGN, "+="}, - {OPERATOR_PLUS, "+"}, - {OPERATOR_DECREMENT, "--"}, - {OPERATOR_SUBASSIGN, "-="}, - {OPERATOR_MINUS, "-"}, - {OPERATOR_NOT, "!"}, - {OPERATOR_MULASSIGN, "*="}, - {OPERATOR_MULTIPLY, "*"}, - {OPERATOR_DIVASSIGN, "/="}, - {OPERATOR_DIVIDE, "/"}, - {OPERATOR_LESSEQUAL, "<="}, - /*{ OPERATOR_LSHASSIGN, "<<=" }, */ - /*{ OPERATOR_LSHIFT, "<<" }, */ - {OPERATOR_LESS, "<"}, - {OPERATOR_GREATEREQUAL, ">="}, - /*{ OPERATOR_RSHASSIGN, ">>=" }, */ - /*{ OPERATOR_RSHIFT, ">>" }, */ - {OPERATOR_GREATER, ">"}, - /*{ OPERATOR_MODASSIGN, "%=" }, */ - /*{ OPERATOR_MODULUS, "%" }, */ - /*{ OPERATOR_ANDASSIGN, "&=" }, */ - /*{ OPERATOR_BITAND, "&" }, */ - /*{ OPERATOR_ORASSIGN, "|=" }, */ - /*{ OPERATOR_BITOR, "|" }, */ - /*{ OPERATOR_COMPLEMENT, "~" }, */ - /*{ OPERATOR_XORASSIGN, "^=" }, */ - {OPERATOR_LOGICALXOR, "^^"}, - /*{ OPERATOR_BITXOR, "^" } */ -}; - -static slang_atom -parse_operator_name(slang_parse_ctx * C) -{ - unsigned int i; - - for (i = 0; i < sizeof(operator_names) / sizeof(*operator_names); i++) { - if (operator_names[i].o_code == (unsigned int) (*C->I)) { - slang_atom atom = - slang_atom_pool_atom(C->atoms, operator_names[i].o_name); - if (atom == SLANG_ATOM_NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - C->I++; - return atom; - } - } - RETURN0; -} - - -static int -parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, - slang_function * func) -{ - GLuint functype; - /* parse function type and name */ - if (!parse_fully_specified_type(C, O, &func->header.type)) - RETURN0; - - functype = *C->I++; - switch (functype) { - case FUNCTION_ORDINARY: - func->kind = SLANG_FUNC_ORDINARY; - func->header.a_name = parse_identifier(C); - if (func->header.a_name == SLANG_ATOM_NULL) - RETURN0; - break; - case FUNCTION_CONSTRUCTOR: - func->kind = SLANG_FUNC_CONSTRUCTOR; - if (func->header.type.specifier.type == SLANG_SPEC_STRUCT) - RETURN0; - func->header.a_name = - slang_atom_pool_atom(C->atoms, - slang_type_specifier_type_to_string - (func->header.type.specifier.type)); - if (func->header.a_name == SLANG_ATOM_NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - break; - case FUNCTION_OPERATOR: - func->kind = SLANG_FUNC_OPERATOR; - func->header.a_name = parse_operator_name(C); - if (func->header.a_name == SLANG_ATOM_NULL) - RETURN0; - break; - default: - RETURN0; - } - - if (!legal_identifier(func->header.a_name)) { - slang_info_log_error(C->L, "illegal function name '%s'", - (char *) func->header.a_name); - RETURN0; - } - - /* parse function parameters */ - while (*C->I++ == PARAMETER_NEXT) { - slang_variable *p = slang_variable_scope_grow(func->parameters); - if (!p) { - slang_info_log_memory(C->L); - RETURN0; - } - if (!parse_parameter_declaration(C, O, p)) - RETURN0; - } - - /* if the function returns a value, append a hidden __retVal 'out' - * parameter that corresponds to the return value. - */ - if (_slang_function_has_return_value(func)) { - slang_variable *p = slang_variable_scope_grow(func->parameters); - slang_atom a_retVal = slang_atom_pool_atom(C->atoms, "__retVal"); - assert(a_retVal); - p->a_name = a_retVal; - p->type = func->header.type; - p->type.qualifier = SLANG_QUAL_OUT; - } - - /* function formal parameters and local variables share the same - * scope, so save the information about param count in a seperate - * place also link the scope to the global variable scope so when a - * given identifier is not found here, the search process continues - * in the global space - */ - func->param_count = func->parameters->num_variables; - func->parameters->outer_scope = O->vars; - - return 1; -} - -static int -parse_function_definition(slang_parse_ctx * C, slang_output_ctx * O, - slang_function * func) -{ - slang_output_ctx o = *O; - - if (!parse_function_prototype(C, O, func)) - RETURN0; - - /* create function's body operation */ - func->body = (slang_operation *) _slang_alloc(sizeof(slang_operation)); - if (func->body == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - if (!slang_operation_construct(func->body)) { - _slang_free(func->body); - func->body = NULL; - slang_info_log_memory(C->L); - RETURN0; - } - - /* to parse the body the parse context is modified in order to - * capture parsed variables into function's local variable scope - */ - C->global_scope = GL_FALSE; - o.vars = func->parameters; - if (!parse_statement(C, &o, func->body)) - RETURN0; - - C->global_scope = GL_TRUE; - return 1; -} - -static GLboolean -initialize_global(slang_assemble_ctx * A, slang_variable * var) -{ - slang_operation op_id, op_assign; - GLboolean result; - - /* construct the left side of assignment */ - if (!slang_operation_construct(&op_id)) - return GL_FALSE; - op_id.type = SLANG_OPER_IDENTIFIER; - op_id.a_id = var->a_name; - - /* put the variable into operation's scope */ - op_id.locals->variables = - (slang_variable **) _slang_alloc(sizeof(slang_variable *)); - if (op_id.locals->variables == NULL) { - slang_operation_destruct(&op_id); - return GL_FALSE; - } - op_id.locals->num_variables = 1; - op_id.locals->variables[0] = var; - - /* construct the assignment expression */ - if (!slang_operation_construct(&op_assign)) { - op_id.locals->num_variables = 0; - slang_operation_destruct(&op_id); - return GL_FALSE; - } - op_assign.type = SLANG_OPER_ASSIGN; - op_assign.children = - (slang_operation *) _slang_alloc(2 * sizeof(slang_operation)); - if (op_assign.children == NULL) { - slang_operation_destruct(&op_assign); - op_id.locals->num_variables = 0; - slang_operation_destruct(&op_id); - return GL_FALSE; - } - op_assign.num_children = 2; - op_assign.children[0] = op_id; - op_assign.children[1] = *var->initializer; - - result = 1; - - /* carefully destroy the operations */ - op_assign.num_children = 0; - _slang_free(op_assign.children); - op_assign.children = NULL; - slang_operation_destruct(&op_assign); - op_id.locals->num_variables = 0; - slang_operation_destruct(&op_id); - - if (!result) - return GL_FALSE; - - return GL_TRUE; -} - -/* init declarator list */ -#define DECLARATOR_NONE 0 -#define DECLARATOR_NEXT 1 - -/* variable declaration */ -#define VARIABLE_NONE 0 -#define VARIABLE_IDENTIFIER 1 -#define VARIABLE_INITIALIZER 2 -#define VARIABLE_ARRAY_EXPLICIT 3 -#define VARIABLE_ARRAY_UNKNOWN 4 - - -/** - * Check if it's OK to re-declare a variable with the given new type. - * This happens when applying layout qualifiers to gl_FragCoord or - * (re)setting an array size. - * If redeclaration is OK, return a pointer to the incoming variable - * updated with new type info. Else return NULL; - */ -static slang_variable * -redeclare_variable(slang_variable *var, - const slang_fully_specified_type *type) -{ - if (slang_fully_specified_types_compatible(&var->type, type)) { - /* replace orig var layout with new layout */ - var->type.layout = type->layout; - - /* XXX there may be other type updates in the future here */ - - return var; - } - else - return NULL; -} - - -/** - * Parse the initializer for a variable declaration. - */ -static int -parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, - const slang_fully_specified_type * type) -{ - GET_CURRENT_CONTEXT(ctx); /* a hack */ - slang_variable *var = NULL, *prevDecl; - slang_atom a_name; - - /* empty init declatator (without name, e.g. "float ;") */ - if (*C->I++ == VARIABLE_NONE) - return 1; - - a_name = parse_identifier(C); - - /* check if name is already in this scope */ - prevDecl = _slang_variable_locate(O->vars, a_name, C->global_scope); - if (prevDecl) { - /* A var with this name has already been declared. - * Check if redeclaring the var with a different type/layout is legal. - */ - if (C->global_scope) { - var = redeclare_variable(prevDecl, type); - } - if (!var) { - slang_info_log_error(C->L, - "declaration of '%s' conflicts with previous declaration", - (char *) a_name); - RETURN0; - } - } - - if (!var) { - /* make room for a new variable and initialize it */ - var = slang_variable_scope_grow(O->vars); - if (!var) { - slang_info_log_memory(C->L); - RETURN0; - } - - /* copy the declarator type qualifier/etc info, parse the identifier */ - var->type.qualifier = type->qualifier; - var->type.centroid = type->centroid; - var->type.precision = type->precision; - var->type.specifier = type->specifier;/*new*/ - var->type.variant = type->variant; - var->type.layout = type->layout; - var->type.array_len = type->array_len; - var->type.varying_kind = type->varying_kind; - var->a_name = a_name; - if (var->a_name == SLANG_ATOM_NULL) - RETURN0; - } - - switch (*C->I++) { - case VARIABLE_NONE: - /* simple variable declarator - just copy the specifier */ - if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) - RETURN0; - break; - case VARIABLE_INITIALIZER: - /* initialized variable - copy the specifier and parse the expression */ - if (0 && type->array_len >= 0) { - /* The type was something like "float[4]" */ - convert_to_array(C, var, &type->specifier); - var->array_len = type->array_len; - } - else { - if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) - RETURN0; - } - var->initializer = - (slang_operation *) _slang_alloc(sizeof(slang_operation)); - if (var->initializer == NULL) { - slang_info_log_memory(C->L); - RETURN0; - } - if (!slang_operation_construct(var->initializer)) { - _slang_free(var->initializer); - var->initializer = NULL; - slang_info_log_memory(C->L); - RETURN0; - } - if (!parse_expression(C, O, var->initializer)) - RETURN0; - break; - case VARIABLE_ARRAY_UNKNOWN: - /* unsized array - mark it as array and copy the specifier to - * the array element - */ - if (type->array_len >= 0) { - slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); - RETURN0; - } - if (!convert_to_array(C, var, &type->specifier)) - return GL_FALSE; - break; - case VARIABLE_ARRAY_EXPLICIT: - if (type->array_len >= 0) { - /* the user is trying to do something like: float[2] x[3]; */ - slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); - RETURN0; - } - if (!convert_to_array(C, var, &type->specifier)) - return GL_FALSE; - if (!parse_array_len(C, O, &var->array_len)) - return GL_FALSE; - break; - default: - RETURN0; - } - - /* allocate global address space for a variable with a known size */ - if (C->global_scope - && !(var->type.specifier.type == SLANG_SPEC_ARRAY - && var->array_len == 0)) { - if (!calculate_var_size(C, O, var)) - return GL_FALSE; - } - - /* emit code for global var decl */ - if (C->global_scope) { - slang_assemble_ctx A; - memset(&A, 0, sizeof(slang_assemble_ctx)); - A.allow_uniform_initializers = C->version > 110; - A.atoms = C->atoms; - A.space.funcs = O->funs; - A.space.structs = O->structs; - A.space.vars = O->vars; - A.program = O->program; - A.pragmas = O->pragmas; - A.vartable = O->vartable; - A.log = C->L; - A.curFuncEndLabel = NULL; - A.EmitContReturn = ctx->Shader.EmitContReturn; - if (!_slang_codegen_global_variable(&A, var, C->type)) - RETURN0; - } - - /* initialize global variable */ - if (C->global_scope) { - if (var->initializer != NULL) { - slang_assemble_ctx A; - memset(&A, 0, sizeof(slang_assemble_ctx)); - A.allow_uniform_initializers = C->version > 110; - A.atoms = C->atoms; - A.space.funcs = O->funs; - A.space.structs = O->structs; - A.space.vars = O->vars; - if (!initialize_global(&A, var)) - RETURN0; - } - } - - if (var->type.qualifier == SLANG_QUAL_FIXEDINPUT && - var->a_name == slang_atom_pool_atom(C->atoms, "gl_FragCoord")) { - /* set the program's PixelCenterInteger, OriginUpperLeft fields */ - struct gl_fragment_program *fragProg = - (struct gl_fragment_program *) O->program; - - if (var->type.layout & SLANG_LAYOUT_UPPER_LEFT_BIT) { - fragProg->OriginUpperLeft = GL_TRUE; - } - if (var->type.layout & SLANG_LAYOUT_PIXEL_CENTER_INTEGER_BIT) { - fragProg->PixelCenterInteger = GL_TRUE; - } - } - - return 1; -} - -/** - * Parse a list of variable declarations. Each variable may have an - * initializer. - */ -static int -parse_init_declarator_list(slang_parse_ctx * C, slang_output_ctx * O) -{ - slang_fully_specified_type type; - - /* parse the fully specified type, common to all declarators */ - if (!slang_fully_specified_type_construct(&type)) - RETURN0; - if (!parse_fully_specified_type(C, O, &type)) { - slang_fully_specified_type_destruct(&type); - RETURN0; - } - - /* parse declarators, pass-in the parsed type */ - do { - if (!parse_init_declarator(C, O, &type)) { - slang_fully_specified_type_destruct(&type); - RETURN0; - } - } - while (*C->I++ == DECLARATOR_NEXT); - - slang_fully_specified_type_destruct(&type); - return 1; -} - - -/** - * Parse a function definition or declaration. - * \param C parsing context - * \param O output context - * \param definition if non-zero expect a definition, else a declaration - * \param parsed_func_ret returns the parsed function - * \return GL_TRUE if success, GL_FALSE if failure - */ -static GLboolean -parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, - slang_function ** parsed_func_ret) -{ - slang_function parsed_func, *found_func; - - /* parse function definition/declaration */ - if (!slang_function_construct(&parsed_func)) - return GL_FALSE; - if (definition) { - if (!parse_function_definition(C, O, &parsed_func)) { - slang_function_destruct(&parsed_func); - return GL_FALSE; - } - } - else { - if (!parse_function_prototype(C, O, &parsed_func)) { - slang_function_destruct(&parsed_func); - return GL_FALSE; - } - } - - /* find a function with a prototype matching the parsed one - only - * the current scope is being searched to allow built-in function - * overriding - */ - found_func = slang_function_scope_find(O->funs, &parsed_func, 0); - if (found_func == NULL) { - /* New function, add it to the function list */ - O->funs->functions = - (slang_function *) _slang_realloc(O->funs->functions, - O->funs->num_functions - * sizeof(slang_function), - (O->funs->num_functions + 1) - * sizeof(slang_function)); - if (O->funs->functions == NULL) { - /* Make sure that there are no functions marked, as the - * allocation is currently NULL, in order to avoid - * a potental segfault as we clean up later. - */ - O->funs->num_functions = 0; - - slang_info_log_memory(C->L); - slang_function_destruct(&parsed_func); - return GL_FALSE; - } - O->funs->functions[O->funs->num_functions] = parsed_func; - O->funs->num_functions++; - - /* return the newly parsed function */ - *parsed_func_ret = &O->funs->functions[O->funs->num_functions - 1]; - } - else { - /* previously defined or declared */ - /* TODO: check function return type qualifiers and specifiers */ - if (definition) { - if (found_func->body != NULL) { - slang_info_log_error(C->L, "%s: function already has a body.", - slang_atom_pool_id(C->atoms, - parsed_func.header. - a_name)); - slang_function_destruct(&parsed_func); - return GL_FALSE; - } - - /* destroy the existing function declaration and replace it - * with the new one - */ - slang_function_destruct(found_func); - *found_func = parsed_func; - } - else { - /* another declaration of the same function prototype - ignore it */ - slang_function_destruct(&parsed_func); - } - - /* return the found function */ - *parsed_func_ret = found_func; - } - - return GL_TRUE; -} - -/* declaration */ -#define DECLARATION_FUNCTION_PROTOTYPE 1 -#define DECLARATION_INIT_DECLARATOR_LIST 2 - -static int -parse_declaration(slang_parse_ctx * C, slang_output_ctx * O) -{ - switch (*C->I++) { - case DECLARATION_INIT_DECLARATOR_LIST: - if (!parse_init_declarator_list(C, O)) - RETURN0; - break; - case DECLARATION_FUNCTION_PROTOTYPE: - { - slang_function *dummy_func; - - if (!parse_function(C, O, 0, &dummy_func)) - RETURN0; - } - break; - default: - RETURN0; - } - return 1; -} - -static int -parse_default_precision(slang_parse_ctx * C, slang_output_ctx * O) -{ - int precision, type; - - if (!O->allow_precision) { - slang_info_log_error(C->L, "syntax error at \"precision\""); - RETURN0; - } - - precision = *C->I++; - switch (precision) { - case PRECISION_LOW: - case PRECISION_MEDIUM: - case PRECISION_HIGH: - /* OK */ - break; - default: - _mesa_problem(NULL, "unexpected precision %d at %s:%d\n", - precision, __FILE__, __LINE__); - RETURN0; - } - - type = *C->I++; - switch (type) { - case TYPE_SPECIFIER_FLOAT: - case TYPE_SPECIFIER_INT: - case TYPE_SPECIFIER_SAMPLER1D: - case TYPE_SPECIFIER_SAMPLER2D: - case TYPE_SPECIFIER_SAMPLER3D: - case TYPE_SPECIFIER_SAMPLERCUBE: - case TYPE_SPECIFIER_SAMPLER1DSHADOW: - case TYPE_SPECIFIER_SAMPLER2DSHADOW: - case TYPE_SPECIFIER_SAMPLER2DRECT: - case TYPE_SPECIFIER_SAMPLER2DRECTSHADOW: - case TYPE_SPECIFIER_SAMPLER_1D_ARRAY: - case TYPE_SPECIFIER_SAMPLER_2D_ARRAY: - case TYPE_SPECIFIER_SAMPLER_1D_ARRAY_SHADOW: - case TYPE_SPECIFIER_SAMPLER_2D_ARRAY_SHADOW: - /* OK */ - break; - default: - _mesa_problem(NULL, "unexpected type %d at %s:%d\n", - type, __FILE__, __LINE__); - RETURN0; - } - - assert(type < TYPE_SPECIFIER_COUNT); - O->default_precision[type] = precision; - - return 1; -} - - -/** - * Initialize the default precision for all types. - * XXX this info isn't used yet. - */ -static void -init_default_precision(slang_output_ctx *O, slang_unit_type type) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint i; - for (i = 0; i < TYPE_SPECIFIER_COUNT; i++) { -#if FEATURE_es2_glsl - if (ctx->API == API_OPENGLES2) - O->default_precision[i] = PRECISION_LOW; - else - O->default_precision[i] = PRECISION_HIGH; -#else - (void) ctx; - O->default_precision[i] = PRECISION_HIGH; -#endif - } - - if (type == SLANG_UNIT_VERTEX_SHADER || type == SLANG_UNIT_GEOMETRY_SHADER) { - O->default_precision[TYPE_SPECIFIER_FLOAT] = PRECISION_HIGH; - O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_HIGH; - } - else { - O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_MEDIUM; - } -} - - -static int -parse_invariant(slang_parse_ctx * C, slang_output_ctx * O) -{ - if (O->allow_invariant) { - slang_atom *a = parse_identifier(C); - /* XXX not doing anything with this var yet */ - /*printf("ID: %s\n", (char*) a);*/ - return a ? 1 : 0; - } - else { - slang_info_log_error(C->L, "syntax error at \"invariant\""); - RETURN0; - } -} - - -/* external declaration or default precision specifier */ -#define EXTERNAL_NULL 0 -#define EXTERNAL_FUNCTION_DEFINITION 1 -#define EXTERNAL_DECLARATION 2 -#define DEFAULT_PRECISION 3 -#define INVARIANT_STMT 4 - - -static GLboolean -parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, - struct gl_shader *shader) -{ - GET_CURRENT_CONTEXT(ctx); - slang_output_ctx o; - GLboolean success; - GLuint maxRegs; - slang_function *mainFunc = NULL; - - if (unit->type == SLANG_UNIT_FRAGMENT_BUILTIN || - unit->type == SLANG_UNIT_FRAGMENT_SHADER) { - maxRegs = ctx->Const.FragmentProgram.MaxTemps; - } - else if (unit->type == SLANG_UNIT_VERTEX_BUILTIN || - unit->type == SLANG_UNIT_VERTEX_SHADER) { - maxRegs = ctx->Const.VertexProgram.MaxTemps; - } else { - assert(unit->type == SLANG_UNIT_GEOMETRY_BUILTIN || - unit->type == SLANG_UNIT_GEOMETRY_SHADER); - maxRegs = ctx->Const.GeometryProgram.MaxTemps; - } - - /* setup output context */ - o.funs = &unit->funs; - o.structs = &unit->structs; - o.vars = &unit->vars; - o.program = shader ? shader->Program : NULL; - o.pragmas = shader ? &shader->Pragmas : NULL; - o.vartable = _slang_new_var_table(maxRegs); - _slang_push_var_table(o.vartable); - - /* allow 'invariant' keyword? */ -#if FEATURE_es2_glsl - o.allow_invariant = - (ctx->API == API_OPENGLES2 || C->version >= 120) ? GL_TRUE : GL_FALSE; -#else - o.allow_invariant = (C->version >= 120) ? GL_TRUE : GL_FALSE; -#endif - - /* allow 'centroid' keyword? */ - o.allow_centroid = (C->version >= 120) ? GL_TRUE : GL_FALSE; - - /* allow 'lowp/mediump/highp' keywords? */ -#if FEATURE_es2_glsl - o.allow_precision = - (ctx->API == API_OPENGLES2 || C->version >= 120) ? GL_TRUE : GL_FALSE; -#else - o.allow_precision = (C->version >= 120) ? GL_TRUE : GL_FALSE; -#endif - init_default_precision(&o, unit->type); - - /* allow 'float[]' keyword? */ - o.allow_array_types = (C->version >= 120) ? GL_TRUE : GL_FALSE; - - /* parse individual functions and declarations */ - while (*C->I != EXTERNAL_NULL) { - switch (*C->I++) { - case EXTERNAL_FUNCTION_DEFINITION: - { - slang_function *func; - success = parse_function(C, &o, 1, &func); - if (success && strcmp((char *) func->header.a_name, "main") == 0) { - /* found main() */ - mainFunc = func; - } - } - break; - case EXTERNAL_DECLARATION: - success = parse_declaration(C, &o); - break; - case DEFAULT_PRECISION: - success = parse_default_precision(C, &o); - break; - case INVARIANT_STMT: - success = parse_invariant(C, &o); - break; - default: - success = GL_FALSE; - } - - if (!success) { - /* xxx free codegen */ - _slang_pop_var_table(o.vartable); - return GL_FALSE; - } - } - C->I++; - - if (mainFunc) { - /* assemble (generate code) for main() */ - slang_assemble_ctx A; - memset(&A, 0, sizeof(slang_assemble_ctx)); - A.atoms = C->atoms; - A.space.funcs = o.funs; - A.space.structs = o.structs; - A.space.vars = o.vars; - A.program = o.program; - A.pragmas = &shader->Pragmas; - A.vartable = o.vartable; - A.EmitContReturn = ctx->Shader.EmitContReturn; - A.log = C->L; - A.allow_uniform_initializers = C->version > 110; - - /* main() takes no parameters */ - if (mainFunc->param_count > 0) { - slang_info_log_error(A.log, "main() takes no arguments"); - return GL_FALSE; - } - - _slang_codegen_function(&A, mainFunc); - - shader->Main = GL_TRUE; /* this shader defines main() */ - - shader->UnresolvedRefs = A.UnresolvedRefs; - } - - _slang_pop_var_table(o.vartable); - _slang_delete_var_table(o.vartable); - - return GL_TRUE; -} - -static GLboolean -compile_binary(const unsigned char * prod, slang_code_unit * unit, - GLuint version, - slang_unit_type type, slang_info_log * infolog, - slang_code_unit * builtin, slang_code_unit * downlink, - struct gl_shader *shader) -{ - slang_parse_ctx C; - - unit->type = type; - - /* setup parse context */ - C.I = prod; - C.L = infolog; - C.parsing_builtin = (builtin == NULL); - C.global_scope = GL_TRUE; - C.atoms = &unit->object->atompool; - C.type = type; - C.version = version; - - if (!check_revision(&C)) - return GL_FALSE; - - if (downlink != NULL) { - unit->vars.outer_scope = &downlink->vars; - unit->funs.outer_scope = &downlink->funs; - unit->structs.outer_scope = &downlink->structs; - } - - /* parse translation unit */ - return parse_code_unit(&C, unit, shader); -} - -static GLboolean -compile_with_grammar(const char *source, - slang_code_unit *unit, - slang_unit_type type, - slang_info_log *infolog, - slang_code_unit *builtin, - struct gl_shader *shader, - struct gl_sl_pragmas *pragmas, - unsigned int shader_type, - unsigned int parsing_builtin) -{ - GET_CURRENT_CONTEXT(ctx); - struct sl_pp_purify_options options; - struct sl_pp_context *context; - unsigned char *prod; - GLuint size; - unsigned int version; - unsigned int maxVersion; - int result; - char errmsg[200] = ""; - - assert(shader_type == 1 || shader_type == 2); - - memset(&options, 0, sizeof(options)); - - context = sl_pp_context_create(source, &options); - if (!context) { - slang_info_log_error(infolog, "out of memory"); - return GL_FALSE; - } - - if (sl_pp_version(context, &version)) { - slang_info_log_error(infolog, "%s", sl_pp_context_error_message(context)); - sl_pp_context_destroy(context); - return GL_FALSE; - } - - if (sl_pp_context_add_extension(context, "GL_ARB_draw_buffers") || - sl_pp_context_add_extension(context, "GL_ARB_texture_rectangle")) { - slang_info_log_error(infolog, "%s", sl_pp_context_error_message(context)); - sl_pp_context_destroy(context); - return GL_FALSE; - } - - if (type == SLANG_UNIT_FRAGMENT_SHADER) { - sl_pp_context_add_extension(context, "GL_ARB_fragment_coord_conventions"); - } - - -#if FEATURE_es2_glsl - if (ctx->API == API_OPENGLES2) { - if (sl_pp_context_add_predefined(context, "GL_ES", "1") || - sl_pp_context_add_predefined(context, "GL_FRAGMENT_PRECISION_HIGH", "1")) { - slang_info_log_error(infolog, "%s", sl_pp_context_error_message(context)); - sl_pp_context_destroy(context); - return GL_FALSE; - } - } -#else - (void) ctx; -#endif - -#if FEATURE_ARB_shading_language_120 - maxVersion = 120; -#elif FEATURE_es2_glsl - maxVersion = 100; -#else - maxVersion = 110; -#endif - - if (version > maxVersion || - (version != 100 && version != 110 && version != 120)) { - slang_info_log_error(infolog, - "language version %.2f is not supported.", - version * 0.01); - sl_pp_context_destroy(context); - return GL_FALSE; - } - - /* Finally check the syntax and generate its binary representation. */ - result = sl_cl_compile(context, - shader_type, - parsing_builtin, - &prod, - &size, - errmsg, - sizeof(errmsg)); - - sl_pp_context_destroy(context); - - if (result) { - /*GLint pos;*/ - - slang_info_log_error(infolog, errmsg); - /* syntax error (possibly in library code) */ -#if 0 - { - int line, col; - char *s; - s = (char *) _mesa_find_line_column((const GLubyte *) source, - (const GLubyte *) source + pos, - &line, &col); - printf("Error on line %d, col %d: %s\n", line, col, s); - } -#endif - return GL_FALSE; - } - - /* Syntax is okay - translate it to internal representation. */ - if (!compile_binary(prod, unit, version, type, infolog, builtin, - &builtin[SLANG_BUILTIN_TOTAL - 1], - shader)) { - free(prod); - return GL_FALSE; - } - free(prod); - return GL_TRUE; -} - -static const unsigned char slang_core_gc[] = { -#include "library/slang_core_gc.h" -}; - -static const unsigned char slang_120_core_gc[] = { -#include "library/slang_120_core_gc.h" -}; - -static const unsigned char slang_120_fragment_gc[] = { -#include "library/slang_builtin_120_fragment_gc.h" -}; - -static const unsigned char slang_common_builtin_gc[] = { -#include "library/slang_common_builtin_gc.h" -}; - -static const unsigned char slang_fragment_builtin_gc[] = { -#include "library/slang_fragment_builtin_gc.h" -}; - -static const unsigned char slang_vertex_builtin_gc[] = { -#include "library/slang_vertex_builtin_gc.h" -}; - -static const unsigned char slang_geometry_builtin_gc[] = { -#include "library/slang_geometry_builtin_gc.h" -}; - -static GLboolean -compile_object(const char *source, - slang_code_object *object, - slang_unit_type type, - slang_info_log *infolog, - struct gl_shader *shader, - struct gl_sl_pragmas *pragmas) -{ - slang_code_unit *builtins = NULL; - GLuint base_version = 110; - unsigned int shader_type; - unsigned int parsing_builtin; - - /* set shader type - the syntax is slightly different for different shaders */ - if (type == SLANG_UNIT_FRAGMENT_SHADER || type == SLANG_UNIT_FRAGMENT_BUILTIN) { - shader_type = 1; - } else { - shader_type = 2; - } - - /* enable language extensions */ - parsing_builtin = 1; - - /* if parsing user-specified shader, load built-in library */ - if (type == SLANG_UNIT_FRAGMENT_SHADER || type == SLANG_UNIT_VERTEX_SHADER || - type == SLANG_UNIT_GEOMETRY_SHADER) { - /* compile core functionality first */ - if (!compile_binary(slang_core_gc, - &object->builtin[SLANG_BUILTIN_CORE], - base_version, - SLANG_UNIT_FRAGMENT_BUILTIN, infolog, - NULL, NULL, NULL)) - return GL_FALSE; - -#if FEATURE_ARB_shading_language_120 - if (!compile_binary(slang_120_core_gc, - &object->builtin[SLANG_BUILTIN_120_CORE], - 120, - SLANG_UNIT_FRAGMENT_BUILTIN, infolog, - NULL, &object->builtin[SLANG_BUILTIN_CORE], NULL)) - return GL_FALSE; -#endif - - /* compile common functions and variables, link to core */ - if (!compile_binary(slang_common_builtin_gc, - &object->builtin[SLANG_BUILTIN_COMMON], -#if FEATURE_ARB_shading_language_120 - 120, -#else - base_version, -#endif - SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, -#if FEATURE_ARB_shading_language_120 - &object->builtin[SLANG_BUILTIN_120_CORE], -#else - &object->builtin[SLANG_BUILTIN_CORE], -#endif - NULL)) - return GL_FALSE; - - /* compile target-specific functions and variables, link to common */ - if (type == SLANG_UNIT_FRAGMENT_SHADER) { - if (!compile_binary(slang_fragment_builtin_gc, - &object->builtin[SLANG_BUILTIN_TARGET], - base_version, - SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, - &object->builtin[SLANG_BUILTIN_COMMON], NULL)) - return GL_FALSE; -#if FEATURE_ARB_shading_language_120 - if (!compile_binary(slang_120_fragment_gc, - &object->builtin[SLANG_BUILTIN_TARGET], - 120, - SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, - &object->builtin[SLANG_BUILTIN_COMMON], NULL)) - return GL_FALSE; -#endif - } - else if (type == SLANG_UNIT_VERTEX_SHADER) { - if (!compile_binary(slang_vertex_builtin_gc, - &object->builtin[SLANG_BUILTIN_TARGET], - base_version, - SLANG_UNIT_VERTEX_BUILTIN, infolog, NULL, - &object->builtin[SLANG_BUILTIN_COMMON], NULL)) - return GL_FALSE; - } -#if FEATURE_ARB_geometry_shader4 - else if (type == SLANG_UNIT_GEOMETRY_SHADER) { - if (!compile_binary(slang_geometry_builtin_gc, - &object->builtin[SLANG_BUILTIN_TARGET], - base_version, - SLANG_UNIT_GEOMETRY_BUILTIN, infolog, NULL, - &object->builtin[SLANG_BUILTIN_COMMON], NULL)) - return GL_FALSE; - } -#endif - - /* disable language extensions */ - parsing_builtin = 0; - - builtins = object->builtin; - } - - /* compile the actual shader - pass-in built-in library for external shader */ - return compile_with_grammar(source, - &object->unit, - type, - infolog, - builtins, - shader, - pragmas, - shader_type, - parsing_builtin); -} - - -GLboolean -_slang_compile(GLcontext *ctx, struct gl_shader *shader) -{ - GLboolean success; - slang_info_log info_log; - slang_code_object obj; - slang_unit_type type; - GLenum progTarget; - - if (shader->Type == GL_VERTEX_SHADER) { - type = SLANG_UNIT_VERTEX_SHADER; - } - else if (shader->Type == GL_FRAGMENT_SHADER) { - type = SLANG_UNIT_FRAGMENT_SHADER; - } else { - assert(shader->Type == GL_GEOMETRY_SHADER_ARB); - type = SLANG_UNIT_GEOMETRY_SHADER; - } - - if (!shader->Source) - return GL_FALSE; - - ctx->Shader.MemPool = _slang_new_mempool(1024*1024); - - shader->Main = GL_FALSE; - - /* free the shader's old instructions, etc */ - _mesa_reference_program(ctx, &shader->Program, NULL); - - /* allocate new GPU program, parameter lists, etc. */ - if (shader->Type == GL_VERTEX_SHADER) - progTarget = GL_VERTEX_PROGRAM_ARB; - else if (shader->Type == GL_FRAGMENT_SHADER) - progTarget = GL_FRAGMENT_PROGRAM_ARB; - else - progTarget = MESA_GEOMETRY_PROGRAM; - shader->Program = ctx->Driver.NewProgram(ctx, progTarget, 1); - shader->Program->Parameters = _mesa_new_parameter_list(); - shader->Program->Varying = _mesa_new_parameter_list(); - shader->Program->Attributes = _mesa_new_parameter_list(); - - slang_info_log_construct(&info_log); - _slang_code_object_ctr(&obj); - - success = compile_object(shader->Source, - &obj, - type, - &info_log, - shader, - &shader->Pragmas); - - /* free shader's prev info log */ - if (shader->InfoLog) { - free(shader->InfoLog); - shader->InfoLog = NULL; - } - - if (info_log.text) { - /* copy info-log string to shader object */ - shader->InfoLog = _mesa_strdup(info_log.text); - } - - if (info_log.error_flag) { - success = GL_FALSE; - } - - slang_info_log_destruct(&info_log); - _slang_code_object_dtr(&obj); - - _slang_delete_mempool((slang_mempool *) ctx->Shader.MemPool); - ctx->Shader.MemPool = NULL; - - /* remove any reads of output registers */ -#if 0 - printf("Pre-remove output reads:\n"); - _mesa_print_program(shader->Program); -#endif - _mesa_remove_output_reads(shader->Program, PROGRAM_OUTPUT); - if (shader->Type == GL_VERTEX_SHADER) { - /* and remove writes to varying vars in vertex programs */ - _mesa_remove_output_reads(shader->Program, PROGRAM_VARYING); - } -#if 0 - printf("Post-remove output reads:\n"); - _mesa_print_program(shader->Program); -#endif - - shader->CompileStatus = success; - - if (success) { - if (shader->Pragmas.Optimize && - (ctx->Shader.Flags & GLSL_NO_OPT) == 0) { - _mesa_optimize_program(ctx, shader->Program); - } - if ((ctx->Shader.Flags & GLSL_NOP_VERT) && - shader->Program->Target == GL_VERTEX_PROGRAM_ARB) { - _mesa_nop_vertex_program(ctx, - (struct gl_vertex_program *) shader->Program); - } - if ((ctx->Shader.Flags & GLSL_NOP_FRAG) && - shader->Program->Target == GL_FRAGMENT_PROGRAM_ARB) { - _mesa_nop_fragment_program(ctx, - (struct gl_fragment_program *) shader->Program); - } - } - - if (ctx->Shader.Flags & GLSL_LOG) { - _mesa_write_shader_to_file(shader); - } - - return success; -} - diff --git a/src/mesa/slang/slang_compile.h b/src/mesa/slang/slang_compile.h deleted file mode 100644 index 6061f878e7..0000000000 --- a/src/mesa/slang/slang_compile.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#if !defined SLANG_COMPILE_H -#define SLANG_COMPILE_H - -#include "main/glheader.h" -#include "main/mtypes.h" -#include "slang_compile_function.h" -#include "slang_compile_struct.h" -#include "slang_compile_variable.h" -#include "slang_utility.h" - -struct slang_code_object_; - -#if defined __cplusplus -extern "C" { -#endif - -typedef struct slang_name_space_ -{ - struct slang_function_scope_ *funcs; - struct slang_struct_scope_ *structs; - struct slang_variable_scope_ *vars; -} slang_name_space; - -typedef enum slang_unit_type_ -{ - SLANG_UNIT_FRAGMENT_SHADER, - SLANG_UNIT_VERTEX_SHADER, - SLANG_UNIT_GEOMETRY_SHADER, - SLANG_UNIT_FRAGMENT_BUILTIN, - SLANG_UNIT_VERTEX_BUILTIN, - SLANG_UNIT_GEOMETRY_BUILTIN -} slang_unit_type; - - -typedef struct slang_code_unit_ -{ - slang_variable_scope vars; - slang_function_scope funs; - slang_struct_scope structs; - slang_unit_type type; - struct slang_code_object_ *object; -} slang_code_unit; - - -extern GLvoid -_slang_code_unit_ctr (slang_code_unit *, struct slang_code_object_ *); - -extern GLvoid -_slang_code_unit_dtr (slang_code_unit *); - -#define SLANG_BUILTIN_CORE 0 -#define SLANG_BUILTIN_120_CORE 1 -#define SLANG_BUILTIN_COMMON 2 -#define SLANG_BUILTIN_TARGET 3 - -#define SLANG_BUILTIN_TOTAL 4 - -typedef struct slang_code_object_ -{ - slang_code_unit builtin[SLANG_BUILTIN_TOTAL]; - slang_code_unit unit; - slang_atom_pool atompool; -} slang_code_object; - -extern GLvoid -_slang_code_object_ctr (slang_code_object *); - -extern GLvoid -_slang_code_object_dtr (slang_code_object *); - -extern GLboolean -_slang_compile (GLcontext *ctx, struct gl_shader *shader); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/src/mesa/slang/slang_compile_function.c b/src/mesa/slang/slang_compile_function.c deleted file mode 100644 index 4dd885176d..0000000000 --- a/src/mesa/slang/slang_compile_function.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_compile_function.c - * slang front-end compiler - * \author Michal Krol - */ - -#include "main/imports.h" -#include "slang_compile.h" -#include "slang_mem.h" - - -int -slang_function_construct(slang_function * func) -{ - func->kind = SLANG_FUNC_ORDINARY; - if (!slang_variable_construct(&func->header)) - return 0; - - func->parameters = (slang_variable_scope *) - _slang_alloc(sizeof(slang_variable_scope)); - if (func->parameters == NULL) { - slang_variable_destruct(&func->header); - return 0; - } - - _slang_variable_scope_ctr(func->parameters); - func->param_count = 0; - func->body = NULL; - return 1; -} - -void -slang_function_destruct(slang_function * func) -{ - slang_variable_destruct(&func->header); - slang_variable_scope_destruct(func->parameters); - _slang_free(func->parameters); - if (func->body != NULL) { - slang_operation_destruct(func->body); - _slang_free(func->body); - } -} - - -slang_function * -slang_function_new(slang_function_kind kind) -{ - slang_function *fun = (slang_function *) - _slang_alloc(sizeof(slang_function)); - if (fun) { - slang_function_construct(fun); - fun->kind = kind; - } - return fun; -} - - -/* - * slang_function_scope - */ - -GLvoid -_slang_function_scope_ctr(slang_function_scope * self) -{ - self->functions = NULL; - self->num_functions = 0; - self->outer_scope = NULL; -} - -void -slang_function_scope_destruct(slang_function_scope * scope) -{ - unsigned int i; - - for (i = 0; i < scope->num_functions; i++) - slang_function_destruct(scope->functions + i); - _slang_free(scope->functions); -} - - -/** - * Does this function have a non-void return value? - */ -GLboolean -_slang_function_has_return_value(const slang_function *fun) -{ - return fun->header.type.specifier.type != SLANG_SPEC_VOID; -} - - -/** - * Search a list of functions for a particular function by name. - * \param funcs the list of functions to search - * \param a_name the name to search for - * \param all_scopes if non-zero, search containing scopes too. - * \return pointer to found function, or NULL. - */ -int -slang_function_scope_find_by_name(slang_function_scope * funcs, - slang_atom a_name, int all_scopes) -{ - unsigned int i; - - for (i = 0; i < funcs->num_functions; i++) - if (a_name == funcs->functions[i].header.a_name) - return 1; - if (all_scopes && funcs->outer_scope != NULL) - return slang_function_scope_find_by_name(funcs->outer_scope, a_name, 1); - return 0; -} - - -/** - * Search a list of functions for a particular function (for implementing - * function calls. Matching is done by first comparing the function's name, - * then the function's parameter list. - * - * \param funcs the list of functions to search - * \param fun the function to search for - * \param all_scopes if non-zero, search containing scopes too. - * \return pointer to found function, or NULL. - */ -slang_function * -slang_function_scope_find(slang_function_scope * funcs, slang_function * fun, - int all_scopes) -{ - unsigned int i; - - for (i = 0; i < funcs->num_functions; i++) { - slang_function *f = &funcs->functions[i]; - const GLuint haveRetValue = 0; -#if 0 - = (f->header.type.specifier.type != SLANG_SPEC_VOID); -#endif - unsigned int j; - - /* - printf("Compare name %s to %s (ret %u, %d, %d)\n", - (char *) fun->header.a_name, (char *) f->header.a_name, - haveRetValue, - fun->param_count, f->param_count); - */ - - if (fun->header.a_name != f->header.a_name) - continue; - if (fun->param_count != f->param_count) - continue; - for (j = haveRetValue; j < fun->param_count; j++) { - if (!slang_type_specifier_equal - (&fun->parameters->variables[j]->type.specifier, - &f->parameters->variables[j]->type.specifier)) - break; - } - if (j == fun->param_count) { - /* - printf("Found match\n"); - */ - return f; - } - } - /* - printf("Not found\n"); - */ - if (all_scopes && funcs->outer_scope != NULL) - return slang_function_scope_find(funcs->outer_scope, fun, 1); - return NULL; -} - - -/** - * Lookup a function according to name and parameter count/types. - */ -slang_function * -_slang_function_locate(const slang_function_scope * funcs, slang_atom a_name, - slang_operation * args, GLuint num_args, - const slang_name_space * space, slang_atom_pool * atoms, - slang_info_log *log, GLboolean *error) -{ - slang_typeinfo arg_ti[100]; - GLuint i; - - *error = GL_FALSE; - - /* determine type of each argument */ - assert(num_args < 100); - for (i = 0; i < num_args; i++) { - if (!slang_typeinfo_construct(&arg_ti[i])) - return NULL; - if (!_slang_typeof_operation(&args[i], space, &arg_ti[i], atoms, log)) { - return NULL; - } - } - - /* loop over function scopes */ - while (funcs) { - - /* look for function with matching name and argument/param types */ - for (i = 0; i < funcs->num_functions; i++) { - slang_function *f = &funcs->functions[i]; - const GLuint haveRetValue = _slang_function_has_return_value(f); - GLuint j; - - if (a_name != f->header.a_name) - continue; - if (f->param_count - haveRetValue != num_args) - continue; - - /* compare parameter / argument types */ - for (j = 0; j < num_args; j++) { - if (!slang_type_specifier_compatible(&arg_ti[j].spec, - &f->parameters->variables[j]->type.specifier)) { - /* param/arg types don't match */ - break; - } - - /* "out" and "inout" formal parameter requires the actual - * argument to be an l-value. - */ - if (!arg_ti[j].can_be_referenced && - (f->parameters->variables[j]->type.qualifier == SLANG_QUAL_OUT || - f->parameters->variables[j]->type.qualifier == SLANG_QUAL_INOUT)) { - /* param is not an lvalue! */ - *error = GL_TRUE; - return NULL; - } - } - - if (j == num_args) { - /* name and args match! */ - return f; - } - } - - funcs = funcs->outer_scope; - } - - return NULL; -} diff --git a/src/mesa/slang/slang_compile_function.h b/src/mesa/slang/slang_compile_function.h deleted file mode 100644 index 0eced3ca1a..0000000000 --- a/src/mesa/slang/slang_compile_function.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.2 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SLANG_COMPILE_FUNCTION_H -#define SLANG_COMPILE_FUNCTION_H - -#include "main/glheader.h" -#include "slang_compile_operation.h" -#include "slang_compile_variable.h" -#include "slang_log.h" -#include "slang_utility.h" - -struct slang_name_space_; -struct slang_operation_; - -/** - * Types of functions. - */ -typedef enum slang_function_kind_ -{ - SLANG_FUNC_ORDINARY, - SLANG_FUNC_CONSTRUCTOR, - SLANG_FUNC_OPERATOR -} slang_function_kind; - - -/** - * Description of a compiled shader function. - */ -typedef struct slang_function_ -{ - slang_function_kind kind; - slang_variable header; /**< The function's name and return type */ - slang_variable_scope *parameters; /**< formal parameters AND local vars */ - unsigned int param_count; /**< number of formal params (no locals) */ - slang_operation *body; /**< The instruction tree */ -} slang_function; - -extern int slang_function_construct(slang_function *); -extern void slang_function_destruct(slang_function *); -extern slang_function *slang_function_new(slang_function_kind kind); - -extern GLboolean -_slang_function_has_return_value(const slang_function *fun); - - -/** - * Basically, a list of compiled functions. - */ -typedef struct slang_function_scope_ -{ - slang_function *functions; - GLuint num_functions; - struct slang_function_scope_ *outer_scope; -} slang_function_scope; - - -extern GLvoid -_slang_function_scope_ctr(slang_function_scope *); - -extern void -slang_function_scope_destruct(slang_function_scope *); - -extern int -slang_function_scope_find_by_name(slang_function_scope *, slang_atom, int); - -extern slang_function * -slang_function_scope_find(slang_function_scope *, slang_function *, int); - -extern struct slang_function_ * -_slang_function_locate(const struct slang_function_scope_ *funcs, - slang_atom name, struct slang_operation_ *params, - GLuint num_params, - const struct slang_name_space_ *space, - slang_atom_pool *atoms, slang_info_log *log, - GLboolean *error); - - -#endif /* SLANG_COMPILE_FUNCTION_H */ diff --git a/src/mesa/slang/slang_compile_operation.c b/src/mesa/slang/slang_compile_operation.c deleted file mode 100644 index 5441d60df5..0000000000 --- a/src/mesa/slang/slang_compile_operation.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.2 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_compile_operation.c - * slang front-end compiler - * \author Michal Krol - */ - -#include "main/imports.h" -#include "slang_compile.h" -#include "slang_mem.h" - - -/** - * Init a slang_operation object - */ -GLboolean -slang_operation_construct(slang_operation * oper) -{ - oper->type = SLANG_OPER_NONE; - oper->children = NULL; - oper->num_children = 0; - oper->literal[0] = 0.0; - oper->literal_size = 1; - oper->array_constructor = GL_FALSE; - oper->a_id = SLANG_ATOM_NULL; - oper->a_obj = SLANG_ATOM_NULL; - oper->locals = _slang_variable_scope_new(NULL); - if (oper->locals == NULL) - return GL_FALSE; - _slang_variable_scope_ctr(oper->locals); - oper->fun = NULL; - oper->var = NULL; - oper->label = NULL; - return GL_TRUE; -} - -void -slang_operation_destruct(slang_operation * oper) -{ - GLuint i; - - for (i = 0; i < oper->num_children; i++) - slang_operation_destruct(oper->children + i); - _slang_free(oper->children); - slang_variable_scope_destruct(oper->locals); - _slang_free(oper->locals); - oper->children = NULL; - oper->num_children = 0; - oper->locals = NULL; -} - - -/** - * Recursively traverse 'oper', replacing occurances of 'oldScope' with - * 'newScope' in the oper->locals->outer_scope field. - */ -void -slang_replace_scope(slang_operation *oper, - slang_variable_scope *oldScope, - slang_variable_scope *newScope) -{ - GLuint i; - - if (oper->locals != newScope && - oper->locals->outer_scope == oldScope) { - /* found. replace old w/ new */ - oper->locals->outer_scope = newScope; - } - - if (oper->type == SLANG_OPER_VARIABLE_DECL) { - /* search/replace in the initializer */ - slang_variable *var; - var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); - if (var && var->initializer) { - slang_replace_scope(var->initializer, oldScope, newScope); - } - } - - /* search/replace in children */ - for (i = 0; i < oper->num_children; i++) { - slang_replace_scope(&oper->children[i], oldScope, newScope); - } -} - - -/** - * Recursively copy a slang_operation node. - * \param x copy target - * \param y copy source - * \return GL_TRUE for success, GL_FALSE if failure - */ -GLboolean -slang_operation_copy(slang_operation * x, const slang_operation * y) -{ - slang_operation z; - GLuint i; - - if (!slang_operation_construct(&z)) - return GL_FALSE; - z.type = y->type; - if (y->num_children > 0) { - z.children = (slang_operation *) - _slang_alloc(y->num_children * sizeof(slang_operation)); - if (z.children == NULL) { - slang_operation_destruct(&z); - return GL_FALSE; - } - } - for (z.num_children = 0; z.num_children < y->num_children; - z.num_children++) { - if (!slang_operation_construct(&z.children[z.num_children])) { - slang_operation_destruct(&z); - return GL_FALSE; - } - } - for (i = 0; i < z.num_children; i++) { - if (!slang_operation_copy(&z.children[i], &y->children[i])) { - slang_operation_destruct(&z); - return GL_FALSE; - } - } - z.literal[0] = y->literal[0]; - z.literal[1] = y->literal[1]; - z.literal[2] = y->literal[2]; - z.literal[3] = y->literal[3]; - z.literal_size = y->literal_size; - assert(y->literal_size >= 1); - assert(y->literal_size <= 4); - z.a_id = y->a_id; - if (y->locals) { - if (!slang_variable_scope_copy(z.locals, y->locals)) { - slang_operation_destruct(&z); - return GL_FALSE; - } - } - - /* update scoping for children */ - for (i = 0; i < y->num_children; i++) { - if (y->children[i].locals && - y->children[i].locals->outer_scope == y->locals) { - z.children[i].locals->outer_scope = z.locals; - } - } - -#if 0 - z.var = y->var; - z.fun = y->fun; -#endif - slang_operation_destruct(x); - *x = z; - - /* If this operation declares a new scope, we need to make sure - * all children point to it, not the original operation's scope! - */ - if (x->type == SLANG_OPER_BLOCK_NEW_SCOPE || - x->type == SLANG_OPER_WHILE || - x->type == SLANG_OPER_FOR) { - slang_replace_scope(x, y->locals, x->locals); - } - - return GL_TRUE; -} - - -slang_operation * -slang_operation_new(GLuint count) -{ - slang_operation *ops - = (slang_operation *) _slang_alloc(count * sizeof(slang_operation)); - assert(count > 0); - if (ops) { - GLuint i; - for (i = 0; i < count; i++) - slang_operation_construct(ops + i); - } - return ops; -} - - -/** - * Delete operation and all children - */ -void -slang_operation_delete(slang_operation *oper) -{ - slang_operation_destruct(oper); - _slang_free(oper); -} - - -void -slang_operation_free_children(slang_operation *oper) -{ - GLuint i; - for (i = 0; i < slang_oper_num_children(oper); i++) { - slang_operation *child = slang_oper_child(oper, i); - slang_operation_destruct(child); - } - _slang_free(oper->children); - oper->children = NULL; - oper->num_children = 0; -} - - -slang_operation * -slang_operation_grow(GLuint *numChildren, slang_operation **children) -{ - slang_operation *ops; - - ops = (slang_operation *) - _slang_realloc(*children, - *numChildren * sizeof(slang_operation), - (*numChildren + 1) * sizeof(slang_operation)); - if (ops) { - slang_operation *newOp = ops + *numChildren; - if (!slang_operation_construct(newOp)) { - _slang_free(ops); - *children = NULL; - return NULL; - } - *children = ops; - (*numChildren)++; - return newOp; - } - return NULL; -} - -/** - * Insert a new slang_operation into an array. - * \param numElements pointer to current array size (in/out) - * \param array address of the array (in/out) - * \param pos position to insert new element - * \return pointer to the new operation/element - */ -slang_operation * -slang_operation_insert(GLuint *numElements, slang_operation **array, - GLuint pos) -{ - slang_operation *ops; - - assert(pos <= *numElements); - - ops = (slang_operation *) - _slang_alloc((*numElements + 1) * sizeof(slang_operation)); - if (ops) { - slang_operation *newOp; - newOp = ops + pos; - if (pos > 0) - memcpy(ops, *array, pos * sizeof(slang_operation)); - if (pos < *numElements) - memcpy(newOp + 1, (*array) + pos, - (*numElements - pos) * sizeof(slang_operation)); - - if (!slang_operation_construct(newOp)) { - _slang_free(ops); - *numElements = 0; - *array = NULL; - return NULL; - } - if (*array) - _slang_free(*array); - *array = ops; - (*numElements)++; - return newOp; - } - return NULL; -} - - -/** - * Add/insert new child into given node at given position. - * \return pointer to the new child node - */ -slang_operation * -slang_operation_insert_child(slang_operation *oper, GLuint pos) -{ - slang_operation *newOp; - - newOp = slang_operation_insert(&oper->num_children, - &oper->children, - pos); - if (newOp) { - newOp->locals->outer_scope = oper->locals; - } - - return newOp; -} - - -void -_slang_operation_swap(slang_operation *oper0, slang_operation *oper1) -{ - slang_operation tmp = *oper0; - *oper0 = *oper1; - *oper1 = tmp; -} - - -void -slang_operation_add_children(slang_operation *oper, GLuint num_children) -{ - GLuint i; - assert(oper->num_children == 0); - assert(oper->children == NULL); - oper->num_children = num_children; - oper->children = slang_operation_new(num_children); - for (i = 0; i < num_children; i++) { - oper->children[i].locals = _slang_variable_scope_new(oper->locals); - } -} - diff --git a/src/mesa/slang/slang_compile_operation.h b/src/mesa/slang/slang_compile_operation.h deleted file mode 100644 index b8c5f214cf..0000000000 --- a/src/mesa/slang/slang_compile_operation.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.2 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SLANG_COMPILE_OPERATION_H -#define SLANG_COMPILE_OPERATION_H - - -#include "main/glheader.h" -#include "slang_compile_variable.h" -#include "slang_utility.h" - -/** - * Types of slang operations. - * These are the types of the AST (abstract syntax tree) nodes. - * [foo] indicates a sub-tree or reference to another type of node - */ -typedef enum slang_operation_type_ -{ - SLANG_OPER_NONE, - SLANG_OPER_BLOCK_NO_NEW_SCOPE, /* "{" sequence "}" */ - SLANG_OPER_BLOCK_NEW_SCOPE, /* "{" sequence "}" */ - SLANG_OPER_VARIABLE_DECL, /* [type] [var] or [var] = [expr] */ - SLANG_OPER_ASM, - SLANG_OPER_BREAK, /* "break" statement */ - SLANG_OPER_CONTINUE, /* "continue" statement */ - SLANG_OPER_DISCARD, /* "discard" (kill fragment) statement */ - SLANG_OPER_RETURN, /* "return" [expr] */ - SLANG_OPER_RETURN_INLINED, /* "return" [expr] from inlined function */ - SLANG_OPER_LABEL, /* a jump target */ - SLANG_OPER_EXPRESSION, /* [expr] */ - SLANG_OPER_IF, /* "if" [0] then [1] else [2] */ - SLANG_OPER_WHILE, /* "while" [cond] [body] */ - SLANG_OPER_DO, /* "do" [body] "while" [cond] */ - SLANG_OPER_FOR, /* "for" [init] [while] [incr] [body] */ - SLANG_OPER_VOID, /* nop */ - SLANG_OPER_LITERAL_BOOL, /* "true" or "false" */ - SLANG_OPER_LITERAL_INT, /* integer literal */ - SLANG_OPER_LITERAL_FLOAT, /* float literal */ - SLANG_OPER_IDENTIFIER, /* var name, func name, etc */ - SLANG_OPER_SEQUENCE, /* [expr] "," [expr] "," etc */ - SLANG_OPER_ASSIGN, /* [var] "=" [expr] */ - SLANG_OPER_ADDASSIGN, /* [var] "+=" [expr] */ - SLANG_OPER_SUBASSIGN, /* [var] "-=" [expr] */ - SLANG_OPER_MULASSIGN, /* [var] "*=" [expr] */ - SLANG_OPER_DIVASSIGN, /* [var] "/=" [expr] */ - /*SLANG_OPER_MODASSIGN, */ - /*SLANG_OPER_LSHASSIGN, */ - /*SLANG_OPER_RSHASSIGN, */ - /*SLANG_OPER_ORASSIGN, */ - /*SLANG_OPER_XORASSIGN, */ - /*SLANG_OPER_ANDASSIGN, */ - SLANG_OPER_SELECT, /* [expr] "?" [expr] ":" [expr] */ - SLANG_OPER_LOGICALOR, /* [expr] "||" [expr] */ - SLANG_OPER_LOGICALXOR, /* [expr] "^^" [expr] */ - SLANG_OPER_LOGICALAND, /* [expr] "&&" [expr] */ - /*SLANG_OPER_BITOR, */ - /*SLANG_OPER_BITXOR, */ - /*SLANG_OPER_BITAND, */ - SLANG_OPER_EQUAL, /* [expr] "==" [expr] */ - SLANG_OPER_NOTEQUAL, /* [expr] "!=" [expr] */ - SLANG_OPER_LESS, /* [expr] "<" [expr] */ - SLANG_OPER_GREATER, /* [expr] ">" [expr] */ - SLANG_OPER_LESSEQUAL, /* [expr] "<=" [expr] */ - SLANG_OPER_GREATEREQUAL, /* [expr] ">=" [expr] */ - /*SLANG_OPER_LSHIFT, */ - /*SLANG_OPER_RSHIFT, */ - SLANG_OPER_ADD, /* [expr] "+" [expr] */ - SLANG_OPER_SUBTRACT, /* [expr] "-" [expr] */ - SLANG_OPER_MULTIPLY, /* [expr] "*" [expr] */ - SLANG_OPER_DIVIDE, /* [expr] "/" [expr] */ - /*SLANG_OPER_MODULUS, */ - SLANG_OPER_PREINCREMENT, /* "++" [var] */ - SLANG_OPER_PREDECREMENT, /* "--" [var] */ - SLANG_OPER_PLUS, /* "-" [expr] */ - SLANG_OPER_MINUS, /* "+" [expr] */ - /*SLANG_OPER_COMPLEMENT, */ - SLANG_OPER_NOT, /* "!" [expr] */ - SLANG_OPER_SUBSCRIPT, /* [expr] "[" [expr] "]" */ - SLANG_OPER_CALL, /* [func name] [param] [param] [...] */ - SLANG_OPER_NON_INLINED_CALL, /* a real function call */ - SLANG_OPER_METHOD, /* method call, such as v.length() */ - SLANG_OPER_FIELD, /* i.e.: ".next" or ".xzy" or ".xxx" etc */ - SLANG_OPER_POSTINCREMENT, /* [var] "++" */ - SLANG_OPER_POSTDECREMENT /* [var] "--" */ -} slang_operation_type; - - -/** - * A slang_operation is basically a compiled instruction (such as assignment, - * a while-loop, a conditional, a multiply, a function call, etc). - * The AST (abstract syntax tree) is built from these nodes. - * NOTE: This structure could have been implemented as a union of simpler - * structs which would correspond to the operation types above. - */ -typedef struct slang_operation_ -{ - slang_operation_type type; - struct slang_operation_ *children; - GLuint num_children; - GLfloat literal[4]; /**< Used for float, int and bool values */ - GLuint literal_size; /**< 1, 2, 3, or 4 */ - slang_atom a_id; /**< type: asm, identifier, call, field */ - slang_atom a_obj; /**< object in a method call */ - slang_variable_scope *locals; /**< local vars for scope */ - struct slang_function_ *fun; /**< If type == SLANG_OPER_CALL */ - struct slang_variable_ *var; /**< If type == slang_oper_identier */ - struct slang_label_ *label; /**< If type == SLANG_OPER_LABEL */ - /** If type==SLANG_OPER_CALL and we're calling an array constructor, - * for which there's no real function, we need to have a flag to - * indicate such. num_children indicates number of elements. - */ - GLboolean array_constructor; -} slang_operation; - - -extern GLboolean -slang_operation_construct(slang_operation *); - -extern void -slang_operation_destruct(slang_operation *); - -extern void -slang_replace_scope(slang_operation *oper, - slang_variable_scope *oldScope, - slang_variable_scope *newScope); - -extern GLboolean -slang_operation_copy(slang_operation *, const slang_operation *); - -extern slang_operation * -slang_operation_new(GLuint count); - -extern void -slang_operation_delete(slang_operation *oper); - -extern void -slang_operation_free_children(slang_operation *oper); - -extern slang_operation * -slang_operation_grow(GLuint *numChildren, slang_operation **children); - -extern slang_operation * -slang_operation_insert(GLuint *numChildren, slang_operation **children, - GLuint pos); - -extern slang_operation * -slang_operation_insert_child(slang_operation *oper, GLuint pos); - -extern void -_slang_operation_swap(slang_operation *oper0, slang_operation *oper1); - - -extern void -slang_operation_add_children(slang_operation *oper, GLuint num_children); - - -/** Return number of children of given node */ -static INLINE GLuint -slang_oper_num_children(const slang_operation *oper) -{ - return oper->num_children; -} - -/** Return child of given operation node */ -static INLINE slang_operation * -slang_oper_child(slang_operation *oper, GLuint child) -{ - assert(child < oper->num_children); - return &oper->children[child]; -} - - -/** Return child of given operation node, const version */ -static INLINE const slang_operation * -slang_oper_child_const(const slang_operation *oper, GLuint child) -{ - assert(child < oper->num_children); - return &oper->children[child]; -} - - -/** Init oper to a boolean literal. */ -static INLINE void -slang_operation_literal_bool(slang_operation *oper, GLboolean value) -{ - oper->type = SLANG_OPER_LITERAL_BOOL; - oper->literal[0] = - oper->literal[1] = - oper->literal[2] = - oper->literal[3] = (float) value; - oper->literal_size = 1; -} - - -/** Init oper to an int literal. */ -static INLINE void -slang_operation_literal_int(slang_operation *oper, GLint value) -{ - oper->type = SLANG_OPER_LITERAL_INT; - oper->literal[0] = - oper->literal[1] = - oper->literal[2] = - oper->literal[3] = (float) value; - oper->literal_size = 1; -} - - -#endif /* SLANG_COMPILE_OPERATION_H */ diff --git a/src/mesa/slang/slang_compile_struct.c b/src/mesa/slang/slang_compile_struct.c deleted file mode 100644 index e6c38730d7..0000000000 --- a/src/mesa/slang/slang_compile_struct.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_compile_struct.c - * slang front-end compiler - * \author Michal Krol - */ - -#include "main/imports.h" -#include "slang_mem.h" -#include "slang_compile.h" - - -GLvoid -_slang_struct_scope_ctr(slang_struct_scope * self) -{ - self->structs = NULL; - self->num_structs = 0; - self->outer_scope = NULL; -} - -void -slang_struct_scope_destruct(slang_struct_scope * scope) -{ - GLuint i; - - for (i = 0; i < scope->num_structs; i++) - slang_struct_destruct(scope->structs + i); - _slang_free(scope->structs); - /* do not free scope->outer_scope */ -} - -int -slang_struct_scope_copy(slang_struct_scope * x, const slang_struct_scope * y) -{ - slang_struct_scope z; - GLuint i; - - _slang_struct_scope_ctr(&z); - z.structs = (slang_struct *) - _slang_alloc(y->num_structs * sizeof(slang_struct)); - if (z.structs == NULL) { - slang_struct_scope_destruct(&z); - return 0; - } - for (z.num_structs = 0; z.num_structs < y->num_structs; z.num_structs++) - if (!slang_struct_construct(&z.structs[z.num_structs])) { - slang_struct_scope_destruct(&z); - return 0; - } - for (i = 0; i < z.num_structs; i++) - if (!slang_struct_copy(&z.structs[i], &y->structs[i])) { - slang_struct_scope_destruct(&z); - return 0; - } - z.outer_scope = y->outer_scope; - slang_struct_scope_destruct(x); - *x = z; - return 1; -} - -slang_struct * -slang_struct_scope_find(slang_struct_scope * stru, slang_atom a_name, - int all_scopes) -{ - GLuint i; - - for (i = 0; i < stru->num_structs; i++) - if (a_name == stru->structs[i].a_name) - return &stru->structs[i]; - if (all_scopes && stru->outer_scope != NULL) - return slang_struct_scope_find(stru->outer_scope, a_name, 1); - return NULL; -} - -/* slang_struct */ - -int -slang_struct_construct(slang_struct * stru) -{ - stru->a_name = SLANG_ATOM_NULL; - stru->fields = (slang_variable_scope *) - _slang_alloc(sizeof(slang_variable_scope)); - if (stru->fields == NULL) - return 0; - _slang_variable_scope_ctr(stru->fields); - - stru->structs = - (slang_struct_scope *) _slang_alloc(sizeof(slang_struct_scope)); - if (stru->structs == NULL) { - slang_variable_scope_destruct(stru->fields); - _slang_free(stru->fields); - return 0; - } - _slang_struct_scope_ctr(stru->structs); - stru->constructor = NULL; - return 1; -} - -void -slang_struct_destruct(slang_struct * stru) -{ - slang_variable_scope_destruct(stru->fields); - _slang_free(stru->fields); - slang_struct_scope_destruct(stru->structs); - _slang_free(stru->structs); -} - -int -slang_struct_copy(slang_struct * x, const slang_struct * y) -{ - slang_struct z; - - if (!slang_struct_construct(&z)) - return 0; - z.a_name = y->a_name; - if (!slang_variable_scope_copy(z.fields, y->fields)) { - slang_struct_destruct(&z); - return 0; - } - if (!slang_struct_scope_copy(z.structs, y->structs)) { - slang_struct_destruct(&z); - return 0; - } - slang_struct_destruct(x); - *x = z; - return 1; -} - -int -slang_struct_equal(const slang_struct * x, const slang_struct * y) -{ - GLuint i; - - if (x->fields->num_variables != y->fields->num_variables) - return 0; - - for (i = 0; i < x->fields->num_variables; i++) { - const slang_variable *varx = x->fields->variables[i]; - const slang_variable *vary = y->fields->variables[i]; - - if (varx->a_name != vary->a_name) - return 0; - if (!slang_type_specifier_equal(&varx->type.specifier, - &vary->type.specifier)) - return 0; - if (varx->type.specifier.type == SLANG_SPEC_ARRAY) - if (varx->array_len != vary->array_len) - return GL_FALSE; - } - return 1; -} diff --git a/src/mesa/slang/slang_compile_struct.h b/src/mesa/slang/slang_compile_struct.h deleted file mode 100644 index 7be6f204e1..0000000000 --- a/src/mesa/slang/slang_compile_struct.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#if !defined SLANG_COMPILE_STRUCT_H -#define SLANG_COMPILE_STRUCT_H - -#if defined __cplusplus -extern "C" { -#endif - -#include "main/glheader.h" -#include "slang_utility.h" - -struct slang_function_; - -typedef struct slang_struct_scope_ -{ - struct slang_struct_ *structs; - GLuint num_structs; - struct slang_struct_scope_ *outer_scope; -} slang_struct_scope; - -extern GLvoid -_slang_struct_scope_ctr (slang_struct_scope *); - -void slang_struct_scope_destruct (slang_struct_scope *); -int slang_struct_scope_copy (slang_struct_scope *, const slang_struct_scope *); -struct slang_struct_ *slang_struct_scope_find (slang_struct_scope *, slang_atom, int); - -typedef struct slang_struct_ -{ - slang_atom a_name; - struct slang_variable_scope_ *fields; - slang_struct_scope *structs; - struct slang_function_ *constructor; -} slang_struct; - -int slang_struct_construct (slang_struct *); -void slang_struct_destruct (slang_struct *); -int slang_struct_copy (slang_struct *, const slang_struct *); -int slang_struct_equal (const slang_struct *, const slang_struct *); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/src/mesa/slang/slang_compile_variable.c b/src/mesa/slang/slang_compile_variable.c deleted file mode 100644 index 23c08a9039..0000000000 --- a/src/mesa/slang/slang_compile_variable.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_compile_variable.c - * slang front-end compiler - * \author Michal Krol - */ - -#include "main/imports.h" -#include "slang_compile.h" -#include "slang_mem.h" - - -static slang_variable * -slang_variable_new(void) -{ - slang_variable *v = (slang_variable *) _slang_alloc(sizeof(slang_variable)); - if (v) { - if (!slang_variable_construct(v)) { - _slang_free(v); - v = NULL; - } - } - return v; -} - - -static void -slang_variable_delete(slang_variable * var) -{ - slang_variable_destruct(var); - _slang_free(var); -} - - -/* - * slang_variable_scope - */ - -slang_variable_scope * -_slang_variable_scope_new(slang_variable_scope *parent) -{ - slang_variable_scope *s; - s = (slang_variable_scope *) _slang_alloc(sizeof(slang_variable_scope)); - if (s) - s->outer_scope = parent; - return s; -} - - -GLvoid -_slang_variable_scope_ctr(slang_variable_scope * self) -{ - self->variables = NULL; - self->num_variables = 0; - self->outer_scope = NULL; -} - -void -slang_variable_scope_destruct(slang_variable_scope * scope) -{ - unsigned int i; - - if (!scope) - return; - for (i = 0; i < scope->num_variables; i++) { - if (scope->variables[i]) - slang_variable_delete(scope->variables[i]); - } - _slang_free(scope->variables); - /* do not free scope->outer_scope */ -} - -int -slang_variable_scope_copy(slang_variable_scope * x, - const slang_variable_scope * y) -{ - slang_variable_scope z; - unsigned int i; - - _slang_variable_scope_ctr(&z); - z.variables = (slang_variable **) - _slang_alloc(y->num_variables * sizeof(slang_variable *)); - if (z.variables == NULL) { - slang_variable_scope_destruct(&z); - return 0; - } - for (z.num_variables = 0; z.num_variables < y->num_variables; - z.num_variables++) { - z.variables[z.num_variables] = slang_variable_new(); - if (!z.variables[z.num_variables]) { - slang_variable_scope_destruct(&z); - return 0; - } - } - for (i = 0; i < z.num_variables; i++) { - if (!slang_variable_copy(z.variables[i], y->variables[i])) { - slang_variable_scope_destruct(&z); - return 0; - } - } - z.outer_scope = y->outer_scope; - slang_variable_scope_destruct(x); - *x = z; - return 1; -} - - -/** - * Grow the variable list by one. - * \return pointer to space for the new variable (will be initialized) - */ -slang_variable * -slang_variable_scope_grow(slang_variable_scope *scope) -{ - const int n = scope->num_variables; - scope->variables = (slang_variable **) - _slang_realloc(scope->variables, - n * sizeof(slang_variable *), - (n + 1) * sizeof(slang_variable *)); - if (!scope->variables) - return NULL; - - scope->num_variables++; - - scope->variables[n] = slang_variable_new(); - if (!scope->variables[n]) - return NULL; - - return scope->variables[n]; -} - - - -/* slang_variable */ - -int -slang_variable_construct(slang_variable * var) -{ - if (!slang_fully_specified_type_construct(&var->type)) - return 0; - var->a_name = SLANG_ATOM_NULL; - var->array_len = 0; - var->initializer = NULL; - var->size = 0; - var->isTemp = GL_FALSE; - var->store = NULL; - var->declared = 0; - return 1; -} - - -void -slang_variable_destruct(slang_variable * var) -{ - slang_fully_specified_type_destruct(&var->type); - if (var->initializer != NULL) { - slang_operation_destruct(var->initializer); - _slang_free(var->initializer); - } -#if 0 - if (var->aux) { - free(var->aux); - } -#endif -} - - -int -slang_variable_copy(slang_variable * x, const slang_variable * y) -{ - slang_variable z; - - if (!slang_variable_construct(&z)) - return 0; - if (!slang_fully_specified_type_copy(&z.type, &y->type)) { - slang_variable_destruct(&z); - return 0; - } - z.a_name = y->a_name; - z.array_len = y->array_len; - if (y->initializer != NULL) { - z.initializer - = (slang_operation *) _slang_alloc(sizeof(slang_operation)); - if (z.initializer == NULL) { - slang_variable_destruct(&z); - return 0; - } - if (!slang_operation_construct(z.initializer)) { - _slang_free(z.initializer); - slang_variable_destruct(&z); - return 0; - } - if (!slang_operation_copy(z.initializer, y->initializer)) { - slang_variable_destruct(&z); - return 0; - } - } - z.size = y->size; - slang_variable_destruct(x); - *x = z; - return 1; -} - - -/** - * Search for named variable in given scope. - * \param all if true, search parent scopes too. - */ -slang_variable * -_slang_variable_locate(const slang_variable_scope * scope, - const slang_atom a_name, GLboolean all) -{ - while (scope) { - GLuint i; - for (i = 0; i < scope->num_variables; i++) - if (a_name == scope->variables[i]->a_name) - return scope->variables[i]; - if (all) - scope = scope->outer_scope; - else - scope = NULL; - } - return NULL; -} diff --git a/src/mesa/slang/slang_compile_variable.h b/src/mesa/slang/slang_compile_variable.h deleted file mode 100644 index 48dc6efca4..0000000000 --- a/src/mesa/slang/slang_compile_variable.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.2 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SLANG_COMPILE_VARIABLE_H -#define SLANG_COMPILE_VARIABLE_H - - -#include "main/glheader.h" -#include "slang_typeinfo.h" -#include "slang_utility.h" - - -/** - * A shading language program variable. - */ -typedef struct slang_variable_ -{ - slang_fully_specified_type type; /**< Variable's data type */ - slang_atom a_name; /**< The variable's name (char *) */ - GLuint array_len; /**< only if type == SLANG_SPEC_ARRAy */ - struct slang_operation_ *initializer; /**< Optional initializer code */ - GLuint size; /**< Variable's size in bytes */ - GLboolean is_global; - GLboolean isTemp; /**< a named temporary (__resultTmp) */ - GLboolean declared; /**< has the var been declared? */ - struct slang_ir_storage_ *store; /**< Storage for this var */ -} slang_variable; - - -/** - * Basically a list of variables, with a pointer to the parent scope. - */ -typedef struct slang_variable_scope_ -{ - slang_variable **variables; /**< Array [num_variables] of ptrs to vars */ - GLuint num_variables; - struct slang_variable_scope_ *outer_scope; -} slang_variable_scope; - - -extern slang_variable_scope * -_slang_variable_scope_new(slang_variable_scope *parent); - -extern GLvoid -_slang_variable_scope_ctr(slang_variable_scope *); - -extern void -slang_variable_scope_destruct(slang_variable_scope *); - -extern int -slang_variable_scope_copy(slang_variable_scope *, - const slang_variable_scope *); - -extern slang_variable * -slang_variable_scope_grow(slang_variable_scope *); - -extern int -slang_variable_construct(slang_variable *); - -extern void -slang_variable_destruct(slang_variable *); - -extern int -slang_variable_copy(slang_variable *, const slang_variable *); - -extern slang_variable * -_slang_variable_locate(const slang_variable_scope *, const slang_atom a_name, - GLboolean all); - - -#endif /* SLANG_COMPILE_VARIABLE_H */ diff --git a/src/mesa/slang/slang_emit.c b/src/mesa/slang/slang_emit.c deleted file mode 100644 index a9aa6fe1c3..0000000000 --- a/src/mesa/slang/slang_emit.c +++ /dev/null @@ -1,2686 +0,0 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2008 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_emit.c - * Emit program instructions (PI code) from IR trees. - * \author Brian Paul - */ - -/*** - *** NOTES - *** - *** To emit GPU instructions, we basically just do an in-order traversal - *** of the IR tree. - ***/ - - -#include "main/imports.h" -#include "main/context.h" -#include "program/program.h" -#include "program/prog_instruction.h" -#include "program/prog_parameter.h" -#include "program/prog_print.h" -#include "slang_builtin.h" -#include "slang_emit.h" -#include "slang_mem.h" - - -#define PEEPHOLE_OPTIMIZATIONS 1 -#define ANNOTATE 0 - - -typedef struct -{ - slang_info_log *log; - slang_var_table *vt; - struct gl_program *prog; - struct gl_program **Subroutines; - GLuint NumSubroutines; - - GLuint MaxInstructions; /**< size of prog->Instructions[] buffer */ - - GLboolean UnresolvedFunctions; - - /* code-gen options */ - GLboolean EmitHighLevelInstructions; - GLboolean EmitCondCodes; - GLboolean EmitComments; - GLboolean EmitBeginEndSub; /* XXX TEMPORARY */ -} slang_emit_info; - - - -static struct gl_program * -new_subroutine(slang_emit_info *emitInfo, GLuint *id) -{ - GET_CURRENT_CONTEXT(ctx); - const GLuint n = emitInfo->NumSubroutines; - - emitInfo->Subroutines = (struct gl_program **) - _mesa_realloc(emitInfo->Subroutines, - n * sizeof(struct gl_program *), - (n + 1) * sizeof(struct gl_program *)); - emitInfo->Subroutines[n] = ctx->Driver.NewProgram(ctx, emitInfo->prog->Target, 0); - emitInfo->Subroutines[n]->Parameters = emitInfo->prog->Parameters; - emitInfo->NumSubroutines++; - *id = n; - return emitInfo->Subroutines[n]; -} - - -/** - * Convert a writemask to a swizzle. Used for testing cond codes because - * we only want to test the cond code component(s) that was set by the - * previous instruction. - */ -static GLuint -writemask_to_swizzle(GLuint writemask) -{ - if (writemask == WRITEMASK_X) - return SWIZZLE_XXXX; - if (writemask == WRITEMASK_Y) - return SWIZZLE_YYYY; - if (writemask == WRITEMASK_Z) - return SWIZZLE_ZZZZ; - if (writemask == WRITEMASK_W) - return SWIZZLE_WWWW; - return SWIZZLE_XYZW; /* shouldn't be hit */ -} - - -/** - * Convert a swizzle mask to a writemask. - * Note that the slang_ir_storage->Swizzle field can represent either a - * swizzle mask or a writemask, depending on how it's used. For example, - * when we parse "direction.yz" alone, we don't know whether .yz is a - * writemask or a swizzle. In this case, we encode ".yz" in store->Swizzle - * as a swizzle mask (.yz?? actually). Later, if direction.yz is used as - * an R-value, we use store->Swizzle as-is. Otherwise, if direction.yz is - * used as an L-value, we convert it to a writemask. - */ -static GLuint -swizzle_to_writemask(GLuint swizzle) -{ - GLuint i, writemask = 0x0; - for (i = 0; i < 4; i++) { - GLuint swz = GET_SWZ(swizzle, i); - if (swz <= SWIZZLE_W) { - writemask |= (1 << swz); - } - } - return writemask; -} - - -/** - * Swizzle a swizzle (function composition). - * That is, return swz2(swz1), or said another way: swz1.szw2 - * Example: swizzle_swizzle(".zwxx", ".xxyw") yields ".zzwx" - */ -GLuint -_slang_swizzle_swizzle(GLuint swz1, GLuint swz2) -{ - GLuint i, swz, s[4]; - for (i = 0; i < 4; i++) { - GLuint c = GET_SWZ(swz2, i); - if (c <= SWIZZLE_W) - s[i] = GET_SWZ(swz1, c); - else - s[i] = c; - } - swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]); - return swz; -} - - -/** - * Return the default swizzle mask for accessing a variable of the - * given size (in floats). If size = 1, comp is used to identify - * which component [0..3] of the register holds the variable. - */ -GLuint -_slang_var_swizzle(GLint size, GLint comp) -{ - switch (size) { - case 1: - return MAKE_SWIZZLE4(comp, SWIZZLE_NIL, SWIZZLE_NIL, SWIZZLE_NIL); - case 2: - return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_NIL, SWIZZLE_NIL); - case 3: - return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_NIL); - default: - return SWIZZLE_XYZW; - } -} - - - -/** - * Allocate storage for the given node (if it hasn't already been allocated). - * - * Typically this is temporary storage for an intermediate result (such as - * for a multiply or add, etc). - * - * If n->Store does not exist it will be created and will be of the size - * specified by defaultSize. - */ -static GLboolean -alloc_node_storage(slang_emit_info *emitInfo, slang_ir_node *n, - GLint defaultSize) -{ - assert(!n->Var); - if (!n->Store) { - assert(defaultSize > 0); - n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, defaultSize); - if (!n->Store) { - return GL_FALSE; - } - } - - /* now allocate actual register(s). I.e. set n->Store->Index >= 0 */ - if (n->Store->Index < 0) { - if (!_slang_alloc_temp(emitInfo->vt, n->Store)) { - slang_info_log_error(emitInfo->log, - "Ran out of registers, too many temporaries"); - _slang_free(n->Store); - n->Store = NULL; - return GL_FALSE; - } - } - return GL_TRUE; -} - - -/** - * Free temporary storage, if n->Store is, in fact, temp storage. - * Otherwise, no-op. - */ -static void -free_node_storage(slang_var_table *vt, slang_ir_node *n) -{ - if (n->Store->File == PROGRAM_TEMPORARY && - n->Store->Index >= 0 && - n->Opcode != IR_SWIZZLE) { - if (_slang_is_temp(vt, n->Store)) { - _slang_free_temp(vt, n->Store); - n->Store->Index = -1; - n->Store = NULL; /* XXX this may not be needed */ - } - } -} - - -/** - * Helper function to allocate a short-term temporary. - * Free it with _slang_free_temp(). - */ -static GLboolean -alloc_local_temp(slang_emit_info *emitInfo, slang_ir_storage *temp, GLint size) -{ - assert(size >= 1); - assert(size <= 4); - memset(temp, 0, sizeof(*temp)); - temp->Size = size; - temp->File = PROGRAM_TEMPORARY; - temp->Index = -1; - return _slang_alloc_temp(emitInfo->vt, temp); -} - - -/** - * Remove any SWIZZLE_NIL terms from given swizzle mask. - * For a swizzle like .z??? generate .zzzz (replicate single component). - * Else, for .wx?? generate .wxzw (insert default component for the position). - */ -static GLuint -fix_swizzle(GLuint swizzle) -{ - GLuint c0 = GET_SWZ(swizzle, 0), - c1 = GET_SWZ(swizzle, 1), - c2 = GET_SWZ(swizzle, 2), - c3 = GET_SWZ(swizzle, 3); - if (c1 == SWIZZLE_NIL && c2 == SWIZZLE_NIL && c3 == SWIZZLE_NIL) { - /* smear first component across all positions */ - c1 = c2 = c3 = c0; - } - else { - /* insert default swizzle components */ - if (c0 == SWIZZLE_NIL) - c0 = SWIZZLE_X; - if (c1 == SWIZZLE_NIL) - c1 = SWIZZLE_Y; - if (c2 == SWIZZLE_NIL) - c2 = SWIZZLE_Z; - if (c3 == SWIZZLE_NIL) - c3 = SWIZZLE_W; - } - return MAKE_SWIZZLE4(c0, c1, c2, c3); -} - - - -/** - * Convert IR storage to an instruction dst register. - */ -static void -storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st) -{ - const GLboolean relAddr = st->RelAddr; - const GLint size = st->Size; - GLint index = st->Index; - GLuint swizzle = st->Swizzle; - - assert(index >= 0); - /* if this is storage relative to some parent storage, walk up the tree */ - while (st->Parent) { - st = st->Parent; - assert(st->Index >= 0); - index += st->Index; - swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); - } - - assert(st->File != PROGRAM_UNDEFINED); - dst->File = st->File; - - assert(index >= 0); - dst->Index = index; - - assert(size >= 1); - assert(size <= 4); - - if (swizzle != SWIZZLE_XYZW) { - dst->WriteMask = swizzle_to_writemask(swizzle); - } - else { - switch (size) { - case 1: - dst->WriteMask = WRITEMASK_X << GET_SWZ(st->Swizzle, 0); - break; - case 2: - dst->WriteMask = WRITEMASK_XY; - break; - case 3: - dst->WriteMask = WRITEMASK_XYZ; - break; - case 4: - dst->WriteMask = WRITEMASK_XYZW; - break; - default: - ; /* error would have been caught above */ - } - } - - dst->RelAddr = relAddr; -} - - -/** - * Convert IR storage to an instruction src register. - */ -static void -storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st) -{ - const GLboolean relAddr = st->RelAddr; - GLint index = st->Index; - GLuint swizzle = st->Swizzle; - - /* if this is storage relative to some parent storage, walk up the tree */ - assert(index >= 0); - while (st->Parent) { - st = st->Parent; - if (st->Index < 0) { - /* an error should have been reported already */ - return; - } - assert(st->Index >= 0); - index += st->Index; - swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle); - } - - assert(st->File >= 0); -#if 1 /* XXX temporary */ - if (st->File == PROGRAM_UNDEFINED) { - slang_ir_storage *st0 = (slang_ir_storage *) st; - st0->File = PROGRAM_TEMPORARY; - } -#endif - assert(st->File < PROGRAM_FILE_MAX); - src->File = st->File; - - assert(index >= 0); - src->Index = index; - - swizzle = fix_swizzle(swizzle); - assert(GET_SWZ(swizzle, 0) <= SWIZZLE_W); - assert(GET_SWZ(swizzle, 1) <= SWIZZLE_W); - assert(GET_SWZ(swizzle, 2) <= SWIZZLE_W); - assert(GET_SWZ(swizzle, 3) <= SWIZZLE_W); - src->Swizzle = swizzle; - - src->HasIndex2 = st->Is2D; - src->Index2 = st->Index2; - - src->RelAddr = relAddr; -} - - -/* - * Setup storage pointing to a scalar constant/literal. - */ -static void -constant_to_storage(slang_emit_info *emitInfo, - GLfloat val, - slang_ir_storage *store) -{ - GLuint swizzle; - GLint reg; - GLfloat value[4]; - - value[0] = val; - reg = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, - value, 1, &swizzle); - - memset(store, 0, sizeof(*store)); - store->File = PROGRAM_CONSTANT; - store->Index = reg; - store->Swizzle = swizzle; -} - - -/** - * Add new instruction at end of given program. - * \param prog the program to append instruction onto - * \param opcode opcode for the new instruction - * \return pointer to the new instruction - */ -static struct prog_instruction * -new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode) -{ - struct gl_program *prog = emitInfo->prog; - struct prog_instruction *inst; - -#if 0 - /* print prev inst */ - if (prog->NumInstructions > 0) { - _mesa_print_instruction(prog->Instructions + prog->NumInstructions - 1); - } -#endif - assert(prog->NumInstructions <= emitInfo->MaxInstructions); - - if (prog->NumInstructions == emitInfo->MaxInstructions) { - /* grow the instruction buffer */ - emitInfo->MaxInstructions += 20; - prog->Instructions = - _mesa_realloc_instructions(prog->Instructions, - prog->NumInstructions, - emitInfo->MaxInstructions); - if (!prog->Instructions) { - return NULL; - } - } - - inst = prog->Instructions + prog->NumInstructions; - prog->NumInstructions++; - _mesa_init_instructions(inst, 1); - inst->Opcode = opcode; - inst->BranchTarget = -1; /* invalid */ - /* - printf("New inst %d: %p %s\n", prog->NumInstructions-1,(void*)inst, - _mesa_opcode_string(inst->Opcode)); - */ - return inst; -} - - -static struct prog_instruction * -emit_arl_load(slang_emit_info *emitInfo, - gl_register_file file, GLint index, GLuint swizzle) -{ - struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ARL); - if (inst) { - inst->SrcReg[0].File = file; - inst->SrcReg[0].Index = index; - inst->SrcReg[0].Swizzle = fix_swizzle(swizzle); - inst->DstReg.File = PROGRAM_ADDRESS; - inst->DstReg.Index = 0; - inst->DstReg.WriteMask = WRITEMASK_X; - } - return inst; -} - - -/** - * Emit a new instruction with given opcode, operands. - * At this point the instruction may have multiple indirect register - * loads/stores. We convert those into ARL loads and address-relative - * operands. See comments inside. - * At some point in the future we could directly emit indirectly addressed - * registers in Mesa GPU instructions. - */ -static struct prog_instruction * -emit_instruction(slang_emit_info *emitInfo, - gl_inst_opcode opcode, - const slang_ir_storage *dst, - const slang_ir_storage *src0, - const slang_ir_storage *src1, - const slang_ir_storage *src2) -{ - struct prog_instruction *inst; - GLuint numIndirect = 0; - const slang_ir_storage *src[3]; - slang_ir_storage newSrc[3], newDst; - GLuint i; - GLboolean isTemp[3]; - - isTemp[0] = isTemp[1] = isTemp[2] = GL_FALSE; - - src[0] = src0; - src[1] = src1; - src[2] = src2; - - /* count up how many operands are indirect loads */ - for (i = 0; i < 3; i++) { - if (src[i] && src[i]->IsIndirect) - numIndirect++; - } - if (dst && dst->IsIndirect) - numIndirect++; - - /* Take special steps for indirect register loads. - * If we had multiple address registers this would be simpler. - * For example, this GLSL code: - * x[i] = y[j] + z[k]; - * would translate into something like: - * ARL ADDR.x, i; - * ARL ADDR.y, j; - * ARL ADDR.z, k; - * ADD TEMP[ADDR.x+5], TEMP[ADDR.y+9], TEMP[ADDR.z+4]; - * But since we currently only have one address register we have to do this: - * ARL ADDR.x, i; - * MOV t1, TEMP[ADDR.x+9]; - * ARL ADDR.x, j; - * MOV t2, TEMP[ADDR.x+4]; - * ARL ADDR.x, k; - * ADD TEMP[ADDR.x+5], t1, t2; - * The code here figures this out... - */ - if (numIndirect > 0) { - for (i = 0; i < 3; i++) { - if (src[i] && src[i]->IsIndirect) { - /* load the ARL register with the indirect register */ - emit_arl_load(emitInfo, - src[i]->IndirectFile, - src[i]->IndirectIndex, - src[i]->IndirectSwizzle); - - if (numIndirect > 1) { - /* Need to load src[i] into a temporary register */ - slang_ir_storage srcRelAddr; - alloc_local_temp(emitInfo, &newSrc[i], src[i]->Size); - isTemp[i] = GL_TRUE; - - /* set RelAddr flag on src register */ - srcRelAddr = *src[i]; - srcRelAddr.RelAddr = GL_TRUE; - srcRelAddr.IsIndirect = GL_FALSE; /* not really needed */ - - /* MOV newSrc, srcRelAddr; */ - inst = emit_instruction(emitInfo, - OPCODE_MOV, - &newSrc[i], - &srcRelAddr, - NULL, - NULL); - if (!inst) { - return NULL; - } - - src[i] = &newSrc[i]; - } - else { - /* just rewrite the src[i] storage to be ARL-relative */ - newSrc[i] = *src[i]; - newSrc[i].RelAddr = GL_TRUE; - newSrc[i].IsIndirect = GL_FALSE; /* not really needed */ - src[i] = &newSrc[i]; - } - } - } - } - - /* Take special steps for indirect dest register write */ - if (dst && dst->IsIndirect) { - /* load the ARL register with the indirect register */ - emit_arl_load(emitInfo, - dst->IndirectFile, - dst->IndirectIndex, - dst->IndirectSwizzle); - newDst = *dst; - newDst.RelAddr = GL_TRUE; - newDst.IsIndirect = GL_FALSE; - dst = &newDst; - } - - /* OK, emit the instruction and its dst, src regs */ - inst = new_instruction(emitInfo, opcode); - if (!inst) - return NULL; - - if (dst) - storage_to_dst_reg(&inst->DstReg, dst); - - for (i = 0; i < 3; i++) { - if (src[i]) - storage_to_src_reg(&inst->SrcReg[i], src[i]); - } - - /* Free any temp registers that we allocated above */ - for (i = 0; i < 3; i++) { - if (isTemp[i]) - _slang_free_temp(emitInfo->vt, &newSrc[i]); - } - - return inst; -} - - - -/** - * Put a comment on the given instruction. - */ -static void -inst_comment(struct prog_instruction *inst, const char *comment) -{ - if (inst) - inst->Comment = _mesa_strdup(comment); -} - - - -/** - * Return pointer to last instruction in program. - */ -static struct prog_instruction * -prev_instruction(slang_emit_info *emitInfo) -{ - struct gl_program *prog = emitInfo->prog; - if (prog->NumInstructions == 0) - return NULL; - else - return prog->Instructions + prog->NumInstructions - 1; -} - - -static struct prog_instruction * -emit(slang_emit_info *emitInfo, slang_ir_node *n); - - -/** - * Return an annotation string for given node's storage. - */ -static char * -storage_annotation(const slang_ir_node *n, const struct gl_program *prog) -{ -#if ANNOTATE - const slang_ir_storage *st = n->Store; - static char s[100] = ""; - - if (!st) - return _mesa_strdup(""); - - switch (st->File) { - case PROGRAM_CONSTANT: - if (st->Index >= 0) { - const GLfloat *val = prog->Parameters->ParameterValues[st->Index]; - if (st->Swizzle == SWIZZLE_NOOP) - _mesa_snprintf(s, sizeof(s), "{%g, %g, %g, %g}", val[0], val[1], val[2], val[3]); - else { - _mesa_snprintf(s, sizeof(s), "%g", val[GET_SWZ(st->Swizzle, 0)]); - } - } - break; - case PROGRAM_TEMPORARY: - if (n->Var) - _mesa_snprintf(s, sizeof(s), "%s", (char *) n->Var->a_name); - else - _mesa_snprintf(s, sizeof(s), "t[%d]", st->Index); - break; - case PROGRAM_STATE_VAR: - case PROGRAM_UNIFORM: - _mesa_snprintf(s, sizeof(s), "%s", prog->Parameters->Parameters[st->Index].Name); - break; - case PROGRAM_VARYING: - _mesa_snprintf(s, sizeof(s), "%s", prog->Varying->Parameters[st->Index].Name); - break; - case PROGRAM_INPUT: - _mesa_snprintf(s, sizeof(s), "input[%d]", st->Index); - break; - case PROGRAM_OUTPUT: - _mesa_snprintf(s, sizeof(s), "output[%d]", st->Index); - break; - default: - s[0] = 0; - } - return _mesa_strdup(s); -#else - return NULL; -#endif -} - - -/** - * Return an annotation string for an instruction. - */ -static char * -instruction_annotation(gl_inst_opcode opcode, char *dstAnnot, - char *srcAnnot0, char *srcAnnot1, char *srcAnnot2) -{ -#if ANNOTATE - const char *operator; - char *s; - int len = 50; - - if (dstAnnot) - len += strlen(dstAnnot); - else - dstAnnot = _mesa_strdup(""); - - if (srcAnnot0) - len += strlen(srcAnnot0); - else - srcAnnot0 = _mesa_strdup(""); - - if (srcAnnot1) - len += strlen(srcAnnot1); - else - srcAnnot1 = _mesa_strdup(""); - - if (srcAnnot2) - len += strlen(srcAnnot2); - else - srcAnnot2 = _mesa_strdup(""); - - switch (opcode) { - case OPCODE_ADD: - operator = "+"; - break; - case OPCODE_SUB: - operator = "-"; - break; - case OPCODE_MUL: - operator = "*"; - break; - case OPCODE_DP2: - operator = "DP2"; - break; - case OPCODE_DP3: - operator = "DP3"; - break; - case OPCODE_DP4: - operator = "DP4"; - break; - case OPCODE_XPD: - operator = "XPD"; - break; - case OPCODE_RSQ: - operator = "RSQ"; - break; - case OPCODE_SGT: - operator = ">"; - break; - default: - operator = ","; - } - - s = (char *) malloc(len); - _mesa_snprintf(s, len, "%s = %s %s %s %s", dstAnnot, - srcAnnot0, operator, srcAnnot1, srcAnnot2); - - free(dstAnnot); - free(srcAnnot0); - free(srcAnnot1); - free(srcAnnot2); - - return s; -#else - return NULL; -#endif -} - - -/** - * Emit an instruction that's just a comment. - */ -static struct prog_instruction * -emit_comment(slang_emit_info *emitInfo, const char *comment) -{ - struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_NOP); - if (inst) { - inst_comment(inst, comment); - } - return inst; -} - - -/** - * Generate code for a simple arithmetic instruction. - * Either 1, 2 or 3 operands. - */ -static struct prog_instruction * -emit_arith(slang_emit_info *emitInfo, slang_ir_node *n) -{ - const slang_ir_info *info = _slang_ir_info(n->Opcode); - struct prog_instruction *inst; - GLuint i; - - assert(info); - assert(info->InstOpcode != OPCODE_NOP); - -#if PEEPHOLE_OPTIMIZATIONS - /* Look for MAD opportunity */ - if (info->NumParams == 2 && - n->Opcode == IR_ADD && n->Children[0]->Opcode == IR_MUL) { - /* found pattern IR_ADD(IR_MUL(A, B), C) */ - emit(emitInfo, n->Children[0]->Children[0]); /* A */ - emit(emitInfo, n->Children[0]->Children[1]); /* B */ - emit(emitInfo, n->Children[1]); /* C */ - if (!alloc_node_storage(emitInfo, n, -1)) { /* dest */ - return NULL; - } - - inst = emit_instruction(emitInfo, - OPCODE_MAD, - n->Store, - n->Children[0]->Children[0]->Store, - n->Children[0]->Children[1]->Store, - n->Children[1]->Store); - - free_node_storage(emitInfo->vt, n->Children[0]->Children[0]); - free_node_storage(emitInfo->vt, n->Children[0]->Children[1]); - free_node_storage(emitInfo->vt, n->Children[1]); - return inst; - } - - if (info->NumParams == 2 && - n->Opcode == IR_ADD && n->Children[1]->Opcode == IR_MUL) { - /* found pattern IR_ADD(A, IR_MUL(B, C)) */ - emit(emitInfo, n->Children[0]); /* A */ - emit(emitInfo, n->Children[1]->Children[0]); /* B */ - emit(emitInfo, n->Children[1]->Children[1]); /* C */ - if (!alloc_node_storage(emitInfo, n, -1)) { /* dest */ - return NULL; - } - - inst = emit_instruction(emitInfo, - OPCODE_MAD, - n->Store, - n->Children[1]->Children[0]->Store, - n->Children[1]->Children[1]->Store, - n->Children[0]->Store); - - free_node_storage(emitInfo->vt, n->Children[1]->Children[0]); - free_node_storage(emitInfo->vt, n->Children[1]->Children[1]); - free_node_storage(emitInfo->vt, n->Children[0]); - return inst; - } -#endif - - /* gen code for children, may involve temp allocation */ - for (i = 0; i < info->NumParams; i++) { - emit(emitInfo, n->Children[i]); - if (!n->Children[i] || !n->Children[i]->Store) { - /* error recovery */ - return NULL; - } - } - - /* result storage */ - if (!alloc_node_storage(emitInfo, n, -1)) { - return NULL; - } - - inst = emit_instruction(emitInfo, - info->InstOpcode, - n->Store, /* dest */ - (info->NumParams > 0 ? n->Children[0]->Store : NULL), - (info->NumParams > 1 ? n->Children[1]->Store : NULL), - (info->NumParams > 2 ? n->Children[2]->Store : NULL) - ); - - /* free temps */ - for (i = 0; i < info->NumParams; i++) - free_node_storage(emitInfo->vt, n->Children[i]); - - return inst; -} - - -/** - * Emit code for == and != operators. These could normally be handled - * by emit_arith() except we need to be able to handle structure comparisons. - */ -static struct prog_instruction * -emit_compare(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct prog_instruction *inst = NULL; - GLint size; - - assert(n->Opcode == IR_EQUAL || n->Opcode == IR_NOTEQUAL); - - /* gen code for children */ - emit(emitInfo, n->Children[0]); - emit(emitInfo, n->Children[1]); - - if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) { - /* XXX this error should have been caught in slang_codegen.c */ - slang_info_log_error(emitInfo->log, "invalid operands to == or !="); - n->Store = NULL; - return NULL; - } - - /* final result is 1 bool */ - if (!alloc_node_storage(emitInfo, n, 1)) - return NULL; - - size = n->Children[0]->Store->Size; - - if (size == 1) { - gl_inst_opcode opcode = n->Opcode == IR_EQUAL ? OPCODE_SEQ : OPCODE_SNE; - inst = emit_instruction(emitInfo, - opcode, - n->Store, /* dest */ - n->Children[0]->Store, - n->Children[1]->Store, - NULL); - } - else if (size <= 4) { - /* compare two vectors. - * Unfortunately, there's no instruction to compare vectors and - * return a scalar result. Do it with some compare and dot product - * instructions... - */ - GLuint swizzle; - gl_inst_opcode dotOp; - slang_ir_storage tempStore; - - if (!alloc_local_temp(emitInfo, &tempStore, 4)) { - n->Store = NULL; - return NULL; - /* out of temps */ - } - - if (size == 4) { - dotOp = OPCODE_DP4; - swizzle = SWIZZLE_XYZW; - } - else if (size == 3) { - dotOp = OPCODE_DP3; - swizzle = SWIZZLE_XYZW; - } - else { - assert(size == 2); - dotOp = OPCODE_DP3; /* XXX use OPCODE_DP2 eventually */ - swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y); - } - - /* Compute inequality (temp = (A != B)) */ - inst = emit_instruction(emitInfo, - OPCODE_SNE, - &tempStore, - n->Children[0]->Store, - n->Children[1]->Store, - NULL); - if (!inst) { - return NULL; - } - inst_comment(inst, "Compare values"); - - /* Compute val = DOT(temp, temp) (reduction) */ - inst = emit_instruction(emitInfo, - dotOp, - n->Store, - &tempStore, - &tempStore, - NULL); - if (!inst) { - return NULL; - } - inst->SrcReg[0].Swizzle = inst->SrcReg[1].Swizzle = swizzle; /*override*/ - inst_comment(inst, "Reduce vec to bool"); - - _slang_free_temp(emitInfo->vt, &tempStore); /* free temp */ - - if (n->Opcode == IR_EQUAL) { - /* compute val = !val.x with SEQ val, val, 0; */ - slang_ir_storage zero; - constant_to_storage(emitInfo, 0.0, &zero); - inst = emit_instruction(emitInfo, - OPCODE_SEQ, - n->Store, /* dest */ - n->Store, - &zero, - NULL); - if (!inst) { - return NULL; - } - inst_comment(inst, "Invert true/false"); - } - } - else { - /* size > 4, struct or array compare. - * XXX this won't work reliably for structs with padding!! - */ - GLint i, num = (n->Children[0]->Store->Size + 3) / 4; - slang_ir_storage accTemp, sneTemp; - - if (!alloc_local_temp(emitInfo, &accTemp, 4)) - return NULL; - - if (!alloc_local_temp(emitInfo, &sneTemp, 4)) - return NULL; - - for (i = 0; i < num; i++) { - slang_ir_storage srcStore0 = *n->Children[0]->Store; - slang_ir_storage srcStore1 = *n->Children[1]->Store; - srcStore0.Index += i; - srcStore1.Index += i; - - if (i == 0) { - /* SNE accTemp, left[i], right[i] */ - inst = emit_instruction(emitInfo, OPCODE_SNE, - &accTemp, /* dest */ - &srcStore0, - &srcStore1, - NULL); - if (!inst) { - return NULL; - } - inst_comment(inst, "Begin struct/array comparison"); - } - else { - /* SNE sneTemp, left[i], right[i] */ - inst = emit_instruction(emitInfo, OPCODE_SNE, - &sneTemp, /* dest */ - &srcStore0, - &srcStore1, - NULL); - if (!inst) { - return NULL; - } - /* ADD accTemp, accTemp, sneTemp; # like logical-OR */ - inst = emit_instruction(emitInfo, OPCODE_ADD, - &accTemp, /* dest */ - &accTemp, - &sneTemp, - NULL); - if (!inst) { - return NULL; - } - } - } - - /* compute accTemp.x || accTemp.y || accTemp.z || accTemp.w with DOT4 */ - inst = emit_instruction(emitInfo, OPCODE_DP4, - n->Store, - &accTemp, - &accTemp, - NULL); - if (!inst) { - return NULL; - } - inst_comment(inst, "End struct/array comparison"); - - if (n->Opcode == IR_EQUAL) { - /* compute tmp.x = !tmp.x via tmp.x = (tmp.x == 0) */ - slang_ir_storage zero; - constant_to_storage(emitInfo, 0.0, &zero); - inst = emit_instruction(emitInfo, OPCODE_SEQ, - n->Store, /* dest */ - n->Store, - &zero, - NULL); - if (!inst) { - return NULL; - } - inst_comment(inst, "Invert true/false"); - } - - _slang_free_temp(emitInfo->vt, &accTemp); - _slang_free_temp(emitInfo->vt, &sneTemp); - } - - /* free temps */ - free_node_storage(emitInfo->vt, n->Children[0]); - free_node_storage(emitInfo->vt, n->Children[1]); - - return inst; -} - - - -/** - * Generate code for an IR_CLAMP instruction. - */ -static struct prog_instruction * -emit_clamp(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct prog_instruction *inst; - slang_ir_node tmpNode; - - assert(n->Opcode == IR_CLAMP); - /* ch[0] = value - * ch[1] = min limit - * ch[2] = max limit - */ - - inst = emit(emitInfo, n->Children[0]); - - /* If lower limit == 0.0 and upper limit == 1.0, - * set prev instruction's SaturateMode field to SATURATE_ZERO_ONE. - * Else, - * emit OPCODE_MIN, OPCODE_MAX sequence. - */ -#if 0 - /* XXX this isn't quite finished yet */ - if (n->Children[1]->Opcode == IR_FLOAT && - n->Children[1]->Value[0] == 0.0 && - n->Children[1]->Value[1] == 0.0 && - n->Children[1]->Value[2] == 0.0 && - n->Children[1]->Value[3] == 0.0 && - n->Children[2]->Opcode == IR_FLOAT && - n->Children[2]->Value[0] == 1.0 && - n->Children[2]->Value[1] == 1.0 && - n->Children[2]->Value[2] == 1.0 && - n->Children[2]->Value[3] == 1.0) { - if (!inst) { - inst = prev_instruction(prog); - } - if (inst && inst->Opcode != OPCODE_NOP) { - /* and prev instruction's DstReg matches n->Children[0]->Store */ - inst->SaturateMode = SATURATE_ZERO_ONE; - n->Store = n->Children[0]->Store; - return inst; - } - } -#else - (void) inst; -#endif - - if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) - return NULL; - - emit(emitInfo, n->Children[1]); - emit(emitInfo, n->Children[2]); - - /* Some GPUs don't allow reading from output registers. So if the - * dest for this clamp() is an output reg, we can't use that reg for - * the intermediate result. Use a temp register instead. - */ - memset(&tmpNode, 0, sizeof(tmpNode)); - if (!alloc_node_storage(emitInfo, &tmpNode, n->Store->Size)) { - return NULL; - } - - /* tmp = max(ch[0], ch[1]) */ - inst = emit_instruction(emitInfo, OPCODE_MAX, - tmpNode.Store, /* dest */ - n->Children[0]->Store, - n->Children[1]->Store, - NULL); - if (!inst) { - return NULL; - } - - /* n->dest = min(tmp, ch[2]) */ - inst = emit_instruction(emitInfo, OPCODE_MIN, - n->Store, /* dest */ - tmpNode.Store, - n->Children[2]->Store, - NULL); - - free_node_storage(emitInfo->vt, &tmpNode); - - return inst; -} - - -static struct prog_instruction * -emit_negation(slang_emit_info *emitInfo, slang_ir_node *n) -{ - /* Implement as MOV dst, -src; */ - /* XXX we could look at the previous instruction and in some circumstances - * modify it to accomplish the negation. - */ - struct prog_instruction *inst; - - emit(emitInfo, n->Children[0]); - - if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) - return NULL; - - inst = emit_instruction(emitInfo, - OPCODE_MOV, - n->Store, /* dest */ - n->Children[0]->Store, - NULL, - NULL); - if (inst) { - inst->SrcReg[0].Negate = NEGATE_XYZW; - } - return inst; -} - - -static struct prog_instruction * -emit_label(slang_emit_info *emitInfo, const slang_ir_node *n) -{ - assert(n->Label); -#if 0 - /* XXX this fails in loop tail code - investigate someday */ - assert(_slang_label_get_location(n->Label) < 0); - _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, - emitInfo->prog); -#else - if (_slang_label_get_location(n->Label) < 0) - _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, - emitInfo->prog); -#endif - return NULL; -} - - -/** - * Emit code for a function call. - * Note that for each time a function is called, we emit the function's - * body code again because the set of available registers may be different. - */ -static struct prog_instruction * -emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct gl_program *progSave; - struct prog_instruction *inst; - GLuint subroutineId; - GLuint maxInstSave; - - assert(n->Opcode == IR_CALL); - assert(n->Label); - - /* save/push cur program */ - maxInstSave = emitInfo->MaxInstructions; - progSave = emitInfo->prog; - - emitInfo->prog = new_subroutine(emitInfo, &subroutineId); - emitInfo->MaxInstructions = emitInfo->prog->NumInstructions; - - _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, - emitInfo->prog); - - if (emitInfo->EmitBeginEndSub) { - /* BGNSUB isn't a real instruction. - * We require a label (i.e. "foobar:") though, if we're going to - * print the program in the NV format. The BNGSUB instruction is - * really just a NOP to attach the label to. - */ - inst = new_instruction(emitInfo, OPCODE_BGNSUB); - if (!inst) { - return NULL; - } - inst_comment(inst, n->Label->Name); - } - - /* body of function: */ - emit(emitInfo, n->Children[0]); - n->Store = n->Children[0]->Store; - - /* add RET instruction now, if needed */ - inst = prev_instruction(emitInfo); - if (inst && inst->Opcode != OPCODE_RET) { - inst = new_instruction(emitInfo, OPCODE_RET); - if (!inst) { - return NULL; - } - } - - if (emitInfo->EmitBeginEndSub) { - inst = new_instruction(emitInfo, OPCODE_ENDSUB); - if (!inst) { - return NULL; - } - inst_comment(inst, n->Label->Name); - } - - /* pop/restore cur program */ - emitInfo->prog = progSave; - emitInfo->MaxInstructions = maxInstSave; - - /* emit the function call */ - inst = new_instruction(emitInfo, OPCODE_CAL); - if (!inst) { - return NULL; - } - /* The branch target is just the subroutine number (changed later) */ - inst->BranchTarget = subroutineId; - inst_comment(inst, n->Label->Name); - assert(inst->BranchTarget >= 0); - - return inst; -} - - -/** - * Emit code for a 'return' statement. - */ -static struct prog_instruction * -emit_return(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct prog_instruction *inst; - assert(n); - assert(n->Opcode == IR_RETURN); - assert(n->Label); - inst = new_instruction(emitInfo, OPCODE_RET); - if (inst) { - inst->DstReg.CondMask = COND_TR; /* always return */ - } - return inst; -} - - -static struct prog_instruction * -emit_kill(slang_emit_info *emitInfo) -{ - struct gl_fragment_program *fp; - struct prog_instruction *inst; - /* NV-KILL - discard fragment depending on condition code. - * Note that ARB-KILL depends on sign of vector operand. - */ - inst = new_instruction(emitInfo, OPCODE_KIL_NV); - if (!inst) { - return NULL; - } - inst->DstReg.CondMask = COND_TR; /* always kill */ - - assert(emitInfo->prog->Target == GL_FRAGMENT_PROGRAM_ARB); - fp = (struct gl_fragment_program *) emitInfo->prog; - fp->UsesKill = GL_TRUE; - - return inst; -} - - -static struct prog_instruction * -emit_tex(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct prog_instruction *inst; - gl_inst_opcode opcode; - GLboolean shadow = GL_FALSE; - - switch (n->Opcode) { - case IR_TEX: - opcode = OPCODE_TEX; - break; - case IR_TEX_SH: - opcode = OPCODE_TEX; - shadow = GL_TRUE; - break; - case IR_TEXB: - opcode = OPCODE_TXB; - break; - case IR_TEXB_SH: - opcode = OPCODE_TXB; - shadow = GL_TRUE; - break; - case IR_TEXP: - opcode = OPCODE_TXP; - break; - case IR_TEXP_SH: - opcode = OPCODE_TXP; - shadow = GL_TRUE; - break; - default: - _mesa_problem(NULL, "Bad IR TEX code"); - return NULL; - } - - if (n->Children[0]->Opcode == IR_ELEMENT) { - /* array is the sampler (a uniform which'll indicate the texture unit) */ - assert(n->Children[0]->Children[0]->Store); - assert(n->Children[0]->Children[0]->Store->File == PROGRAM_SAMPLER); - - emit(emitInfo, n->Children[0]); - - n->Children[0]->Var = n->Children[0]->Children[0]->Var; - } else { - /* this is the sampler (a uniform which'll indicate the texture unit) */ - assert(n->Children[0]->Store); - assert(n->Children[0]->Store->File == PROGRAM_SAMPLER); - } - - /* emit code for the texcoord operand */ - (void) emit(emitInfo, n->Children[1]); - - /* alloc storage for result of texture fetch */ - if (!alloc_node_storage(emitInfo, n, 4)) - return NULL; - - /* emit TEX instruction; Child[1] is the texcoord */ - inst = emit_instruction(emitInfo, - opcode, - n->Store, - n->Children[1]->Store, - NULL, - NULL); - if (!inst) { - return NULL; - } - - inst->TexShadow = shadow; - - /* Store->Index is the uniform/sampler index */ - assert(n->Children[0]->Store->Index >= 0); - inst->TexSrcUnit = n->Children[0]->Store->Index; - inst->TexSrcTarget = n->Children[0]->Store->TexTarget; - - /* mark the sampler as being used */ - _mesa_use_uniform(emitInfo->prog->Parameters, - (char *) n->Children[0]->Var->a_name); - - return inst; -} - - -/** - * Assignment/copy - */ -static struct prog_instruction * -emit_copy(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct prog_instruction *inst; - - assert(n->Opcode == IR_COPY); - - /* lhs */ - emit(emitInfo, n->Children[0]); - if (!n->Children[0]->Store || n->Children[0]->Store->Index < 0) { - /* an error should have been already recorded */ - return NULL; - } - - /* rhs */ - assert(n->Children[1]); - inst = emit(emitInfo, n->Children[1]); - - if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) { - if (!emitInfo->log->text && !emitInfo->UnresolvedFunctions) { - /* XXX this error should have been caught in slang_codegen.c */ - slang_info_log_error(emitInfo->log, "invalid assignment"); - } - return NULL; - } - - assert(n->Children[1]->Store->Index >= 0); - - /*assert(n->Children[0]->Store->Size == n->Children[1]->Store->Size);*/ - - n->Store = n->Children[0]->Store; - - if (n->Store->File == PROGRAM_SAMPLER) { - /* no code generated for sampler assignments, - * just copy the sampler index/target at compile time. - */ - n->Store->Index = n->Children[1]->Store->Index; - n->Store->TexTarget = n->Children[1]->Store->TexTarget; - return NULL; - } - -#if PEEPHOLE_OPTIMIZATIONS - if (inst && - (n->Children[1]->Opcode != IR_SWIZZLE) && - _slang_is_temp(emitInfo->vt, n->Children[1]->Store) && - (inst->DstReg.File == n->Children[1]->Store->File) && - (inst->DstReg.Index == n->Children[1]->Store->Index) && - !n->Children[0]->Store->IsIndirect && - n->Children[0]->Store->Size <= 4) { - /* Peephole optimization: - * The Right-Hand-Side has its results in a temporary place. - * Modify the RHS (and the prev instruction) to store its results - * in the destination specified by n->Children[0]. - * Then, this MOVE is a no-op. - * Ex: - * MUL tmp, x, y; - * MOV a, tmp; - * becomes: - * MUL a, x, y; - */ - - /* fixup the previous instruction (which stored the RHS result) */ - assert(n->Children[0]->Store->Index >= 0); - storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store); - return inst; - } - else -#endif - { - if (n->Children[0]->Store->Size > 4) { - /* move matrix/struct etc (block of registers) */ - slang_ir_storage dstStore = *n->Children[0]->Store; - slang_ir_storage srcStore = *n->Children[1]->Store; - GLint size = srcStore.Size; - ASSERT(n->Children[1]->Store->Swizzle == SWIZZLE_NOOP); - dstStore.Size = 4; - srcStore.Size = 4; - while (size >= 4) { - inst = emit_instruction(emitInfo, OPCODE_MOV, - &dstStore, - &srcStore, - NULL, - NULL); - if (!inst) { - return NULL; - } - inst_comment(inst, "IR_COPY block"); - srcStore.Index++; - dstStore.Index++; - size -= 4; - } - } - else { - /* single register move */ - char *srcAnnot, *dstAnnot; - assert(n->Children[0]->Store->Index >= 0); - inst = emit_instruction(emitInfo, OPCODE_MOV, - n->Children[0]->Store, /* dest */ - n->Children[1]->Store, - NULL, - NULL); - if (!inst) { - return NULL; - } - dstAnnot = storage_annotation(n->Children[0], emitInfo->prog); - srcAnnot = storage_annotation(n->Children[1], emitInfo->prog); - inst->Comment = instruction_annotation(inst->Opcode, dstAnnot, - srcAnnot, NULL, NULL); - } - free_node_storage(emitInfo->vt, n->Children[1]); - return inst; - } -} - - -/** - * An IR_COND node wraps a boolean expression which is used by an - * IF or WHILE test. This is where we'll set condition codes, if needed. - */ -static struct prog_instruction * -emit_cond(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct prog_instruction *inst; - - assert(n->Opcode == IR_COND); - - if (!n->Children[0]) - return NULL; - - /* emit code for the expression */ - inst = emit(emitInfo, n->Children[0]); - - if (!n->Children[0]->Store) { - /* error recovery */ - return NULL; - } - - assert(n->Children[0]->Store); - /*assert(n->Children[0]->Store->Size == 1);*/ - - if (emitInfo->EmitCondCodes) { - if (inst && - n->Children[0]->Store && - inst->DstReg.File == n->Children[0]->Store->File && - inst->DstReg.Index == n->Children[0]->Store->Index) { - /* The previous instruction wrote to the register who's value - * we're testing. Just fix that instruction so that the - * condition codes are computed. - */ - inst->CondUpdate = GL_TRUE; - n->Store = n->Children[0]->Store; - return inst; - } - else { - /* This'll happen for things like "if (i) ..." where no code - * is normally generated for the expression "i". - * Generate a move instruction just to set condition codes. - */ - if (!alloc_node_storage(emitInfo, n, 1)) - return NULL; - inst = emit_instruction(emitInfo, OPCODE_MOV, - n->Store, /* dest */ - n->Children[0]->Store, - NULL, - NULL); - if (!inst) { - return NULL; - } - inst->CondUpdate = GL_TRUE; - inst_comment(inst, "COND expr"); - _slang_free_temp(emitInfo->vt, n->Store); - return inst; - } - } - else { - /* No-op: the boolean result of the expression is in a regular reg */ - n->Store = n->Children[0]->Store; - return inst; - } -} - - -/** - * Logical-NOT - */ -static struct prog_instruction * -emit_not(slang_emit_info *emitInfo, slang_ir_node *n) -{ - static const struct { - gl_inst_opcode op, opNot; - } operators[] = { - { OPCODE_SLT, OPCODE_SGE }, - { OPCODE_SLE, OPCODE_SGT }, - { OPCODE_SGT, OPCODE_SLE }, - { OPCODE_SGE, OPCODE_SLT }, - { OPCODE_SEQ, OPCODE_SNE }, - { OPCODE_SNE, OPCODE_SEQ }, - { 0, 0 } - }; - struct prog_instruction *inst; - slang_ir_storage zero; - GLuint i; - - /* child expr */ - inst = emit(emitInfo, n->Children[0]); - -#if PEEPHOLE_OPTIMIZATIONS - if (inst) { - /* if the prev instruction was a comparison instruction, invert it */ - for (i = 0; operators[i].op; i++) { - if (inst->Opcode == operators[i].op) { - inst->Opcode = operators[i].opNot; - n->Store = n->Children[0]->Store; - return inst; - } - } - } -#endif - - /* else, invert using SEQ (v = v == 0) */ - if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) - return NULL; - - constant_to_storage(emitInfo, 0.0, &zero); - inst = emit_instruction(emitInfo, - OPCODE_SEQ, - n->Store, - n->Children[0]->Store, - &zero, - NULL); - if (!inst) { - return NULL; - } - inst_comment(inst, "NOT"); - - free_node_storage(emitInfo->vt, n->Children[0]); - - return inst; -} - - -static struct prog_instruction * -emit_if(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct gl_program *prog = emitInfo->prog; - GLuint ifInstLoc, elseInstLoc = 0; - GLuint condWritemask = 0; - - /* emit condition expression code */ - { - struct prog_instruction *inst; - inst = emit(emitInfo, n->Children[0]); - if (emitInfo->EmitCondCodes) { - if (!inst) { - /* error recovery */ - return NULL; - } - condWritemask = inst->DstReg.WriteMask; - } - } - - if (!n->Children[0]->Store) - return NULL; - -#if 0 - assert(n->Children[0]->Store->Size == 1); /* a bool! */ -#endif - - ifInstLoc = prog->NumInstructions; - if (emitInfo->EmitHighLevelInstructions) { - if (emitInfo->EmitCondCodes) { - /* IF condcode THEN ... */ - struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_IF); - if (!ifInst) { - return NULL; - } - ifInst->DstReg.CondMask = COND_NE; /* if cond is non-zero */ - /* only test the cond code (1 of 4) that was updated by the - * previous instruction. - */ - ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); - } - else { - struct prog_instruction *inst; - - /* IF src[0] THEN ... */ - inst = emit_instruction(emitInfo, OPCODE_IF, - NULL, /* dst */ - n->Children[0]->Store, /* op0 */ - NULL, - NULL); - if (!inst) { - return NULL; - } - } - } - else { - /* conditional jump to else, or endif */ - struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_BRA); - if (!ifInst) { - return NULL; - } - ifInst->DstReg.CondMask = COND_EQ; /* BRA if cond is zero */ - inst_comment(ifInst, "if zero"); - ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); - } - - /* if body */ - emit(emitInfo, n->Children[1]); - - if (n->Children[2]) { - /* have else body */ - elseInstLoc = prog->NumInstructions; - if (emitInfo->EmitHighLevelInstructions) { - struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ELSE); - if (!inst) { - return NULL; - } - prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions - 1; - } - else { - /* jump to endif instruction */ - struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_BRA); - if (!inst) { - return NULL; - } - inst_comment(inst, "else"); - inst->DstReg.CondMask = COND_TR; /* always branch */ - prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions; - } - emit(emitInfo, n->Children[2]); - } - else { - /* no else body */ - prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions; - } - - if (emitInfo->EmitHighLevelInstructions) { - struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ENDIF); - if (!inst) { - return NULL; - } - } - - if (elseInstLoc) { - /* point ELSE instruction BranchTarget at ENDIF */ - if (emitInfo->EmitHighLevelInstructions) { - prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions - 1; - } - else { - prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions; - } - } - return NULL; -} - - -static struct prog_instruction * -emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct gl_program *prog = emitInfo->prog; - struct prog_instruction *endInst; - GLuint beginInstLoc, tailInstLoc, endInstLoc; - slang_ir_node *ir; - - /* emit OPCODE_BGNLOOP */ - beginInstLoc = prog->NumInstructions; - if (emitInfo->EmitHighLevelInstructions) { - struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_BGNLOOP); - if (!inst) { - return NULL; - } - } - - /* body */ - emit(emitInfo, n->Children[0]); - - /* tail */ - tailInstLoc = prog->NumInstructions; - if (n->Children[1]) { - if (emitInfo->EmitComments) - emit_comment(emitInfo, "Loop tail code:"); - emit(emitInfo, n->Children[1]); - } - - endInstLoc = prog->NumInstructions; - if (emitInfo->EmitHighLevelInstructions) { - /* emit OPCODE_ENDLOOP */ - endInst = new_instruction(emitInfo, OPCODE_ENDLOOP); - if (!endInst) { - return NULL; - } - } - else { - /* emit unconditional BRA-nch */ - endInst = new_instruction(emitInfo, OPCODE_BRA); - if (!endInst) { - return NULL; - } - endInst->DstReg.CondMask = COND_TR; /* always true */ - } - /* ENDLOOP's BranchTarget points to the BGNLOOP inst */ - endInst->BranchTarget = beginInstLoc; - - if (emitInfo->EmitHighLevelInstructions) { - /* BGNLOOP's BranchTarget points to the ENDLOOP inst */ - prog->Instructions[beginInstLoc].BranchTarget = prog->NumInstructions -1; - } - - /* Done emitting loop code. Now walk over the loop's linked list of - * BREAK and CONT nodes, filling in their BranchTarget fields (which - * will point to the corresponding ENDLOOP instruction. - */ - for (ir = n->List; ir; ir = ir->List) { - struct prog_instruction *inst = prog->Instructions + ir->InstLocation; - assert(inst->BranchTarget < 0); - if (ir->Opcode == IR_BREAK || - ir->Opcode == IR_BREAK_IF_TRUE) { - assert(inst->Opcode == OPCODE_BRK || - inst->Opcode == OPCODE_BRA); - /* go to instruction at end of loop */ - if (emitInfo->EmitHighLevelInstructions) { - inst->BranchTarget = endInstLoc; - } - else { - inst->BranchTarget = endInstLoc + 1; - } - } - else { - assert(ir->Opcode == IR_CONT || - ir->Opcode == IR_CONT_IF_TRUE); - assert(inst->Opcode == OPCODE_CONT || - inst->Opcode == OPCODE_BRA); - /* go to instruction at tail of loop */ - inst->BranchTarget = endInstLoc; - } - } - return NULL; -} - - -/** - * Unconditional "continue" or "break" statement. - * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted. - */ -static struct prog_instruction * -emit_cont_break(slang_emit_info *emitInfo, slang_ir_node *n) -{ - gl_inst_opcode opcode; - struct prog_instruction *inst; - - if (n->Opcode == IR_CONT) { - /* we need to execute the loop's tail code before doing CONT */ - assert(n->Parent); - assert(n->Parent->Opcode == IR_LOOP); - if (n->Parent->Children[1]) { - /* emit tail code */ - if (emitInfo->EmitComments) { - emit_comment(emitInfo, "continue - tail code:"); - } - emit(emitInfo, n->Parent->Children[1]); - } - } - - /* opcode selection */ - if (emitInfo->EmitHighLevelInstructions) { - opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK; - } - else { - opcode = OPCODE_BRA; - } - n->InstLocation = emitInfo->prog->NumInstructions; - inst = new_instruction(emitInfo, opcode); - if (inst) { - inst->DstReg.CondMask = COND_TR; /* always true */ - } - return inst; -} - - -/** - * Conditional "continue" or "break" statement. - * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted. - */ -static struct prog_instruction * -emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct prog_instruction *inst; - - assert(n->Opcode == IR_CONT_IF_TRUE || - n->Opcode == IR_BREAK_IF_TRUE); - - /* evaluate condition expr, setting cond codes */ - inst = emit(emitInfo, n->Children[0]); - if (emitInfo->EmitCondCodes) { - assert(inst); - inst->CondUpdate = GL_TRUE; - } - - n->InstLocation = emitInfo->prog->NumInstructions; - - /* opcode selection */ - if (emitInfo->EmitHighLevelInstructions) { - const gl_inst_opcode opcode - = (n->Opcode == IR_CONT_IF_TRUE) ? OPCODE_CONT : OPCODE_BRK; - if (emitInfo->EmitCondCodes) { - /* Get the writemask from the previous instruction which set - * the condcodes. Use that writemask as the CondSwizzle. - */ - const GLuint condWritemask = inst->DstReg.WriteMask; - inst = new_instruction(emitInfo, opcode); - if (inst) { - inst->DstReg.CondMask = COND_NE; - inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); - } - return inst; - } - else { - /* IF reg - * BRK/CONT; - * ENDIF - */ - GLint ifInstLoc; - ifInstLoc = emitInfo->prog->NumInstructions; - inst = emit_instruction(emitInfo, OPCODE_IF, - NULL, /* dest */ - n->Children[0]->Store, - NULL, - NULL); - if (!inst) { - return NULL; - } - n->InstLocation = emitInfo->prog->NumInstructions; - - inst = new_instruction(emitInfo, opcode); - if (!inst) { - return NULL; - } - inst = new_instruction(emitInfo, OPCODE_ENDIF); - if (!inst) { - return NULL; - } - - emitInfo->prog->Instructions[ifInstLoc].BranchTarget - = emitInfo->prog->NumInstructions - 1; - return inst; - } - } - else { - const GLuint condWritemask = inst->DstReg.WriteMask; - assert(emitInfo->EmitCondCodes); - inst = new_instruction(emitInfo, OPCODE_BRA); - if (inst) { - inst->DstReg.CondMask = COND_NE; - inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); - } - return inst; - } -} - - -/** - * Return the size of a swizzle mask given that some swizzle components - * may be NIL/undefined. For example: - * swizzle_size(".zzxx") = 4 - * swizzle_size(".xy??") = 2 - * swizzle_size(".w???") = 1 - */ -static GLuint -swizzle_size(GLuint swizzle) -{ - GLuint i; - for (i = 0; i < 4; i++) { - if (GET_SWZ(swizzle, i) == SWIZZLE_NIL) - return i; - } - return 4; -} - - -static struct prog_instruction * -emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct prog_instruction *inst; - - inst = emit(emitInfo, n->Children[0]); - - if (!n->Store->Parent) { - /* this covers a case such as "(b ? p : q).x" */ - n->Store->Parent = n->Children[0]->Store; - assert(n->Store->Parent); - } - - { - const GLuint swizzle = n->Store->Swizzle; - /* new storage is parent storage with updated Swizzle + Size fields */ - _slang_copy_ir_storage(n->Store, n->Store->Parent); - /* Apply this node's swizzle to parent's storage */ - n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle); - /* Update size */ - n->Store->Size = swizzle_size(n->Store->Swizzle); - } - - assert(!n->Store->Parent); - assert(n->Store->Index >= 0); - - return inst; -} - - -/** - * Dereference array element: element == array[index] - * This basically involves emitting code for computing the array index - * and updating the node/element's storage info. - */ -static struct prog_instruction * -emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) -{ - slang_ir_storage *arrayStore, *indexStore; - const int elemSize = n->Store->Size; /* number of floats */ - const GLint elemSizeVec = (elemSize + 3) / 4; /* number of vec4 */ - struct prog_instruction *inst; - - assert(n->Opcode == IR_ELEMENT); - assert(elemSize > 0); - - /* special case for built-in state variables, like light state */ - { - slang_ir_storage *root = n->Store; - assert(!root->Parent); - while (root->Parent) - root = root->Parent; - - if (root->File == PROGRAM_STATE_VAR) { - GLboolean direct; - GLint index = - _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); - if (index < 0) { - /* error */ - return NULL; - } - if (direct) { - n->Store->Index = index; - return NULL; /* all done */ - } - } - } - - /* do codegen for array itself */ - emit(emitInfo, n->Children[0]); - arrayStore = n->Children[0]->Store; - - /* The initial array element storage is the array's storage, - * then modified below. - */ - _slang_copy_ir_storage(n->Store, arrayStore); - - - if (n->Children[1]->Opcode == IR_FLOAT) { - /* Constant array index */ - const GLint element = (GLint) n->Children[1]->Value[0]; - - /* this element's storage is the array's storage, plus constant offset */ - n->Store->Index += elemSizeVec * element; - } - else { - /* Variable array index */ - - /* do codegen for array index expression */ - emit(emitInfo, n->Children[1]); - indexStore = n->Children[1]->Store; - - if (indexStore->IsIndirect) { - /* need to put the array index into a temporary since we can't - * directly support a[b[i]] constructs. - */ - - - /*indexStore = tempstore();*/ - } - - - if (elemSize > 4) { - /* need to multiply array index by array element size */ - struct prog_instruction *inst; - slang_ir_storage *indexTemp; - slang_ir_storage elemSizeStore; - - /* allocate 1 float indexTemp */ - indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); - _slang_alloc_temp(emitInfo->vt, indexTemp); - - /* allocate a constant containing the element size */ - constant_to_storage(emitInfo, (float) elemSizeVec, &elemSizeStore); - - /* multiply array index by element size */ - inst = emit_instruction(emitInfo, - OPCODE_MUL, - indexTemp, /* dest */ - indexStore, /* the index */ - &elemSizeStore, - NULL); - if (!inst) { - return NULL; - } - - indexStore = indexTemp; - } - - if (arrayStore->IsIndirect) { - /* ex: in a[i][j], a[i] (the arrayStore) is indirect */ - /* Need to add indexStore to arrayStore->Indirect store */ - slang_ir_storage indirectArray; - slang_ir_storage *indexTemp; - - _slang_init_ir_storage(&indirectArray, - arrayStore->IndirectFile, - arrayStore->IndirectIndex, - 1, - arrayStore->IndirectSwizzle); - - /* allocate 1 float indexTemp */ - indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); - _slang_alloc_temp(emitInfo->vt, indexTemp); - - inst = emit_instruction(emitInfo, - OPCODE_ADD, - indexTemp, /* dest */ - indexStore, /* the index */ - &indirectArray, /* indirect array base */ - NULL); - if (!inst) { - return NULL; - } - - indexStore = indexTemp; - } - - /* update the array element storage info */ - n->Store->IsIndirect = GL_TRUE; - n->Store->IndirectFile = indexStore->File; - n->Store->IndirectIndex = indexStore->Index; - n->Store->IndirectSwizzle = indexStore->Swizzle; - } - - n->Store->Size = elemSize; - n->Store->Swizzle = _slang_var_swizzle(elemSize, 0); - - return NULL; /* no instruction */ -} - - -/** - * Resolve storage for accessing a structure field. - */ -static struct prog_instruction * -emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n) -{ - slang_ir_storage *root = n->Store; - GLint fieldOffset, fieldSize; - - assert(n->Opcode == IR_FIELD); - - assert(!root->Parent); - while (root->Parent) - root = root->Parent; - - /* If this is the field of a state var, allocate constant/uniform - * storage for it now if we haven't already. - * Note that we allocate storage (uniform/constant slots) for state - * variables here rather than at declaration time so we only allocate - * space for the ones that we actually use! - */ - if (root->File == PROGRAM_STATE_VAR) { - GLboolean direct; - GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); - if (index < 0) { - slang_info_log_error(emitInfo->log, "Error parsing state variable"); - return NULL; - } - if (direct) { - root->Index = index; - return NULL; /* all done */ - } - } - - /* do codegen for struct */ - emit(emitInfo, n->Children[0]); - assert(n->Children[0]->Store->Index >= 0); - - - fieldOffset = n->Store->Index; - fieldSize = n->Store->Size; - - _slang_copy_ir_storage(n->Store, n->Children[0]->Store); - - n->Store->Index = n->Children[0]->Store->Index + fieldOffset / 4; - n->Store->Size = fieldSize; - - switch (fieldSize) { - case 1: - { - GLint swz = fieldOffset % 4; - n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz); - } - break; - case 2: - n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, - SWIZZLE_NIL, SWIZZLE_NIL); - break; - case 3: - n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, - SWIZZLE_Z, SWIZZLE_NIL); - break; - default: - n->Store->Swizzle = SWIZZLE_XYZW; - } - - assert(n->Store->Index >= 0); - - return NULL; /* no instruction */ -} - - -/** - * Emit code for a variable declaration. - * This usually doesn't result in any code generation, but just - * memory allocation. - */ -static struct prog_instruction * -emit_var_decl(slang_emit_info *emitInfo, slang_ir_node *n) -{ - assert(n->Store); - assert(n->Store->File != PROGRAM_UNDEFINED); - assert(n->Store->Size > 0); - /*assert(n->Store->Index < 0);*/ - - if (!n->Var || n->Var->isTemp) { - /* a nameless/temporary variable, will be freed after first use */ - /*NEW*/ - if (n->Store->Index < 0 && !_slang_alloc_temp(emitInfo->vt, n->Store)) { - slang_info_log_error(emitInfo->log, - "Ran out of registers, too many temporaries"); - return NULL; - } - } - else { - /* a regular variable */ - _slang_add_variable(emitInfo->vt, n->Var); - if (!_slang_alloc_var(emitInfo->vt, n->Store)) { - slang_info_log_error(emitInfo->log, - "Ran out of registers, too many variables"); - return NULL; - } - /* - printf("IR_VAR_DECL %s %d store %p\n", - (char*) n->Var->a_name, n->Store->Index, (void*) n->Store); - */ - assert(n->Var->store == n->Store); - } - if (emitInfo->EmitComments) { - /* emit NOP with comment describing the variable's storage location */ - char s[1000]; - _mesa_snprintf(s, sizeof(s), "TEMP[%d]%s = variable %s (size %d)", - n->Store->Index, - _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE), - (n->Var ? (char *) n->Var->a_name : "anonymous"), - n->Store->Size); - emit_comment(emitInfo, s); - } - return NULL; -} - - -/** - * Emit code for a reference to a variable. - * Actually, no code is generated but we may do some memory allocation. - * In particular, state vars (uniforms) are allocated on an as-needed basis. - */ -static struct prog_instruction * -emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n) -{ - assert(n->Store); - assert(n->Store->File != PROGRAM_UNDEFINED); - - if (n->Store->File == PROGRAM_STATE_VAR && n->Store->Index < 0) { - GLboolean direct; - GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); - if (index < 0) { - /* error */ - char s[100]; - /* XXX isn't this really an out of memory/resources error? */ - _mesa_snprintf(s, sizeof(s), "Undefined variable '%s'", - (char *) n->Var->a_name); - slang_info_log_error(emitInfo->log, s); - return NULL; - } - - n->Store->Index = index; - } - else if (n->Store->File == PROGRAM_UNIFORM || - n->Store->File == PROGRAM_SAMPLER) { - /* mark var as used */ - _mesa_use_uniform(emitInfo->prog->Parameters, (char *) n->Var->a_name); - } - else if (n->Store->File == PROGRAM_INPUT) { - assert(n->Store->Index >= 0); - /* geometry shaders have the input index in the second - * index */ - if (emitInfo->prog->Target == MESA_GEOMETRY_PROGRAM && - n->Store->Is2D) { - emitInfo->prog->InputsRead |= (1 << n->Store->Index2); - } else - emitInfo->prog->InputsRead |= (1 << n->Store->Index); - } - - if (n->Store->Index < 0) { - /* probably ran out of registers */ - return NULL; - } - assert(n->Store->Size > 0); - - return NULL; -} - - -static struct prog_instruction * -emit(slang_emit_info *emitInfo, slang_ir_node *n) -{ - struct prog_instruction *inst; - if (!n) - return NULL; - - if (emitInfo->log->error_flag) { - return NULL; - } - - if (n->Comment) { - inst = new_instruction(emitInfo, OPCODE_NOP); - if (inst) { - inst->Comment = _mesa_strdup(n->Comment); - } - inst = NULL; - } - - switch (n->Opcode) { - case IR_SEQ: - /* sequence of two sub-trees */ - assert(n->Children[0]); - assert(n->Children[1]); - emit(emitInfo, n->Children[0]); - if (emitInfo->log->error_flag) - return NULL; - inst = emit(emitInfo, n->Children[1]); -#if 0 - assert(!n->Store); -#endif - if (n->Children[1]->Store) - n->Store = n->Children[1]->Store; - else - n->Store = n->Children[0]->Store; - return inst; - - case IR_SCOPE: - /* new variable scope */ - _slang_push_var_table(emitInfo->vt); - inst = emit(emitInfo, n->Children[0]); - _slang_pop_var_table(emitInfo->vt); - n->Store = n->Children[0]->Store; - return inst; - - case IR_VAR_DECL: - /* Variable declaration - allocate a register for it */ - inst = emit_var_decl(emitInfo, n); - return inst; - - case IR_VAR: - /* Reference to a variable - * Storage should have already been resolved/allocated. - */ - return emit_var_ref(emitInfo, n); - - case IR_ELEMENT: - return emit_array_element(emitInfo, n); - case IR_FIELD: - return emit_struct_field(emitInfo, n); - case IR_SWIZZLE: - return emit_swizzle(emitInfo, n); - - /* Simple arithmetic */ - /* unary */ - case IR_MOVE: - case IR_RSQ: - case IR_RCP: - case IR_FLOOR: - case IR_FRAC: - case IR_F_TO_I: - case IR_I_TO_F: - case IR_ABS: - case IR_SIN: - case IR_COS: - case IR_DDX: - case IR_DDY: - case IR_EXP: - case IR_EXP2: - case IR_LOG2: - case IR_NOISE1: - case IR_NOISE2: - case IR_NOISE3: - case IR_NOISE4: - case IR_NRM4: - case IR_NRM3: - /* binary */ - case IR_ADD: - case IR_SUB: - case IR_MUL: - case IR_DOT4: - case IR_DOT3: - case IR_DOT2: - case IR_CROSS: - case IR_MIN: - case IR_MAX: - case IR_SEQUAL: - case IR_SNEQUAL: - case IR_SGE: - case IR_SGT: - case IR_SLE: - case IR_SLT: - case IR_POW: - /* trinary operators */ - case IR_LRP: - case IR_CMP: - return emit_arith(emitInfo, n); - - case IR_EQUAL: - case IR_NOTEQUAL: - return emit_compare(emitInfo, n); - - case IR_CLAMP: - return emit_clamp(emitInfo, n); - case IR_TEX: - case IR_TEXB: - case IR_TEXP: - case IR_TEX_SH: - case IR_TEXB_SH: - case IR_TEXP_SH: - return emit_tex(emitInfo, n); - case IR_NEG: - return emit_negation(emitInfo, n); - case IR_FLOAT: - /* find storage location for this float constant */ - n->Store->Index = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, - n->Value, - n->Store->Size, - &n->Store->Swizzle); - if (n->Store->Index < 0) { - slang_info_log_error(emitInfo->log, "Ran out of space for constants"); - return NULL; - } - return NULL; - - case IR_COPY: - return emit_copy(emitInfo, n); - - case IR_COND: - return emit_cond(emitInfo, n); - - case IR_NOT: - return emit_not(emitInfo, n); - - case IR_LABEL: - return emit_label(emitInfo, n); - - case IR_KILL: - return emit_kill(emitInfo); - - case IR_CALL: - /* new variable scope for subroutines/function calls */ - _slang_push_var_table(emitInfo->vt); - inst = emit_fcall(emitInfo, n); - _slang_pop_var_table(emitInfo->vt); - return inst; - - case IR_IF: - return emit_if(emitInfo, n); - - case IR_LOOP: - return emit_loop(emitInfo, n); - case IR_BREAK_IF_TRUE: - case IR_CONT_IF_TRUE: - return emit_cont_break_if_true(emitInfo, n); - case IR_BREAK: - /* fall-through */ - case IR_CONT: - return emit_cont_break(emitInfo, n); - - case IR_BEGIN_SUB: - return new_instruction(emitInfo, OPCODE_BGNSUB); - case IR_END_SUB: - return new_instruction(emitInfo, OPCODE_ENDSUB); - case IR_RETURN: - return emit_return(emitInfo, n); - - case IR_NOP: - return NULL; - - case IR_EMIT_VERTEX: - return new_instruction(emitInfo, OPCODE_EMIT_VERTEX); - case IR_END_PRIMITIVE: - return new_instruction(emitInfo, OPCODE_END_PRIMITIVE); - - default: - _mesa_problem(NULL, "Unexpected IR opcode in emit()\n"); - } - return NULL; -} - - -/** - * After code generation, any subroutines will be in separate program - * objects. This function appends all the subroutines onto the main - * program and resolves the linking of all the branch/call instructions. - * XXX this logic should really be part of the linking process... - */ -static void -_slang_resolve_subroutines(slang_emit_info *emitInfo) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_program *mainP = emitInfo->prog; - GLuint *subroutineLoc, i, total; - - subroutineLoc - = (GLuint *) malloc(emitInfo->NumSubroutines * sizeof(GLuint)); - - /* total number of instructions */ - total = mainP->NumInstructions; - for (i = 0; i < emitInfo->NumSubroutines; i++) { - subroutineLoc[i] = total; - total += emitInfo->Subroutines[i]->NumInstructions; - } - - /* adjust BranchTargets within the functions */ - for (i = 0; i < emitInfo->NumSubroutines; i++) { - struct gl_program *sub = emitInfo->Subroutines[i]; - GLuint j; - for (j = 0; j < sub->NumInstructions; j++) { - struct prog_instruction *inst = sub->Instructions + j; - if (inst->Opcode != OPCODE_CAL && inst->BranchTarget >= 0) { - inst->BranchTarget += subroutineLoc[i]; - } - } - } - - /* append subroutines' instructions after main's instructions */ - mainP->Instructions = _mesa_realloc_instructions(mainP->Instructions, - mainP->NumInstructions, - total); - mainP->NumInstructions = total; - for (i = 0; i < emitInfo->NumSubroutines; i++) { - struct gl_program *sub = emitInfo->Subroutines[i]; - _mesa_copy_instructions(mainP->Instructions + subroutineLoc[i], - sub->Instructions, - sub->NumInstructions); - /* delete subroutine code */ - sub->Parameters = NULL; /* prevent double-free */ - _mesa_reference_program(ctx, &emitInfo->Subroutines[i], NULL); - } - - /* free subroutine list */ - if (emitInfo->Subroutines) { - free(emitInfo->Subroutines); - emitInfo->Subroutines = NULL; - } - emitInfo->NumSubroutines = 0; - - /* Examine CAL instructions. - * At this point, the BranchTarget field of the CAL instruction is - * the number/id of the subroutine to call (an index into the - * emitInfo->Subroutines list). - * Translate that into an actual instruction location now. - */ - for (i = 0; i < mainP->NumInstructions; i++) { - struct prog_instruction *inst = mainP->Instructions + i; - if (inst->Opcode == OPCODE_CAL) { - const GLuint f = inst->BranchTarget; - inst->BranchTarget = subroutineLoc[f]; - } - } - - free(subroutineLoc); -} - - - -/** - * Convert the IR tree into GPU instructions. - * \param n root of IR tree - * \param vt variable table - * \param prog program to put GPU instructions into - * \param pragmas controls codegen options - * \param withEnd if true, emit END opcode at end - * \param log log for emitting errors/warnings/info - */ -GLboolean -_slang_emit_code(slang_ir_node *n, slang_var_table *vt, - struct gl_program *prog, - const struct gl_sl_pragmas *pragmas, - GLboolean withEnd, - slang_info_log *log) -{ - GET_CURRENT_CONTEXT(ctx); - GLboolean success; - slang_emit_info emitInfo; - GLuint maxUniforms; - - emitInfo.log = log; - emitInfo.vt = vt; - emitInfo.prog = prog; - emitInfo.Subroutines = NULL; - emitInfo.NumSubroutines = 0; - emitInfo.MaxInstructions = prog->NumInstructions; - - emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions; - emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes; - emitInfo.EmitComments = ctx->Shader.EmitComments || pragmas->Debug; - emitInfo.EmitBeginEndSub = GL_TRUE; - - if (!emitInfo.EmitCondCodes) { - emitInfo.EmitHighLevelInstructions = GL_TRUE; - } - - /* Check uniform/constant limits */ - if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) { - maxUniforms = ctx->Const.FragmentProgram.MaxUniformComponents / 4; - } - else if (prog->Target == GL_VERTEX_PROGRAM_ARB) { - maxUniforms = ctx->Const.VertexProgram.MaxUniformComponents / 4; - } else { - assert(prog->Target == MESA_GEOMETRY_PROGRAM); - maxUniforms = ctx->Const.GeometryProgram.MaxUniformComponents / 4; - } - if (prog->Parameters->NumParameters > maxUniforms) { - slang_info_log_error(log, "Constant/uniform register limit exceeded " - "(max=%u vec4)", maxUniforms); - - return GL_FALSE; - } - - (void) emit(&emitInfo, n); - - /* finish up by adding the END opcode to program */ - if (withEnd) { - struct prog_instruction *inst; - inst = new_instruction(&emitInfo, OPCODE_END); - if (!inst) { - return GL_FALSE; - } - } - - _slang_resolve_subroutines(&emitInfo); - - success = GL_TRUE; - -#if 0 - printf("*********** End emit code (%u inst):\n", prog->NumInstructions); - _mesa_print_program(prog); - _mesa_print_program_parameters(ctx,prog); -#endif - - return success; -} diff --git a/src/mesa/slang/slang_ir.c b/src/mesa/slang/slang_ir.c deleted file mode 100644 index 078c9369a8..0000000000 --- a/src/mesa/slang/slang_ir.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "main/imports.h" -#include "main/context.h" -#include "slang_ir.h" -#include "slang_mem.h" -#include "program/prog_instruction.h" -#include "program/prog_print.h" - - -static const slang_ir_info IrInfo[] = { - /* binary ops */ - { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 }, - { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 }, - { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 }, - { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */ - { IR_DOT4, "IR_DOT4", OPCODE_DP4, 1, 2 }, - { IR_DOT3, "IR_DOT3", OPCODE_DP3, 1, 2 }, - { IR_DOT2, "IR_DOT2", OPCODE_DP2, 1, 2 }, - { IR_NRM4, "IR_NRM4", OPCODE_NRM4, 1, 1 }, - { IR_NRM3, "IR_NRM3", OPCODE_NRM3, 1, 1 }, - { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 }, - { IR_LRP, "IR_LRP", OPCODE_LRP, 4, 3 }, - { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 }, - { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 }, - { IR_CLAMP, "IR_CLAMP", OPCODE_NOP, 4, 3 }, /* special case: emit_clamp() */ - { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 }, - { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 }, - { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 }, - { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 }, - { IR_SLE, "IR_SLE", OPCODE_SLE, 4, 2 }, - { IR_SLT, "IR_SLT", OPCODE_SLT, 4, 2 }, - { IR_POW, "IR_POW", OPCODE_POW, 1, 2 }, - { IR_EQUAL, "IR_EQUAL", OPCODE_NOP, 1, 2 }, - { IR_NOTEQUAL, "IR_NOTEQUAL", OPCODE_NOP, 1, 2 }, - - /* unary ops */ - { IR_MOVE, "IR_MOVE", OPCODE_MOV, 4, 1 }, - { IR_I_TO_F, "IR_I_TO_F", OPCODE_MOV, 4, 1 }, /* int[4] to float[4] */ - { IR_F_TO_I, "IR_F_TO_I", OPCODE_TRUNC, 4, 1 }, - { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 }, - { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 }, - { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 }, - { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 }, - { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 }, - { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 }, - { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 }, - { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 }, - { IR_NEG, "IR_NEG", OPCODE_NOP, 4, 1 }, /* special case: emit_negation() */ - { IR_DDX, "IR_DDX", OPCODE_DDX, 4, 1 }, - { IR_DDY, "IR_DDY", OPCODE_DDY, 4, 1 }, - { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 }, - { IR_COS, "IR_COS", OPCODE_COS, 1, 1 }, - { IR_NOISE1, "IR_NOISE1", OPCODE_NOISE1, 1, 1 }, - { IR_NOISE2, "IR_NOISE2", OPCODE_NOISE2, 1, 1 }, - { IR_NOISE3, "IR_NOISE3", OPCODE_NOISE3, 1, 1 }, - { IR_NOISE4, "IR_NOISE4", OPCODE_NOISE4, 1, 1 }, - - /* other */ - { IR_CMP, "IR_CMP", OPCODE_CMP, 4, 3 }, /* compare/select */ - { IR_SEQ, "IR_SEQ", OPCODE_NOP, 0, 0 }, - { IR_SCOPE, "IR_SCOPE", OPCODE_NOP, 0, 0 }, - { IR_LABEL, "IR_LABEL", OPCODE_NOP, 0, 0 }, - { IR_IF, "IR_IF", OPCODE_NOP, 0, 0 }, - { IR_KILL, "IR_KILL", OPCODE_NOP, 0, 0 }, - { IR_COND, "IR_COND", OPCODE_NOP, 0, 0 }, - { IR_CALL, "IR_CALL", OPCODE_NOP, 0, 0 }, - { IR_COPY, "IR_COPY", OPCODE_NOP, 0, 1 }, - { IR_NOT, "IR_NOT", OPCODE_NOP, 1, 1 }, - { IR_VAR, "IR_VAR", OPCODE_NOP, 0, 0 }, - { IR_VAR_DECL, "IR_VAR_DECL", OPCODE_NOP, 0, 0 }, - { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 }, - { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 1 }, - { IR_TEXP, "IR_TEXP", OPCODE_TXP, 4, 1 }, - { IR_TEX_SH, "IR_TEX_SH", OPCODE_TEX, 4, 1 }, - { IR_TEXB_SH, "IR_TEXB_SH", OPCODE_TXB, 4, 1 }, - { IR_TEXP_SH, "IR_TEXP_SH", OPCODE_TXP, 4, 1 }, - { IR_FLOAT, "IR_FLOAT", OPCODE_NOP, 0, 0 }, /* float literal */ - { IR_FIELD, "IR_FIELD", OPCODE_NOP, 0, 0 }, - { IR_ELEMENT, "IR_ELEMENT", OPCODE_NOP, 0, 0 }, - { IR_SWIZZLE, "IR_SWIZZLE", OPCODE_NOP, 0, 0 }, - { IR_NOP, "IR_NOP", OPCODE_NOP, 0, 0 }, - { IR_EMIT_VERTEX, "IR_EMIT_VERTEX", OPCODE_EMIT_VERTEX, 0, 0 }, - { IR_END_PRIMITIVE, "IR_END_PRIMITIVE", OPCODE_END_PRIMITIVE, 0, 0 }, - { 0, NULL, 0, 0, 0 } -}; - - -const slang_ir_info * -_slang_ir_info(slang_ir_opcode opcode) -{ - GLuint i; - for (i = 0; IrInfo[i].IrName; i++) { - if (IrInfo[i].IrOpcode == opcode) { - return IrInfo + i; - } - } - return NULL; -} - - -void -_slang_init_ir_storage(slang_ir_storage *st, - gl_register_file file, GLint index, GLint size, - GLuint swizzle) -{ - st->File = file; - st->Index = index; - st->Size = size; - st->Swizzle = swizzle; - st->Parent = NULL; - st->IsIndirect = GL_FALSE; - st->Is2D = GL_FALSE; - st->Index2 = 0; -} - - -/** - * Return a new slang_ir_storage object. - */ -slang_ir_storage * -_slang_new_ir_storage(gl_register_file file, GLint index, GLint size) -{ - slang_ir_storage *st; - st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); - if (st) { - st->File = file; - st->Index = index; - st->Size = size; - st->Swizzle = SWIZZLE_NOOP; - st->Parent = NULL; - st->IsIndirect = GL_FALSE; - st->Is2D = GL_FALSE; - st->Index2 = 0; - } - return st; -} - - -/** - * Return a new slang_ir_storage object. - */ -slang_ir_storage * -_slang_new_ir_storage_swz(gl_register_file file, GLint index, GLint size, - GLuint swizzle) -{ - slang_ir_storage *st; - st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); - if (st) { - st->File = file; - st->Index = index; - st->Size = size; - st->Swizzle = swizzle; - st->Parent = NULL; - st->IsIndirect = GL_FALSE; - st->Is2D = GL_FALSE; - st->Index2 = 0; - } - return st; -} - -/** - * Return a new slang_ir_storage object. - */ -slang_ir_storage * -_slang_new_ir_storage_2d(gl_register_file file, - GLint index, GLint index2, - GLint size, GLuint swizzle) -{ - slang_ir_storage *st; - st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); - if (st) { - st->File = file; - st->Index = index; - st->Size = size; - st->Swizzle = swizzle; - st->Parent = NULL; - st->IsIndirect = GL_FALSE; - st->Is2D = GL_TRUE; - st->Index2 = index2; - } - return st; -} - - - -/** - * Return a new slang_ir_storage object. - */ -slang_ir_storage * -_slang_new_ir_storage_relative(GLint index, GLint size, - slang_ir_storage *parent) -{ - slang_ir_storage *st; - st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); - if (st) { - st->File = PROGRAM_UNDEFINED; - st->Index = index; - st->Size = size; - st->Swizzle = SWIZZLE_NOOP; - st->Parent = parent; - st->IsIndirect = GL_FALSE; - st->Is2D = GL_FALSE; - st->Index2 = 0; - } - return st; -} - - -slang_ir_storage * -_slang_new_ir_storage_indirect(gl_register_file file, - GLint index, - GLint size, - gl_register_file indirectFile, - GLint indirectIndex, - GLuint indirectSwizzle) -{ - slang_ir_storage *st; - st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); - if (st) { - st->File = file; - st->Index = index; - st->Size = size; - st->Swizzle = SWIZZLE_NOOP; - st->IsIndirect = GL_TRUE; - st->IndirectFile = indirectFile; - st->IndirectIndex = indirectIndex; - st->IndirectSwizzle = indirectSwizzle; - st->Is2D = GL_FALSE; - st->Index2 = 0; - } - return st; -} - - -/** - * Allocate IR storage for a texture sampler. - * \param sampNum the sampler number/index - * \param texTarget one of TEXTURE_x_INDEX values - * \param size number of samplers (in case of sampler array) - */ -slang_ir_storage * -_slang_new_ir_storage_sampler(GLint sampNum, GLuint texTarget, GLint size) -{ - slang_ir_storage *st; - assert(texTarget < NUM_TEXTURE_TARGETS); - st = _slang_new_ir_storage(PROGRAM_SAMPLER, sampNum, size); - if (st) { - st->TexTarget = texTarget; - } - return st; -} - - - -/* XXX temporary function */ -void -_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src) -{ - *dst = *src; - dst->Parent = NULL; -} - - - -static const char * -_slang_ir_name(slang_ir_opcode opcode) -{ - return _slang_ir_info(opcode)->IrName; -} - - - -#if 0 /* no longer needed with mempool */ -/** - * Since many IR nodes might point to the same IR storage info, we need - * to be careful when deleting things. - * Before deleting an IR tree, traverse it and do refcounting on the - * IR storage nodes. Use the refcount info during delete to free things - * properly. - */ -static void -_slang_refcount_storage(slang_ir_node *n) -{ - GLuint i; - if (!n) - return; - if (n->Store) - n->Store->RefCount++; - for (i = 0; i < 3; i++) - _slang_refcount_storage(n->Children[i]); -} -#endif - - -static void -_slang_free_ir(slang_ir_node *n) -{ - GLuint i; - if (!n) - return; - -#if 0 - if (n->Store) { - n->Store->RefCount--; - if (n->Store->RefCount == 0) { - _slang_free(n->Store); - n->Store = NULL; - } - } -#endif - - for (i = 0; i < 3; i++) - _slang_free_ir(n->Children[i]); - /* Do not free n->List since it's a child elsewhere */ - _slang_free(n); -} - - -/** - * Recursively free an IR tree. - */ -void -_slang_free_ir_tree(slang_ir_node *n) -{ -#if 0 - _slang_refcount_storage(n); -#endif - _slang_free_ir(n); -} - - -static const char * -storage_string(const slang_ir_storage *st) -{ - static const char *files[] = { - "TEMP", - "LOCAL_PARAM", - "ENV_PARAM", - "STATE", - "INPUT", - "OUTPUT", - "NAMED_PARAM", - "CONSTANT", - "UNIFORM", - "VARYING", - "WRITE_ONLY", - "ADDRESS", - "SAMPLER", - "UNDEFINED" - }; - static char s[100]; - assert(Elements(files) == PROGRAM_FILE_MAX); -#if 0 - if (st->Size == 1) - _mesa_snprintf(s, "%s[%d]", files[st->File], st->Index); - else - _mesa_snprintf(s, "%s[%d..%d]", files[st->File], st->Index, - st->Index + st->Size - 1); -#endif - assert(st->File < (GLint) (sizeof(files) / sizeof(files[0]))); - _mesa_snprintf(s, sizeof(s), "%s[%d]", files[st->File], st->Index); - return s; -} - - -static void -spaces(int n) -{ - while (n-- > 0) { - printf(" "); - } -} - - -void -_slang_print_ir_tree(const slang_ir_node *n, int indent) -{ -#define IND 0 - - if (!n) - return; -#if !IND - if (n->Opcode != IR_SEQ) -#else - printf("%3d:", indent); -#endif - spaces(indent); - - switch (n->Opcode) { - case IR_SEQ: -#if IND - printf("SEQ at %p\n", (void*) n); -#endif - assert(n->Children[0]); - assert(n->Children[1]); - _slang_print_ir_tree(n->Children[0], indent + IND); - _slang_print_ir_tree(n->Children[1], indent + IND); - break; - case IR_SCOPE: - printf("NEW SCOPE\n"); - assert(!n->Children[1]); - _slang_print_ir_tree(n->Children[0], indent + 3); - break; - case IR_COPY: - printf("COPY\n"); - _slang_print_ir_tree(n->Children[0], indent+3); - _slang_print_ir_tree(n->Children[1], indent+3); - break; - case IR_LABEL: - printf("LABEL: %s\n", n->Label->Name); - break; - case IR_COND: - printf("COND\n"); - _slang_print_ir_tree(n->Children[0], indent + 3); - break; - - case IR_IF: - printf("IF \n"); - _slang_print_ir_tree(n->Children[0], indent+3); - spaces(indent); - printf("THEN\n"); - _slang_print_ir_tree(n->Children[1], indent+3); - if (n->Children[2]) { - spaces(indent); - printf("ELSE\n"); - _slang_print_ir_tree(n->Children[2], indent+3); - } - spaces(indent); - printf("ENDIF\n"); - break; - - case IR_BEGIN_SUB: - printf("BEGIN_SUB\n"); - break; - case IR_END_SUB: - printf("END_SUB\n"); - break; - case IR_RETURN: - printf("RETURN\n"); - break; - case IR_CALL: - printf("CALL %s\n", n->Label->Name); - break; - - case IR_LOOP: - printf("LOOP\n"); - _slang_print_ir_tree(n->Children[0], indent+3); - if (n->Children[1]) { - spaces(indent); - printf("TAIL:\n"); - _slang_print_ir_tree(n->Children[1], indent+3); - } - spaces(indent); - printf("ENDLOOP\n"); - break; - case IR_CONT: - printf("CONT\n"); - break; - case IR_BREAK: - printf("BREAK\n"); - break; - case IR_BREAK_IF_TRUE: - printf("BREAK_IF_TRUE\n"); - _slang_print_ir_tree(n->Children[0], indent+3); - break; - case IR_CONT_IF_TRUE: - printf("CONT_IF_TRUE\n"); - _slang_print_ir_tree(n->Children[0], indent+3); - break; - - case IR_VAR: - printf("VAR %s%s at %s store %p\n", - (n->Var ? (char *) n->Var->a_name : "TEMP"), - _mesa_swizzle_string(n->Store->Swizzle, 0, 0), - storage_string(n->Store), (void*) n->Store); - break; - case IR_VAR_DECL: - printf("VAR_DECL %s (%p) at %s store %p\n", - (n->Var ? (char *) n->Var->a_name : "TEMP"), - (void*) n->Var, storage_string(n->Store), - (void*) n->Store); - break; - case IR_FIELD: - printf("FIELD %s of\n", n->Field); - _slang_print_ir_tree(n->Children[0], indent+3); - break; - case IR_FLOAT: - printf("FLOAT %g %g %g %g\n", - n->Value[0], n->Value[1], n->Value[2], n->Value[3]); - break; - case IR_I_TO_F: - printf("INT_TO_FLOAT\n"); - _slang_print_ir_tree(n->Children[0], indent+3); - break; - case IR_F_TO_I: - printf("FLOAT_TO_INT\n"); - _slang_print_ir_tree(n->Children[0], indent+3); - break; - case IR_SWIZZLE: - printf("SWIZZLE %s of (store %p) \n", - _mesa_swizzle_string(n->Store->Swizzle, 0, 0), (void*) n->Store); - _slang_print_ir_tree(n->Children[0], indent + 3); - break; - default: - printf("%s (%p, %p) (store %p)\n", _slang_ir_name(n->Opcode), - (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store); - _slang_print_ir_tree(n->Children[0], indent+3); - _slang_print_ir_tree(n->Children[1], indent+3); - } -} diff --git a/src/mesa/slang/slang_ir.h b/src/mesa/slang/slang_ir.h deleted file mode 100644 index ce9a6c5a48..0000000000 --- a/src/mesa/slang/slang_ir.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_ir.h - * Mesa GLSL Intermediate Representation tree types and constants. - * \author Brian Paul - */ - - -#ifndef SLANG_IR_H -#define SLANG_IR_H - - -#include "main/imports.h" -#include "slang_compile.h" -#include "slang_label.h" -#include "main/mtypes.h" -#include "program/prog_instruction.h" - - -/** - * Intermediate Representation opcodes - */ -typedef enum -{ - IR_NOP = 0, - IR_SEQ, /* sequence (eval left, then right) */ - IR_SCOPE, /* new variable scope (one child) */ - - IR_LABEL, /* target of a jump or cjump */ - - IR_COND, /* conditional expression/predicate */ - - IR_IF, /* high-level IF/then/else */ - /* Children[0] = conditional expression */ - /* Children[1] = if-true part */ - /* Children[2] = if-else part, or NULL */ - - IR_BEGIN_SUB, /* begin subroutine */ - IR_END_SUB, /* end subroutine */ - IR_RETURN, /* return from subroutine */ - IR_CALL, /* call subroutine */ - - IR_LOOP, /* high-level loop-begin / loop-end */ - /* Children[0] = loop body */ - /* Children[1] = loop tail code, or NULL */ - - IR_CONT, /* continue loop */ - /* n->Parent = ptr to parent IR_LOOP Node */ - IR_BREAK, /* break loop */ - - IR_BREAK_IF_TRUE, /**< Children[0] = the condition expression */ - IR_CONT_IF_TRUE, - - IR_COPY, /**< assignment/copy */ - IR_MOVE, /**< assembly MOV instruction */ - - /* vector ops: */ - IR_ADD, /**< assembly ADD instruction */ - IR_SUB, - IR_MUL, - IR_DIV, - IR_DOT4, - IR_DOT3, - IR_DOT2, - IR_NRM4, - IR_NRM3, - IR_CROSS, /* vec3 cross product */ - IR_LRP, - IR_CLAMP, - IR_MIN, - IR_MAX, - IR_CMP, /* = (op0 < 0) ? op1 : op2 */ - IR_SEQUAL, /* Set if args are equal (vector) */ - IR_SNEQUAL, /* Set if args are not equal (vector) */ - IR_SGE, /* Set if greater or equal (vector) */ - IR_SGT, /* Set if greater than (vector) */ - IR_SLE, /* Set if less or equal (vector) */ - IR_SLT, /* Set if less than (vector) */ - IR_POW, /* x^y */ - IR_EXP, /* e^x */ - IR_EXP2, /* 2^x */ - IR_LOG2, /* log base 2 */ - IR_RSQ, /* 1/sqrt() */ - IR_RCP, /* reciprocol */ - IR_FLOOR, - IR_FRAC, - IR_ABS, /* absolute value */ - IR_NEG, /* negate */ - IR_DDX, /* derivative w.r.t. X */ - IR_DDY, /* derivative w.r.t. Y */ - IR_SIN, /* sine */ - IR_COS, /* cosine */ - IR_NOISE1, /* noise(x) */ - IR_NOISE2, /* noise(x, y) */ - IR_NOISE3, /* noise(x, y, z) */ - IR_NOISE4, /* noise(x, y, z, w) */ - - IR_EQUAL, /* boolean equality */ - IR_NOTEQUAL,/* boolean inequality */ - IR_NOT, /* boolean not */ - - IR_VAR, /* variable reference */ - IR_VAR_DECL,/* var declaration */ - - IR_ELEMENT, /* array element */ - IR_FIELD, /* struct field */ - IR_SWIZZLE, /* swizzled storage access */ - - IR_TEX, /* texture lookup */ - IR_TEXB, /* texture lookup with LOD bias */ - IR_TEXP, /* texture lookup with projection */ - - IR_TEX_SH, /* texture lookup, shadow compare */ - IR_TEXB_SH, /* texture lookup with LOD bias, shadow compare */ - IR_TEXP_SH, /* texture lookup with projection, shadow compare */ - - IR_FLOAT, - IR_I_TO_F, /* int[4] to float[4] conversion */ - IR_F_TO_I, /* float[4] to int[4] conversion */ - - IR_KILL, /* fragment kill/discard */ - - IR_EMIT_VERTEX, /* geometry shader: emit vertex */ - IR_END_PRIMITIVE /* geometry shader: end primitive */ -} slang_ir_opcode; - - -/** - * Describes where data/variables are stored in the various register files. - * - * In the simple case, the File, Index and Size fields indicate where - * a variable is stored. For example, a vec3 variable may be stored - * as (File=PROGRAM_TEMPORARY, Index=6, Size=3). Or, File[Index]. - * Or, a program input like color may be stored as - * (File=PROGRAM_INPUT,Index=3,Size=4); - * - * For single-float values, the Swizzle field indicates which component - * of the vector contains the float. - * - * If IsIndirect is set, the storage is accessed through an indirect - * register lookup. The value in question will be located at: - * File[Index + IndirectFile[IndirectIndex]] - * - * This is primary used for indexing arrays. For example, consider this - * GLSL code: - * uniform int i; - * float a[10]; - * float x = a[i]; - * - * here, storage for a[i] would be described by (File=PROGRAM_TEMPORAY, - * Index=aPos, IndirectFile=PROGRAM_UNIFORM, IndirectIndex=iPos), which - * would mean TEMP[aPos + UNIFORM[iPos]] - */ -struct slang_ir_storage_ -{ - gl_register_file File; /**< PROGRAM_TEMPORARY, PROGRAM_INPUT, etc */ - GLint Index; /**< -1 means unallocated */ - GLint Size; /**< number of floats or ints */ - GLuint Swizzle; /**< Swizzle AND writemask info */ - GLint RefCount; /**< Used during IR tree delete */ - - GLboolean RelAddr; /* we'll remove this eventually */ - - GLboolean IsIndirect; - gl_register_file IndirectFile; - GLint IndirectIndex; - GLuint IndirectSwizzle; - GLuint TexTarget; /**< If File==PROGRAM_SAMPLER, one of TEXTURE_x_INDEX */ - - /* Is the register two-dimensional and - * if so what's the second index */ - GLboolean Is2D; - GLint Index2; - - /** If Parent is non-null, Index is relative to parent. - * The other fields are ignored. - */ - struct slang_ir_storage_ *Parent; -}; - -typedef struct slang_ir_storage_ slang_ir_storage; - - -/** - * Intermediate Representation (IR) tree node - * Basically a binary tree, but IR_LRP and IR_CLAMP have three children. - */ -typedef struct slang_ir_node_ -{ - slang_ir_opcode Opcode; - struct slang_ir_node_ *Children[3]; - slang_ir_storage *Store; /**< location of result of this operation */ - GLint InstLocation; /**< Location of instruction emitted for this node */ - - /** special fields depending on Opcode: */ - const char *Field; /**< If Opcode == IR_FIELD */ - GLfloat Value[4]; /**< If Opcode == IR_FLOAT */ - slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */ - struct slang_ir_node_ *List; /**< For various linked lists */ - struct slang_ir_node_ *Parent; /**< Pointer to logical parent (ie. loop) */ - slang_label *Label; /**< Used for branches */ - const char *Comment; /**< If Opcode == IR_COMMENT */ -} slang_ir_node; - - - -/** - * Assembly and IR info - */ -typedef struct -{ - slang_ir_opcode IrOpcode; - const char *IrName; - gl_inst_opcode InstOpcode; - GLuint ResultSize, NumParams; -} slang_ir_info; - - - -extern const slang_ir_info * -_slang_ir_info(slang_ir_opcode opcode); - - -extern void -_slang_init_ir_storage(slang_ir_storage *st, - gl_register_file file, GLint index, GLint size, - GLuint swizzle); - -extern slang_ir_storage * -_slang_new_ir_storage(gl_register_file file, GLint index, GLint size); - - -extern slang_ir_storage * -_slang_new_ir_storage_swz(gl_register_file file, GLint index, GLint size, - GLuint swizzle); - -extern slang_ir_storage * -_slang_new_ir_storage_2d(gl_register_file file, GLint index, GLint index2d, - GLint size, GLuint swizzle); - -extern slang_ir_storage * -_slang_new_ir_storage_relative(GLint index, GLint size, - slang_ir_storage *parent); - - -extern slang_ir_storage * -_slang_new_ir_storage_indirect(gl_register_file file, - GLint index, - GLint size, - gl_register_file indirectFile, - GLint indirectIndex, - GLuint indirectSwizzle); - -extern slang_ir_storage * -_slang_new_ir_storage_sampler(GLint sampNum, GLuint texTarget, GLint size); - - -extern void -_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src); - - -extern void -_slang_free_ir_tree(slang_ir_node *n); - - -extern void -_slang_print_ir_tree(const slang_ir_node *n, int indent); - - -#endif /* SLANG_IR_H */ diff --git a/src/mesa/slang/slang_label.c b/src/mesa/slang/slang_label.c deleted file mode 100644 index 24881d5b6e..0000000000 --- a/src/mesa/slang/slang_label.c +++ /dev/null @@ -1,106 +0,0 @@ - - -/** - * Functions for managing instruction labels. - * Basically, this is used to manage the problem of forward branches where - * we have a branch instruciton but don't know the target address yet. - */ - - -#include "main/mtypes.h" -#include "program/prog_instruction.h" -#include "slang_label.h" -#include "slang_mem.h" - - - -slang_label * -_slang_label_new(const char *name) -{ - slang_label *l = (slang_label *) _slang_alloc(sizeof(slang_label)); - if (l) { - l->Name = _slang_strdup(name); - l->Location = -1; - } - return l; -} - -/** - * As above, but suffix the name with a unique number. - */ -slang_label * -_slang_label_new_unique(const char *name) -{ - static int id = 1; - slang_label *l = (slang_label *) _slang_alloc(sizeof(slang_label)); - if (l) { - l->Name = (char *) _slang_alloc(strlen(name) + 10); - if (!l->Name) { - free(l); - return NULL; - } - _mesa_snprintf(l->Name, strlen(name) + 10, "%s_%d", name, id); - id++; - l->Location = -1; - } - return l; -} - -void -_slang_label_delete(slang_label *l) -{ - if (l->Name) { - _slang_free(l->Name); - l->Name = NULL; - } - if (l->References) { - _slang_free(l->References); - l->References = NULL; - } - _slang_free(l); -} - - -void -_slang_label_add_reference(slang_label *l, GLuint inst) -{ - const GLuint oldSize = l->NumReferences * sizeof(GLuint); - assert(l->Location < 0); - l->References = _slang_realloc(l->References, - oldSize, oldSize + sizeof(GLuint)); - if (l->References) { - l->References[l->NumReferences] = inst; - l->NumReferences++; - } -} - - -GLint -_slang_label_get_location(const slang_label *l) -{ - return l->Location; -} - - -void -_slang_label_set_location(slang_label *l, GLint location, - struct gl_program *prog) -{ - GLuint i; - - assert(l->Location < 0); - assert(location >= 0); - - l->Location = location; - - /* for the instructions that were waiting to learn the label's location: */ - for (i = 0; i < l->NumReferences; i++) { - const GLuint j = l->References[i]; - prog->Instructions[j].BranchTarget = location; - } - - if (l->References) { - _slang_free(l->References); - l->References = NULL; - } -} diff --git a/src/mesa/slang/slang_label.h b/src/mesa/slang/slang_label.h deleted file mode 100644 index b0cff3a8e8..0000000000 --- a/src/mesa/slang/slang_label.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef SLANG_LABEL_H -#define SLANG_LABEL_H 1 - -#include "main/glheader.h" - -struct gl_program; - -struct slang_label_ -{ - char *Name; - GLint Location; - /** - * List of instruction references (numbered starting at zero) which need - * their BranchTarget field filled in with the location eventually - * assigned to the label. - */ - GLuint NumReferences; - GLuint *References; /** Array [NumReferences] */ -}; - -typedef struct slang_label_ slang_label; - - -extern slang_label * -_slang_label_new(const char *name); - -extern slang_label * -_slang_label_new_unique(const char *name); - -extern void -_slang_label_delete(slang_label *l); - -extern void -_slang_label_add_reference(slang_label *l, GLuint inst); - -extern GLint -_slang_label_get_location(const slang_label *l); - -extern void -_slang_label_set_location(slang_label *l, GLint location, - struct gl_program *prog); - - -#endif /* SLANG_LABEL_H */ diff --git a/src/mesa/slang/slang_link.c b/src/mesa/slang/slang_link.c deleted file mode 100644 index c21f67256a..0000000000 --- a/src/mesa/slang/slang_link.c +++ /dev/null @@ -1,1287 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_link.c - * GLSL linker - * \author Brian Paul - */ - -#include "main/imports.h" -#include "main/context.h" -#include "main/macros.h" -#include "main/shaderapi.h" -#include "main/shaderobj.h" -#include "main/uniforms.h" -#include "program/program.h" -#include "program/prog_instruction.h" -#include "program/prog_parameter.h" -#include "program/prog_print.h" -#include "program/prog_statevars.h" -#include "program/prog_uniform.h" -#include "slang_builtin.h" -#include "slang_link.h" - - -/** cast wrapper */ -static struct gl_vertex_program * -vertex_program(struct gl_program *prog) -{ - assert(prog->Target == GL_VERTEX_PROGRAM_ARB); - return (struct gl_vertex_program *) prog; -} - - -/** cast wrapper */ -static struct gl_fragment_program * -fragment_program(struct gl_program *prog) -{ - assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB); - return (struct gl_fragment_program *) prog; -} - -static struct gl_geometry_program * -geometry_program(struct gl_program *prog) -{ - assert(prog->Target == MESA_GEOMETRY_PROGRAM); - return (struct gl_geometry_program *)prog; -} - -/** - * Record a linking error. - */ -static void -link_error(struct gl_shader_program *shProg, const char *msg) -{ - if (shProg->InfoLog) { - free(shProg->InfoLog); - } - shProg->InfoLog = _mesa_strdup(msg); - shProg->LinkStatus = GL_FALSE; -} - - - -/** - * Check if the given bit is either set or clear in both bitfields. - */ -static GLboolean -bits_agree(GLbitfield flags1, GLbitfield flags2, GLbitfield bit) -{ - return (flags1 & bit) == (flags2 & bit); -} - - -/** - * Examine the outputs/varyings written by the vertex shader and - * append the names of those outputs onto the Varyings list. - * This will only capture the pre-defined/built-in varyings like - * gl_Position, not user-defined varyings. - */ -static void -update_varying_var_list(GLcontext *ctx, struct gl_shader_program *shProg) -{ - if (shProg->VertexProgram) { - GLbitfield64 written = shProg->VertexProgram->Base.OutputsWritten; - GLuint i; - for (i = 0; written && i < VERT_RESULT_MAX; i++) { - if (written & BITFIELD64_BIT(i)) { - const char *name = _slang_vertex_output_name(i); - if (name) - _mesa_add_varying(shProg->Varying, name, 1, GL_FLOAT_VEC4, 0x0); - written &= ~BITFIELD64_BIT(i); - } - } - } - if (shProg->GeometryProgram) { - GLbitfield64 written = shProg->GeometryProgram->Base.OutputsWritten; - GLuint i; - for (i = 0; written && i < GEOM_RESULT_MAX; i++) { - if (written & BITFIELD64_BIT(i)) { - const char *name = _slang_geometry_output_name(i); - if (name) - _mesa_add_varying(shProg->Varying, name, 1, GL_FLOAT_VEC4, 0x0); - written &= ~BITFIELD64_BIT(i); - } - } - } -} - - -/** - * Do link error checking related to transform feedback. - */ -static GLboolean -link_transform_feedback(GLcontext *ctx, struct gl_shader_program *shProg) -{ - GLbitfield varyingMask; - GLuint totalComps, maxComps, i; - - if (shProg->TransformFeedback.NumVarying == 0) { - /* nothing to do */ - return GL_TRUE; - } - - /* Check that there's a vertex shader */ - if (shProg->TransformFeedback.NumVarying > 0 && - !shProg->VertexProgram) { - link_error(shProg, "Transform feedback without vertex shader"); - return GL_FALSE; - } - - /* Check that all named variables exist, and that none are duplicated. - * Also, build a count of the number of varying components to feedback. - */ - totalComps = 0; - varyingMask = 0x0; - for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { - const GLchar *name = shProg->TransformFeedback.VaryingNames[i]; - GLint v = _mesa_lookup_parameter_index(shProg->Varying, -1, name); - struct gl_program_parameter *p; - - if (v < 0) { - char msg[100]; - _mesa_snprintf(msg, sizeof(msg), - "vertex shader does not emit %s", name); - link_error(shProg, msg); - return GL_FALSE; - } - - assert(v < MAX_VARYING); - - /* already seen this varying name? */ - if (varyingMask & (1 << v)) { - char msg[100]; - _mesa_snprintf(msg, sizeof(msg), - "duplicated transform feedback varying name: %s", - name); - link_error(shProg, msg); - return GL_FALSE; - } - - varyingMask |= (1 << v); - - p = &shProg->Varying->Parameters[v]; - - totalComps += _mesa_sizeof_glsl_type(p->DataType); - } - - if (shProg->TransformFeedback.BufferMode == GL_INTERLEAVED_ATTRIBS) - maxComps = ctx->Const.MaxTransformFeedbackInterleavedComponents; - else - maxComps = ctx->Const.MaxTransformFeedbackSeparateComponents; - - /* check max varying components against the limit */ - if (totalComps > maxComps) { - char msg[100]; - _mesa_snprintf(msg, sizeof(msg), - "Too many feedback components: %u, max is %u", - totalComps, maxComps); - link_error(shProg, msg); - return GL_FALSE; - } - - return GL_TRUE; -} - - -/** - * Linking varying vars involves rearranging varying vars so that the - * vertex program's output varyings matches the order of the fragment - * program's input varyings. - * We'll then rewrite instructions to replace PROGRAM_VARYING with either - * PROGRAM_INPUT or PROGRAM_OUTPUT depending on whether it's a vertex or - * fragment shader. - * This is also where we set program Input/OutputFlags to indicate - * which inputs are centroid-sampled, invariant, etc. - */ -static GLboolean -link_varying_vars(GLcontext *ctx, - struct gl_shader_program *shProg, struct gl_program *prog) -{ - GLuint *map, i, firstSrcVarying, firstDstVarying, newSrcFile, newDstFile; - GLbitfield *inOutFlags = NULL; - - map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint)); - if (!map) - return GL_FALSE; - - /* Varying variables are treated like other vertex program outputs - * (and like other fragment program inputs). The position of the - * first varying differs for vertex/fragment programs... - * Also, replace File=PROGRAM_VARYING with File=PROGRAM_INPUT/OUTPUT. - */ - if (prog->Target == GL_VERTEX_PROGRAM_ARB) { - firstSrcVarying = firstDstVarying = VERT_RESULT_VAR0; - newSrcFile = newDstFile = PROGRAM_OUTPUT; - inOutFlags = prog->OutputFlags; - } - else if (prog->Target == MESA_GEOMETRY_PROGRAM) { - firstSrcVarying = GEOM_ATTRIB_VAR0; - newSrcFile = PROGRAM_INPUT; - firstDstVarying = GEOM_RESULT_VAR0; - newDstFile = PROGRAM_OUTPUT; - } - else { - assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB); - firstSrcVarying = firstDstVarying = FRAG_ATTRIB_VAR0; - newSrcFile = newDstFile = PROGRAM_INPUT; - inOutFlags = prog->InputFlags; - } - - for (i = 0; i < prog->Varying->NumParameters; i++) { - /* see if this varying is in the linked varying list */ - const struct gl_program_parameter *var = prog->Varying->Parameters + i; - GLint j = _mesa_lookup_parameter_index(shProg->Varying, -1, var->Name); - if (j >= 0) { - /* varying is already in list, do some error checking */ - const struct gl_program_parameter *v = - &shProg->Varying->Parameters[j]; - if (var->Size != v->Size) { - link_error(shProg, "mismatched varying variable types"); - free(map); - return GL_FALSE; - } - if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_CENTROID)) { - char msg[100]; - _mesa_snprintf(msg, sizeof(msg), - "centroid modifier mismatch for '%s'", var->Name); - link_error(shProg, msg); - free(map); - return GL_FALSE; - } - if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_INVARIANT)) { - char msg[100]; - _mesa_snprintf(msg, sizeof(msg), - "invariant modifier mismatch for '%s'", var->Name); - link_error(shProg, msg); - free(map); - return GL_FALSE; - } - } - else { - /* not already in linked list */ - j = _mesa_add_varying(shProg->Varying, var->Name, var->Size, - var->DataType, var->Flags); - } - - if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) { - link_error(shProg, "Too many varying variables"); - free(map); - return GL_FALSE; - } - - /* Map varying[i] to varying[j]. - * Note: the loop here takes care of arrays or large (sz>4) vars. - */ - { - GLint sz = var->Size; - while (sz > 0) { - inOutFlags[firstDstVarying + j] = var->Flags; - /*printf("Link varying from %d to %d\n", i, j);*/ - map[i++] = j++; - sz -= 4; - } - i--; /* go back one */ - } - } - - - /* OK, now scan the program/shader instructions looking for varying vars, - * replacing the old index with the new index. - */ - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - GLuint j; - - if (inst->DstReg.File == PROGRAM_VARYING) { - inst->DstReg.File = newDstFile; - inst->DstReg.Index = map[ inst->DstReg.Index ] + firstDstVarying; - } - - for (j = 0; j < 3; j++) { - if (inst->SrcReg[j].File == PROGRAM_VARYING) { - inst->SrcReg[j].File = newSrcFile; - inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ] + firstSrcVarying; - } - } - } - - free(map); - - /* these will get recomputed before linking is completed */ - prog->InputsRead = 0x0; - prog->OutputsWritten = 0x0; - - return GL_TRUE; -} - - -/** - * Build the shProg->Uniforms list. - * This is basically a list/index of all uniforms found in either/both of - * the vertex and fragment shaders. - * - * About uniforms: - * Each uniform has two indexes, one that points into the vertex - * program's parameter array and another that points into the fragment - * program's parameter array. When the user changes a uniform's value - * we have to change the value in the vertex and/or fragment program's - * parameter array. - * - * This function will be called twice to set up the two uniform->parameter - * mappings. - * - * If a uniform is only present in the vertex program OR fragment program - * then the fragment/vertex parameter index, respectively, will be -1. - */ -static GLboolean -link_uniform_vars(GLcontext *ctx, - struct gl_shader_program *shProg, - struct gl_program *prog, - GLuint *numSamplers) -{ - GLuint samplerMap[200]; /* max number of samplers declared, not used */ - GLuint i; - - for (i = 0; i < prog->Parameters->NumParameters; i++) { - const struct gl_program_parameter *p = prog->Parameters->Parameters + i; - - /* - * XXX FIX NEEDED HERE - * We should also be adding a uniform if p->Type == PROGRAM_STATE_VAR. - * For example, modelview matrix, light pos, etc. - * Also, we need to update the state-var name-generator code to - * generate GLSL-style names, like "gl_LightSource[0].position". - * Furthermore, we'll need to fix the state-var's size/datatype info. - */ - - if ((p->Type == PROGRAM_UNIFORM || p->Type == PROGRAM_SAMPLER) - && p->Used) { - /* add this uniform, indexing into the target's Parameters list */ - struct gl_uniform *uniform = - _mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i); - if (uniform) - uniform->Initialized = p->Initialized; - } - - /* The samplerMap[] table we build here is used to remap/re-index - * sampler references by TEX instructions. - */ - if (p->Type == PROGRAM_SAMPLER && p->Used) { - /* Allocate a new sampler index */ - GLuint oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0]; - GLuint newSampNum = *numSamplers; - if (newSampNum >= ctx->Const.MaxTextureImageUnits) { - char s[100]; - _mesa_snprintf(s, sizeof(s), - "Too many texture samplers (%u, max is %u)", - newSampNum, ctx->Const.MaxTextureImageUnits); - link_error(shProg, s); - return GL_FALSE; - } - /* save old->new mapping in the table */ - if (oldSampNum < Elements(samplerMap)) - samplerMap[oldSampNum] = newSampNum; - /* update parameter's sampler index */ - prog->Parameters->ParameterValues[i][0] = (GLfloat) newSampNum; - (*numSamplers)++; - } - } - - /* OK, now scan the program/shader instructions looking for texture - * instructions using sampler vars. Replace old sampler indexes with - * new ones. - */ - prog->SamplersUsed = 0x0; - for (i = 0; i < prog->NumInstructions; i++) { - struct prog_instruction *inst = prog->Instructions + i; - if (_mesa_is_tex_instruction(inst->Opcode)) { - /* here, inst->TexSrcUnit is really the sampler unit */ - const GLint oldSampNum = inst->TexSrcUnit; - -#if 0 - printf("====== remap sampler from %d to %d\n", - inst->TexSrcUnit, samplerMap[ inst->TexSrcUnit ]); -#endif - - if (oldSampNum < Elements(samplerMap)) { - const GLuint newSampNum = samplerMap[oldSampNum]; - inst->TexSrcUnit = newSampNum; - prog->SamplerTargets[newSampNum] = inst->TexSrcTarget; - prog->SamplersUsed |= (1 << newSampNum); - if (inst->TexShadow) { - prog->ShadowSamplers |= (1 << newSampNum); - } - } - } - } - - return GL_TRUE; -} - - -/** - * Resolve binding of generic vertex attributes. - * For example, if the vertex shader declared "attribute vec4 foobar" we'll - * allocate a generic vertex attribute for "foobar" and plug that value into - * the vertex program instructions. - * But if the user called glBindAttributeLocation(), those bindings will - * have priority. - */ -static GLboolean -_slang_resolve_attributes(struct gl_shader_program *shProg, - const struct gl_program *origProg, - struct gl_program *linkedProg) -{ - GLint attribMap[MAX_VERTEX_GENERIC_ATTRIBS]; - GLuint i, j; - GLbitfield usedAttributes; /* generics only, not legacy attributes */ - GLbitfield inputsRead = 0x0; - - assert(origProg != linkedProg); - assert(origProg->Target == GL_VERTEX_PROGRAM_ARB); - assert(linkedProg->Target == GL_VERTEX_PROGRAM_ARB); - - if (!shProg->Attributes) - shProg->Attributes = _mesa_new_parameter_list(); - - if (linkedProg->Attributes) { - _mesa_free_parameter_list(linkedProg->Attributes); - } - linkedProg->Attributes = _mesa_new_parameter_list(); - - - /* Build a bitmask indicating which attribute indexes have been - * explicitly bound by the user with glBindAttributeLocation(). - */ - usedAttributes = 0x0; - for (i = 0; i < shProg->Attributes->NumParameters; i++) { - GLint attr = shProg->Attributes->Parameters[i].StateIndexes[0]; - usedAttributes |= (1 << attr); - } - - /* If gl_Vertex is used, that actually counts against the limit - * on generic vertex attributes. This avoids the ambiguity of - * whether glVertexAttrib4fv(0, v) sets legacy attribute 0 (vert pos) - * or generic attribute[0]. If gl_Vertex is used, we want the former. - */ - if (origProg->InputsRead & VERT_BIT_POS) { - usedAttributes |= 0x1; - } - - /* initialize the generic attribute map entries to -1 */ - for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) { - attribMap[i] = -1; - } - - /* - * Scan program for generic attribute references - */ - for (i = 0; i < linkedProg->NumInstructions; i++) { - struct prog_instruction *inst = linkedProg->Instructions + i; - for (j = 0; j < 3; j++) { - if (inst->SrcReg[j].File == PROGRAM_INPUT) { - inputsRead |= (1 << inst->SrcReg[j].Index); - } - - if (inst->SrcReg[j].File == PROGRAM_INPUT && - inst->SrcReg[j].Index >= VERT_ATTRIB_GENERIC0) { - /* - * OK, we've found a generic vertex attribute reference. - */ - const GLint k = inst->SrcReg[j].Index - VERT_ATTRIB_GENERIC0; - - GLint attr = attribMap[k]; - - if (attr < 0) { - /* Need to figure out attribute mapping now. - */ - const char *name = origProg->Attributes->Parameters[k].Name; - const GLint size = origProg->Attributes->Parameters[k].Size; - const GLenum type =origProg->Attributes->Parameters[k].DataType; - GLint index; - - /* See if there's a user-defined attribute binding for - * this name. - */ - index = _mesa_lookup_parameter_index(shProg->Attributes, - -1, name); - if (index >= 0) { - /* Found a user-defined binding */ - attr = shProg->Attributes->Parameters[index].StateIndexes[0]; - } - else { - /* No user-defined binding, choose our own attribute number. - * Start at 1 since generic attribute 0 always aliases - * glVertex/position. - */ - for (attr = 0; attr < MAX_VERTEX_GENERIC_ATTRIBS; attr++) { - if (((1 << attr) & usedAttributes) == 0) - break; - } - if (attr == MAX_VERTEX_GENERIC_ATTRIBS) { - link_error(shProg, "Too many vertex attributes"); - return GL_FALSE; - } - - /* mark this attribute as used */ - usedAttributes |= (1 << attr); - } - - attribMap[k] = attr; - - /* Save the final name->attrib binding so it can be queried - * with glGetAttributeLocation(). - */ - _mesa_add_attribute(linkedProg->Attributes, name, - size, type, attr); - } - - assert(attr >= 0); - - /* update the instruction's src reg */ - inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr; - } - } - } - - /* Handle pre-defined attributes here (gl_Vertex, gl_Normal, etc). - * When the user queries the active attributes we need to include both - * the user-defined attributes and the built-in ones. - */ - for (i = VERT_ATTRIB_POS; i < VERT_ATTRIB_GENERIC0; i++) { - if (inputsRead & (1 << i)) { - _mesa_add_attribute(linkedProg->Attributes, - _slang_vert_attrib_name(i), - 4, /* size in floats */ - _slang_vert_attrib_type(i), - -1 /* attrib/input */); - } - } - - return GL_TRUE; -} - - -/** - * Scan program instructions to update the program's NumTemporaries field. - * Note: this implemenation relies on the code generator allocating - * temps in increasing order (0, 1, 2, ... ). - */ -static void -_slang_count_temporaries(struct gl_program *prog) -{ - GLuint i, j; - GLint maxIndex = -1; - - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; - const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); - for (j = 0; j < numSrc; j++) { - if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { - if (maxIndex < inst->SrcReg[j].Index) - maxIndex = inst->SrcReg[j].Index; - } - if (inst->DstReg.File == PROGRAM_TEMPORARY) { - if (maxIndex < (GLint) inst->DstReg.Index) - maxIndex = inst->DstReg.Index; - } - } - } - - prog->NumTemporaries = (GLuint) (maxIndex + 1); -} - - -/** - * If an input attribute is indexed with relative addressing we have - * to compute a gl_program::InputsRead bitmask which reflects the fact - * that any input may be referenced by array element. Ex: gl_TexCoord[i]. - * This function computes the bitmask of potentially read inputs. - */ -static GLbitfield -get_inputs_read_mask(GLenum target, GLuint index, GLboolean relAddr) -{ - GLbitfield mask; - - mask = 1 << index; - - if (relAddr) { - if (target == GL_VERTEX_PROGRAM_ARB) { - switch (index) { - case VERT_ATTRIB_TEX0: - mask = ((1U << (VERT_ATTRIB_TEX7 + 1)) - 1) - - ((1U << VERT_ATTRIB_TEX0) - 1); - break; - case VERT_ATTRIB_GENERIC0: - /* different code to avoid uint overflow */ - mask = ~0x0U - ((1U << VERT_ATTRIB_GENERIC0) - 1); - break; - default: - ; /* a non-array input attribute */ - } - } - else if (target == GL_FRAGMENT_PROGRAM_ARB) { - switch (index) { - case FRAG_ATTRIB_TEX0: - mask = ((1U << (FRAG_ATTRIB_TEX7 + 1)) - 1) - - ((1U << FRAG_ATTRIB_TEX0) - 1); - break; - case FRAG_ATTRIB_VAR0: - mask = ((1U << (FRAG_ATTRIB_VAR0 + MAX_VARYING)) - 1) - - ((1U << FRAG_ATTRIB_VAR0) - 1); - break; - default: - ; /* a non-array input attribute */ - } - } - else if (target == MESA_GEOMETRY_PROGRAM) { - switch (index) { - case GEOM_ATTRIB_VAR0: - mask = ((1ULL << (GEOM_ATTRIB_VAR0 + MAX_VARYING)) - 1) - - ((1ULL << GEOM_ATTRIB_VAR0) - 1); - break; - default: - ; /* a non-array input attribute */ - } - } - else { - assert(0 && "bad program target"); - } - } - else { - } - - return mask; -} - - -/** - * If an output attribute is indexed with relative addressing we have - * to compute a gl_program::OutputsWritten bitmask which reflects the fact - * that any output may be referenced by array element. Ex: gl_TexCoord[i]. - * This function computes the bitmask of potentially written outputs. - */ -static GLbitfield64 -get_outputs_written_mask(GLenum target, GLuint index, GLboolean relAddr) -{ - GLbitfield64 mask; - - mask = BITFIELD64_BIT(index); - - if (relAddr) { - if (target == GL_VERTEX_PROGRAM_ARB) { - switch (index) { - case VERT_RESULT_TEX0: - mask = BITFIELD64_RANGE(VERT_RESULT_TEX0, - (VERT_RESULT_TEX0 - + MAX_TEXTURE_COORD_UNITS - 1)); - break; - case VERT_RESULT_VAR0: - mask = BITFIELD64_RANGE(VERT_RESULT_VAR0, - (VERT_RESULT_VAR0 + MAX_VARYING - 1)); - break; - default: - ; /* a non-array output attribute */ - } - } - else if (target == GL_FRAGMENT_PROGRAM_ARB) { - switch (index) { - case FRAG_RESULT_DATA0: - mask = BITFIELD64_RANGE(FRAG_RESULT_DATA0, - (FRAG_RESULT_DATA0 - + MAX_DRAW_BUFFERS - 1)); - break; - default: - ; /* a non-array output attribute */ - } - } - else if (target == MESA_GEOMETRY_PROGRAM) { - switch (index) { - case GEOM_RESULT_TEX0: - mask = BITFIELD64_RANGE(GEOM_RESULT_TEX0, - (GEOM_RESULT_TEX0 - + MAX_TEXTURE_COORD_UNITS - 1)); - break; - case GEOM_RESULT_VAR0: - mask = BITFIELD64_RANGE(GEOM_RESULT_VAR0, - (GEOM_RESULT_VAR0 + MAX_VARYING - 1)); - break; - default: - ; /* a non-array output attribute */ - } - } - else { - assert(0 && "bad program target"); - } - } - - return mask; -} - - -/** - * Scan program instructions to update the program's InputsRead and - * OutputsWritten fields. - */ -static void -_slang_update_inputs_outputs(struct gl_program *prog) -{ - GLuint i, j; - GLuint maxAddrReg = 0; - - prog->InputsRead = 0x0; - prog->OutputsWritten = 0x0; - - prog->IndirectRegisterFiles = 0x0; - - for (i = 0; i < prog->NumInstructions; i++) { - const struct prog_instruction *inst = prog->Instructions + i; - const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); - for (j = 0; j < numSrc; j++) { - if (inst->SrcReg[j].File == PROGRAM_INPUT) { - if (prog->Target == MESA_GEOMETRY_PROGRAM && - inst->SrcReg[j].HasIndex2) - prog->InputsRead |= get_inputs_read_mask(prog->Target, - inst->SrcReg[j].Index2, - inst->SrcReg[j].RelAddr2); - else - prog->InputsRead |= get_inputs_read_mask(prog->Target, - inst->SrcReg[j].Index, - inst->SrcReg[j].RelAddr); - } - else if (inst->SrcReg[j].File == PROGRAM_ADDRESS) { - maxAddrReg = MAX2(maxAddrReg, (GLuint) (inst->SrcReg[j].Index + 1)); - } - - if (inst->SrcReg[j].RelAddr) - prog->IndirectRegisterFiles |= (1 << inst->SrcReg[j].File); - } - - if (inst->DstReg.File == PROGRAM_OUTPUT) { - prog->OutputsWritten |= get_outputs_written_mask(prog->Target, - inst->DstReg.Index, - inst->DstReg.RelAddr); - } - else if (inst->DstReg.File == PROGRAM_ADDRESS) { - maxAddrReg = MAX2(maxAddrReg, inst->DstReg.Index + 1); - } - if (inst->DstReg.RelAddr) - prog->IndirectRegisterFiles |= (1 << inst->DstReg.File); - } - prog->NumAddressRegs = maxAddrReg; -} - - - -/** - * Remove extra #version directives from the concatenated source string. - * Disable the extra ones by converting first two chars to //, a comment. - * This is a bit of hack to work around a preprocessor bug that only - * allows one #version directive per source. - */ -static void -remove_extra_version_directives(GLchar *source) -{ - GLuint verCount = 0; - while (1) { - char *ver = strstr(source, "#version"); - if (ver) { - verCount++; - if (verCount > 1) { - ver[0] = '/'; - ver[1] = '/'; - } - source += 8; - } - else { - break; - } - } -} - -/* Returns the number of vertices per geometry shader - * input primitive. - * XXX: duplicated in Gallium in u_vertices_per_prim - * method. Once Mesa core will start using Gallium - * this should be removed - */ -static int -vertices_per_prim(int prim) -{ - switch (prim) { - case GL_POINTS: - return 1; - case GL_LINES: - return 2; - case GL_TRIANGLES: - return 3; - case GL_LINES_ADJACENCY_ARB: - return 4; - case GL_TRIANGLES_ADJACENCY_ARB: - return 6; - default: - ASSERT(!"Bad primitive"); - return 3; - } -} - -/** - * Return a new shader whose source code is the concatenation of - * all the shader sources of the given type. - */ -static struct gl_shader * -concat_shaders(struct gl_shader_program *shProg, GLenum shaderType) -{ - struct gl_shader *newShader; - const struct gl_shader *firstShader = NULL; - GLuint *shaderLengths; - GLchar *source; - GLuint totalLen = 0, len = 0; - GLuint i; - - shaderLengths = (GLuint *)malloc(shProg->NumShaders * sizeof(GLuint)); - if (!shaderLengths) { - return NULL; - } - - /* compute total size of new shader source code */ - for (i = 0; i < shProg->NumShaders; i++) { - const struct gl_shader *shader = shProg->Shaders[i]; - if (shader->Type == shaderType) { - shaderLengths[i] = strlen(shader->Source); - totalLen += shaderLengths[i]; - if (!firstShader) - firstShader = shader; - } - } - - if (totalLen == 0) { - free(shaderLengths); - return NULL; - } - - /* Geometry shader will inject definition of - * const int gl_VerticesIn */ - if (shaderType == GL_GEOMETRY_SHADER_ARB) { - totalLen += 32; - } - - source = (GLchar *) malloc(totalLen + 1); - if (!source) { - free(shaderLengths); - return NULL; - } - - /* concatenate shaders */ - for (i = 0; i < shProg->NumShaders; i++) { - const struct gl_shader *shader = shProg->Shaders[i]; - if (shader->Type == shaderType) { - memcpy(source + len, shader->Source, shaderLengths[i]); - len += shaderLengths[i]; - } - } - /* if it's geometry shader we need to inject definition - * of "const int gl_VerticesIn = X;" where X is the number - * of vertices per input primitive - */ - if (shaderType == GL_GEOMETRY_SHADER_ARB) { - GLchar gs_pre[32]; - GLuint num_verts = vertices_per_prim(shProg->Geom.InputType); - _mesa_snprintf(gs_pre, 31, - "const int gl_VerticesIn = %d;\n", num_verts); - memcpy(source + len, gs_pre, strlen(gs_pre)); - len += strlen(gs_pre); - } - source[len] = '\0'; - /* - printf("---NEW CONCATENATED SHADER---:\n%s\n------------\n", source); - */ - - free(shaderLengths); - - remove_extra_version_directives(source); - - newShader = CALLOC_STRUCT(gl_shader); - if (!newShader) { - free(source); - return NULL; - } - - newShader->Type = shaderType; - newShader->Source = source; - newShader->Pragmas = firstShader->Pragmas; - - return newShader; -} - -/** - * Search the shader program's list of shaders to find the one that - * defines main(). - * This will involve shader concatenation and recompilation if needed. - */ -static struct gl_shader * -get_main_shader(GLcontext *ctx, - struct gl_shader_program *shProg, GLenum type) -{ - struct gl_shader *shader = NULL; - GLuint i; - - /* - * Look for a shader that defines main() and has no unresolved references. - */ - for (i = 0; i < shProg->NumShaders; i++) { - shader = shProg->Shaders[i]; - if (shader->Type == type && - shader->Main && - !shader->UnresolvedRefs) { - /* All set! */ - return shader; - } - } - - /* - * There must have been unresolved references during the original - * compilation. Try concatenating all the shaders of the given type - * and recompile that. - */ - shader = concat_shaders(shProg, type); - - if (shader) { - _slang_compile(ctx, shader); - - /* Finally, check if recompiling failed */ - if (!shader->CompileStatus || - !shader->Main || - shader->UnresolvedRefs) { - link_error(shProg, "Unresolved symbols"); - ctx->Driver.DeleteShader(ctx, shader); - return NULL; - } - } - - return shader; -} - - -/** - * Shader linker. Currently: - * - * 1. The last attached vertex shader and fragment shader are linked. - * 2. Varying vars in the two shaders are combined so their locations - * agree between the vertex and fragment stages. They're treated as - * vertex program output attribs and as fragment program input attribs. - * 3. The vertex and fragment programs are cloned and modified to update - * src/dst register references so they use the new, linked varying - * storage locations. - */ -void -_slang_link(GLcontext *ctx, - GLhandleARB programObj, - struct gl_shader_program *shProg) -{ - const struct gl_vertex_program *vertProg = NULL; - const struct gl_fragment_program *fragProg = NULL; - const struct gl_geometry_program *geomProg = NULL; - GLboolean vertNotify = GL_TRUE, fragNotify = GL_TRUE, geomNotify = GL_TRUE; - GLuint numSamplers = 0; - GLuint i; - - _mesa_clear_shader_program_data(ctx, shProg); - - /* Initialize LinkStatus to "success". Will be cleared if error. */ - shProg->LinkStatus = GL_TRUE; - - /* check that all programs compiled successfully */ - for (i = 0; i < shProg->NumShaders; i++) { - if (!shProg->Shaders[i]->CompileStatus) { - link_error(shProg, "linking with uncompiled shader\n"); - return; - } - } - - shProg->Uniforms = _mesa_new_uniform_list(); - shProg->Varying = _mesa_new_parameter_list(); - - /* - * Find the vertex and fragment shaders which define main() - */ - { - struct gl_shader *vertShader, *fragShader, *geomShader; - vertShader = get_main_shader(ctx, shProg, GL_VERTEX_SHADER); - geomShader = get_main_shader(ctx, shProg, GL_GEOMETRY_SHADER_ARB); - fragShader = get_main_shader(ctx, shProg, GL_FRAGMENT_SHADER); - - if (vertShader) - vertProg = vertex_program(vertShader->Program); - if (geomShader) - geomProg = geometry_program(geomShader->Program); - if (fragShader) - fragProg = fragment_program(fragShader->Program); - if (!shProg->LinkStatus) - return; - } - -#if FEATURE_es2_glsl - /* must have both a vertex and fragment program for ES2 */ - if (ctx->API == API_OPENGLES2) { - if (!vertProg) { - link_error(shProg, "missing vertex shader\n"); - return; - } - if (!fragProg) { - link_error(shProg, "missing fragment shader\n"); - return; - } - } -#endif - - /* - * Make copies of the vertex/fragment programs now since we'll be - * changing src/dst registers after merging the uniforms and varying vars. - */ - _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); - if (vertProg) { - struct gl_vertex_program *linked_vprog = - _mesa_clone_vertex_program(ctx, vertProg); - shProg->VertexProgram = linked_vprog; /* refcount OK */ - /* vertex program ID not significant; just set Id for debugging purposes */ - shProg->VertexProgram->Base.Id = shProg->Name; - ASSERT(shProg->VertexProgram->Base.RefCount == 1); - } - _mesa_reference_geomprog(ctx, &shProg->GeometryProgram, NULL); - if (geomProg) { - struct gl_geometry_program *linked_gprog = - _mesa_clone_geometry_program(ctx, geomProg); - shProg->GeometryProgram = linked_gprog; /* refcount OK */ - shProg->GeometryProgram->Base.Id = shProg->Name; - ASSERT(shProg->GeometryProgram->Base.RefCount == 1); - } - _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); - if (fragProg) { - struct gl_fragment_program *linked_fprog = - _mesa_clone_fragment_program(ctx, fragProg); - shProg->FragmentProgram = linked_fprog; /* refcount OK */ - /* vertex program ID not significant; just set Id for debugging purposes */ - shProg->FragmentProgram->Base.Id = shProg->Name; - ASSERT(shProg->FragmentProgram->Base.RefCount == 1); - } - - /* link varying vars */ - if (shProg->VertexProgram) { - if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base)) - return; - } - if (shProg->GeometryProgram) { - if (!link_varying_vars(ctx, shProg, &shProg->GeometryProgram->Base)) - return; - } - if (shProg->FragmentProgram) { - if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base)) - return; - } - - /* link uniform vars */ - if (shProg->VertexProgram) { - if (!link_uniform_vars(ctx, shProg, &shProg->VertexProgram->Base, - &numSamplers)) { - return; - } - } - if (shProg->GeometryProgram) { - if (!link_uniform_vars(ctx, shProg, &shProg->GeometryProgram->Base, - &numSamplers)) { - return; - } - } - if (shProg->FragmentProgram) { - if (!link_uniform_vars(ctx, shProg, &shProg->FragmentProgram->Base, - &numSamplers)) { - return; - } - } - - /*_mesa_print_uniforms(shProg->Uniforms);*/ - - if (shProg->VertexProgram) { - if (!_slang_resolve_attributes(shProg, &vertProg->Base, - &shProg->VertexProgram->Base)) { - return; - } - } - - if (shProg->VertexProgram) { - _slang_update_inputs_outputs(&shProg->VertexProgram->Base); - _slang_count_temporaries(&shProg->VertexProgram->Base); - if (!(shProg->VertexProgram->Base.OutputsWritten - & BITFIELD64_BIT(VERT_RESULT_HPOS))) { - /* the vertex program did not compute a vertex position */ - link_error(shProg, - "gl_Position was not written by vertex shader\n"); - return; - } - } - if (shProg->GeometryProgram) { - if (!shProg->VertexProgram) { - link_error(shProg, - "Geometry shader without a vertex shader is illegal!\n"); - return; - } - if (shProg->Geom.VerticesOut == 0) { - link_error(shProg, - "GEOMETRY_VERTICES_OUT is zero\n"); - return; - } - - _slang_count_temporaries(&shProg->GeometryProgram->Base); - _slang_update_inputs_outputs(&shProg->GeometryProgram->Base); - } - if (shProg->FragmentProgram) { - _slang_count_temporaries(&shProg->FragmentProgram->Base); - _slang_update_inputs_outputs(&shProg->FragmentProgram->Base); - } - - /* Check that all the varying vars needed by the fragment shader are - * actually produced by the vertex shader. - */ - if (shProg->FragmentProgram) { - const GLbitfield varyingRead - = shProg->FragmentProgram->Base.InputsRead >> FRAG_ATTRIB_VAR0; - const GLbitfield64 varyingWritten = shProg->VertexProgram ? - shProg->VertexProgram->Base.OutputsWritten >> VERT_RESULT_VAR0 : 0x0; - if ((varyingRead & varyingWritten) != varyingRead) { - link_error(shProg, - "Fragment program using varying vars not written by vertex shader\n"); - return; - } - } - - /* check that gl_FragColor and gl_FragData are not both written to */ - if (shProg->FragmentProgram) { - const GLbitfield64 outputsWritten = - shProg->FragmentProgram->Base.OutputsWritten; - if ((outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) && - (outputsWritten >= BITFIELD64_BIT(FRAG_RESULT_DATA0))) { - link_error(shProg, "Fragment program cannot write both gl_FragColor" - " and gl_FragData[].\n"); - return; - } - } - - update_varying_var_list(ctx, shProg); - - /* checks related to transform feedback */ - if (!link_transform_feedback(ctx, shProg)) { - return; - } - - if (fragProg && shProg->FragmentProgram) { - /* Compute initial program's TexturesUsed info */ - _mesa_update_shader_textures_used(&shProg->FragmentProgram->Base); - - /* notify driver that a new fragment program has been compiled/linked */ - vertNotify = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, - &shProg->FragmentProgram->Base); - if (ctx->Shader.Flags & GLSL_DUMP) { - fprintf(stderr, "Mesa pre-link fragment program:\n"); - _mesa_print_program(&fragProg->Base); - _mesa_print_program_parameters(ctx, &fragProg->Base); - - fprintf(stderr, "Mesa post-link fragment program:\n"); - _mesa_print_program(&shProg->FragmentProgram->Base); - _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base); - } - } - - if (geomProg && shProg->GeometryProgram) { - /* Compute initial program's TexturesUsed info */ - _mesa_update_shader_textures_used(&shProg->GeometryProgram->Base); - - /* Copy some per-shader-program fields to per-shader object */ - shProg->GeometryProgram->VerticesOut = shProg->Geom.VerticesOut; - shProg->GeometryProgram->InputType = shProg->Geom.InputType; - shProg->GeometryProgram->OutputType = shProg->Geom.OutputType; - - /* notify driver that a new fragment program has been compiled/linked */ - geomNotify = ctx->Driver.ProgramStringNotify(ctx, MESA_GEOMETRY_PROGRAM, - &shProg->GeometryProgram->Base); - if (ctx->Shader.Flags & GLSL_DUMP) { - fprintf(stderr, "Mesa pre-link geometry program:\n"); - _mesa_print_program(&geomProg->Base); - _mesa_print_program_parameters(ctx, &geomProg->Base); - - fprintf(stderr, "Mesa post-link geometry program:\n"); - _mesa_print_program(&shProg->GeometryProgram->Base); - _mesa_print_program_parameters(ctx, &shProg->GeometryProgram->Base); - } - } - - if (vertProg && shProg->VertexProgram) { - /* Compute initial program's TexturesUsed info */ - _mesa_update_shader_textures_used(&shProg->VertexProgram->Base); - - /* notify driver that a new vertex program has been compiled/linked */ - fragNotify = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, - &shProg->VertexProgram->Base); - if (ctx->Shader.Flags & GLSL_DUMP) { - fprintf(stderr, "Mesa pre-link vertex program:\n"); - _mesa_print_program(&vertProg->Base); - _mesa_print_program_parameters(ctx, &vertProg->Base); - - fprintf(stderr, "Mesa post-link vertex program:\n"); - _mesa_print_program(&shProg->VertexProgram->Base); - _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base); - } - } - - /* Debug: */ - if (0) { - if (shProg->VertexProgram) - _mesa_postprocess_program(ctx, &shProg->VertexProgram->Base); - if (shProg->FragmentProgram) - _mesa_postprocess_program(ctx, &shProg->FragmentProgram->Base); - } - - if (ctx->Shader.Flags & GLSL_DUMP) { - fprintf(stderr, "Varying vars:\n"); - _mesa_print_parameter_list(shProg->Varying); - if (shProg->InfoLog) { - fprintf(stderr, "Info Log: %s\n", shProg->InfoLog); - } - } - - if (!vertNotify || !fragNotify || !geomNotify) { - /* driver rejected one/both of the vertex/fragment programs */ - if (!shProg->InfoLog) { - link_error(shProg, - "Vertex, geometry and/or fragment program rejected by driver\n"); - } - } - else { - shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram); - } -} - diff --git a/src/mesa/slang/slang_log.c b/src/mesa/slang/slang_log.c deleted file mode 100644 index 9ff21417bc..0000000000 --- a/src/mesa/slang/slang_log.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "main/imports.h" -#include "slang_log.h" -#include "slang_utility.h" - - - -static char *out_of_memory = "Error: Out of memory.\n"; - -void -slang_info_log_construct(slang_info_log * log) -{ - log->text = NULL; - log->dont_free_text = GL_FALSE; - log->error_flag = GL_FALSE; -} - -void -slang_info_log_destruct(slang_info_log * log) -{ - if (!log->dont_free_text) - free(log->text); -} - -static int -slang_info_log_message(slang_info_log * log, const char *prefix, - const char *msg) -{ - GLuint size; - - if (log->dont_free_text) - return 0; - size = slang_string_length(msg) + 2; - if (prefix != NULL) - size += slang_string_length(prefix) + 2; - if (log->text != NULL) { - GLuint old_len = slang_string_length(log->text); - log->text = (char *) - _mesa_realloc(log->text, old_len + 1, old_len + size); - } - else { - log->text = (char *) (malloc(size)); - if (log->text != NULL) - log->text[0] = '\0'; - } - if (log->text == NULL) - return 0; - if (prefix != NULL) { - slang_string_concat(log->text, prefix); - slang_string_concat(log->text, ": "); - } - slang_string_concat(log->text, msg); - slang_string_concat(log->text, "\n"); - - return 1; -} - -int -slang_info_log_print(slang_info_log * log, const char *msg, ...) -{ - va_list va; - char buf[1024]; - - va_start(va, msg); - vsprintf(buf, msg, va); - va_end(va); - return slang_info_log_message(log, NULL, buf); -} - -int -slang_info_log_error(slang_info_log * log, const char *msg, ...) -{ - va_list va; - char buf[1024]; - - va_start(va, msg); - vsprintf(buf, msg, va); - va_end(va); - log->error_flag = GL_TRUE; - if (slang_info_log_message(log, "Error", buf)) - return 1; - slang_info_log_memory(log); - return 0; -} - -int -slang_info_log_warning(slang_info_log * log, const char *msg, ...) -{ - va_list va; - char buf[1024]; - - va_start(va, msg); - vsprintf(buf, msg, va); - va_end(va); - if (slang_info_log_message(log, "Warning", buf)) - return 1; - slang_info_log_memory(log); - return 0; -} - -void -slang_info_log_memory(slang_info_log * log) -{ - if (!slang_info_log_message(log, "Error", "Out of memory.")) { - log->dont_free_text = GL_TRUE; - log->error_flag = GL_TRUE; - log->text = out_of_memory; - } -} diff --git a/src/mesa/slang/slang_mem.c b/src/mesa/slang/slang_mem.c deleted file mode 100644 index 5eaa7c4427..0000000000 --- a/src/mesa/slang/slang_mem.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_mem.c - * - * Memory manager for GLSL compiler. The general idea is to do all - * allocations out of a large pool then just free the pool when done - * compiling to avoid intricate malloc/free tracking and memory leaks. - * - * \author Brian Paul - */ - -#include "main/context.h" -#include "main/macros.h" -#include "slang_mem.h" - - -#define GRANULARITY 8 -#define ROUND_UP(B) ( ((B) + (GRANULARITY - 1)) & ~(GRANULARITY - 1) ) - - -/** If 1, use conventional malloc/free. Helpful for debugging */ -#define USE_MALLOC_FREE 0 - - -struct slang_mempool_ -{ - GLuint Size, Used, Count, Largest; - char *Data; - struct slang_mempool_ *Next; -}; - - -slang_mempool * -_slang_new_mempool(GLuint initialSize) -{ - slang_mempool *pool = (slang_mempool *) calloc(1, sizeof(slang_mempool)); - if (pool) { - pool->Data = (char *) calloc(1, initialSize); - /*printf("ALLOC MEMPOOL %d at %p\n", initialSize, pool->Data);*/ - if (!pool->Data) { - free(pool); - return NULL; - } - pool->Size = initialSize; - pool->Used = 0; - } - return pool; -} - - -void -_slang_delete_mempool(slang_mempool *pool) -{ - GLuint total = 0; - while (pool) { - slang_mempool *next = pool->Next; - /* - printf("DELETE MEMPOOL %u / %u count=%u largest=%u\n", - pool->Used, pool->Size, pool->Count, pool->Largest); - */ - total += pool->Used; - free(pool->Data); - free(pool); - pool = next; - } - /*printf("TOTAL ALLOCATED: %u\n", total);*/ -} - - -#ifdef DEBUG -static void -check_zero(const char *addr, GLuint n) -{ - GLuint i; - for (i = 0; i < n; i++) { - assert(addr[i]==0); - } -} -#endif - - -#ifdef DEBUG -static GLboolean -is_valid_address(const slang_mempool *pool, void *addr) -{ - while (pool) { - if ((char *) addr >= pool->Data && - (char *) addr < pool->Data + pool->Used) - return GL_TRUE; - - pool = pool->Next; - } - return GL_FALSE; -} -#endif - - -/** - * Alloc 'bytes' from shader mempool. - */ -void * -_slang_alloc(GLuint bytes) -{ -#if USE_MALLOC_FREE - return calloc(1, bytes); -#else - slang_mempool *pool; - GET_CURRENT_CONTEXT(ctx); - pool = (slang_mempool *) ctx->Shader.MemPool; - - if (bytes == 0) - bytes = 1; - - while (pool) { - if (pool->Used + bytes <= pool->Size) { - /* found room */ - void *addr = (void *) (pool->Data + pool->Used); -#ifdef DEBUG - check_zero((char*) addr, bytes); -#endif - pool->Used += ROUND_UP(bytes); - pool->Largest = MAX2(pool->Largest, bytes); - pool->Count++; - /*printf("alloc %u Used %u\n", bytes, pool->Used);*/ - return addr; - } - else if (pool->Next) { - /* try next block */ - pool = pool->Next; - } - else { - /* alloc new pool */ - const GLuint sz = MAX2(bytes, pool->Size); - pool->Next = _slang_new_mempool(sz); - if (!pool->Next) { - /* we're _really_ out of memory */ - return NULL; - } - else { - pool = pool->Next; - pool->Largest = bytes; - pool->Count++; - pool->Used = ROUND_UP(bytes); -#ifdef DEBUG - check_zero((char*) pool->Data, bytes); -#endif - return (void *) pool->Data; - } - } - } - return NULL; -#endif -} - - -void * -_slang_realloc(void *oldBuffer, GLuint oldSize, GLuint newSize) -{ -#if USE_MALLOC_FREE - return _mesa_realloc(oldBuffer, oldSize, newSize); -#else - GET_CURRENT_CONTEXT(ctx); - slang_mempool *pool = (slang_mempool *) ctx->Shader.MemPool; - (void) pool; - - if (newSize < oldSize) { - return oldBuffer; - } - else { - const GLuint copySize = (oldSize < newSize) ? oldSize : newSize; - void *newBuffer = _slang_alloc(newSize); - - if (oldBuffer) - ASSERT(is_valid_address(pool, oldBuffer)); - - if (newBuffer && oldBuffer && copySize > 0) - memcpy(newBuffer, oldBuffer, copySize); - - return newBuffer; - } -#endif -} - - -/** - * Clone string, storing in current mempool. - */ -char * -_slang_strdup(const char *s) -{ - if (s) { - size_t l = strlen(s); - char *s2 = (char *) _slang_alloc(l + 1); - if (s2) - strcpy(s2, s); - return s2; - } - else { - return NULL; - } -} - - -/** - * Don't actually free memory, but mark it (for debugging). - */ -void -_slang_free(void *addr) -{ -#if USE_MALLOC_FREE - free(addr); -#else - if (addr) { - GET_CURRENT_CONTEXT(ctx); - slang_mempool *pool = (slang_mempool *) ctx->Shader.MemPool; - (void) pool; - ASSERT(is_valid_address(pool, addr)); - } -#endif -} diff --git a/src/mesa/slang/slang_print.c b/src/mesa/slang/slang_print.c deleted file mode 100644 index 6b34f395fd..0000000000 --- a/src/mesa/slang/slang_print.c +++ /dev/null @@ -1,883 +0,0 @@ - -/** - * Dump/print a slang_operation tree - */ - - -#include "main/imports.h" -#include "slang_compile.h" -#include "slang_print.h" - - -static void -spaces(int n) -{ - while (n--) - printf(" "); -} - - -static void -print_type(const slang_fully_specified_type *t) -{ - switch (t->qualifier) { - case SLANG_QUAL_NONE: - /*printf("");*/ - break; - case SLANG_QUAL_CONST: - printf("const "); - break; - case SLANG_QUAL_ATTRIBUTE: - printf("attrib "); - break; - case SLANG_QUAL_VARYING: - printf("varying "); - break; - case SLANG_QUAL_UNIFORM: - printf("uniform "); - break; - case SLANG_QUAL_OUT: - printf("output "); - break; - case SLANG_QUAL_INOUT: - printf("inout "); - break; - case SLANG_QUAL_FIXEDOUTPUT: - printf("fixedoutput"); - break; - case SLANG_QUAL_FIXEDINPUT: - printf("fixedinput"); - break; - default: - printf("unknown qualifer!"); - } - - switch (t->specifier.type) { - case SLANG_SPEC_VOID: - printf("void"); - break; - case SLANG_SPEC_BOOL: - printf("bool"); - break; - case SLANG_SPEC_BVEC2: - printf("bvec2"); - break; - case SLANG_SPEC_BVEC3: - printf("bvec3"); - break; - case SLANG_SPEC_BVEC4: - printf("bvec4"); - break; - case SLANG_SPEC_INT: - printf("int"); - break; - case SLANG_SPEC_IVEC2: - printf("ivec2"); - break; - case SLANG_SPEC_IVEC3: - printf("ivec3"); - break; - case SLANG_SPEC_IVEC4: - printf("ivec4"); - break; - case SLANG_SPEC_FLOAT: - printf("float"); - break; - case SLANG_SPEC_VEC2: - printf("vec2"); - break; - case SLANG_SPEC_VEC3: - printf("vec3"); - break; - case SLANG_SPEC_VEC4: - printf("vec4"); - break; - case SLANG_SPEC_MAT2: - printf("mat2"); - break; - case SLANG_SPEC_MAT3: - printf("mat3"); - break; - case SLANG_SPEC_MAT4: - printf("mat4"); - break; - case SLANG_SPEC_MAT23: - printf("mat2x3"); - break; - case SLANG_SPEC_MAT32: - printf("mat3x2"); - break; - case SLANG_SPEC_MAT24: - printf("mat2x4"); - break; - case SLANG_SPEC_MAT42: - printf("mat4x2"); - break; - case SLANG_SPEC_MAT34: - printf("mat3x4"); - break; - case SLANG_SPEC_MAT43: - printf("mat4x3"); - break; - case SLANG_SPEC_SAMPLER_1D: - printf("sampler1D"); - break; - case SLANG_SPEC_SAMPLER_2D: - printf("sampler2D"); - break; - case SLANG_SPEC_SAMPLER_3D: - printf("sampler3D"); - break; - case SLANG_SPEC_SAMPLER_CUBE: - printf("samplerCube"); - break; - case SLANG_SPEC_SAMPLER_1D_SHADOW: - printf("sampler1DShadow"); - break; - case SLANG_SPEC_SAMPLER_2D_SHADOW: - printf("sampler2DShadow"); - break; - case SLANG_SPEC_STRUCT: - printf("struct"); - break; - case SLANG_SPEC_ARRAY: - printf("array"); - break; - default: - printf("unknown type"); - } - /*printf("\n");*/ -} - - -static void -print_variable(const slang_variable *v, int indent) -{ - spaces(indent); - printf("VAR "); - print_type(&v->type); - printf(" %s (at %p)", (char *) v->a_name, (void *) v); - if (v->initializer) { - printf(" :=\n"); - slang_print_tree(v->initializer, indent + 3); - } - else { - printf(";\n"); - } -} - - -static void -print_binary(const slang_operation *op, const char *oper, int indent) -{ - assert(op->num_children == 2); -#if 0 - printf("binary at %p locals=%p outer=%p\n", - (void *) op, - (void *) op->locals, - (void *) op->locals->outer_scope); -#endif - slang_print_tree(&op->children[0], indent + 3); - spaces(indent); - printf("%s at %p locals=%p outer=%p\n", - oper, (void *) op, (void *) op->locals, - (void *) op->locals->outer_scope); - slang_print_tree(&op->children[1], indent + 3); -} - - -static void -print_generic2(const slang_operation *op, const char *oper, - const char *s, int indent) -{ - GLuint i; - if (oper) { - spaces(indent); - printf("%s %s at %p locals=%p outer=%p\n", - oper, s, (void *) op, (void *) op->locals, - (void *) op->locals->outer_scope); - } - for (i = 0; i < op->num_children; i++) { - spaces(indent); - printf("//child %u of %u:\n", i, op->num_children); - slang_print_tree(&op->children[i], indent); - } -} - -static void -print_generic(const slang_operation *op, const char *oper, int indent) -{ - print_generic2(op, oper, "", indent); -} - - -static const slang_variable_scope * -find_scope(const slang_variable_scope *s, slang_atom name) -{ - GLuint i; - for (i = 0; i < s->num_variables; i++) { - if (s->variables[i]->a_name == name) - return s; - } - if (s->outer_scope) - return find_scope(s->outer_scope, name); - else - return NULL; -} - -static const slang_variable * -find_var(const slang_variable_scope *s, slang_atom name) -{ - GLuint i; - for (i = 0; i < s->num_variables; i++) { - if (s->variables[i]->a_name == name) - return s->variables[i]; - } - if (s->outer_scope) - return find_var(s->outer_scope, name); - else - return NULL; -} - - -void -slang_print_tree(const slang_operation *op, int indent) -{ - GLuint i; - - switch (op->type) { - - case SLANG_OPER_NONE: - spaces(indent); - printf("SLANG_OPER_NONE\n"); - break; - - case SLANG_OPER_BLOCK_NO_NEW_SCOPE: - spaces(indent); - printf("{ locals=%p outer=%p\n", (void*)op->locals, (void*)op->locals->outer_scope); - print_generic(op, NULL, indent+3); - spaces(indent); - printf("}\n"); - break; - - case SLANG_OPER_BLOCK_NEW_SCOPE: - case SLANG_OPER_NON_INLINED_CALL: - spaces(indent); - printf("{{ // new scope locals=%p outer=%p: ", - (void *) op->locals, - (void *) op->locals->outer_scope); - for (i = 0; i < op->locals->num_variables; i++) { - printf("%s ", (char *) op->locals->variables[i]->a_name); - } - printf("\n"); - print_generic(op, NULL, indent+3); - spaces(indent); - printf("}}\n"); - break; - - case SLANG_OPER_VARIABLE_DECL: - assert(op->num_children == 0 || op->num_children == 1); - { - slang_variable *v; - v = _slang_variable_locate(op->locals, op->a_id, GL_TRUE); - if (v) { - const slang_variable_scope *scope; - spaces(indent); - printf("DECL (locals=%p outer=%p) ", (void*)op->locals, (void*) op->locals->outer_scope); - print_type(&v->type); - printf(" %s (%p)", (char *) op->a_id, - (void *) find_var(op->locals, op->a_id)); - - scope = find_scope(op->locals, op->a_id); - printf(" (in scope %p) ", (void *) scope); - assert(scope); - if (op->num_children == 1) { - printf(" :=\n"); - slang_print_tree(&op->children[0], indent + 3); - } - else if (v->initializer) { - printf(" := INITIALIZER\n"); - slang_print_tree(v->initializer, indent + 3); - } - else { - printf(";\n"); - } - /* - spaces(indent); - printf("TYPE: "); - print_type(&v->type); - spaces(indent); - printf("ADDR: %d size: %d\n", v->address, v->size); - */ - } - else { - spaces(indent); - printf("DECL %s (anonymous variable!!!!)\n", (char *) op->a_id); - } - } - break; - - case SLANG_OPER_ASM: - spaces(indent); - printf("ASM: %s at %p locals=%p outer=%p\n", - (char *) op->a_id, - (void *) op, - (void *) op->locals, - (void *) op->locals->outer_scope); - print_generic(op, "ASM", indent+3); - break; - - case SLANG_OPER_BREAK: - spaces(indent); - printf("BREAK\n"); - break; - - case SLANG_OPER_CONTINUE: - spaces(indent); - printf("CONTINUE\n"); - break; - - case SLANG_OPER_DISCARD: - spaces(indent); - printf("DISCARD\n"); - break; - - case SLANG_OPER_RETURN: - spaces(indent); - printf("RETURN\n"); - if (op->num_children > 0) - slang_print_tree(&op->children[0], indent + 3); - break; - - case SLANG_OPER_RETURN_INLINED: - spaces(indent); - printf("RETURN_INLINED\n"); - if (op->num_children > 0) - slang_print_tree(&op->children[0], indent + 3); - break; - - case SLANG_OPER_LABEL: - spaces(indent); - printf("LABEL %s\n", (char *) op->a_id); - break; - - case SLANG_OPER_EXPRESSION: - spaces(indent); - printf("EXPR: locals=%p outer=%p\n", - (void *) op->locals, - (void *) op->locals->outer_scope); - /*print_generic(op, "SLANG_OPER_EXPRESSION", indent);*/ - slang_print_tree(&op->children[0], indent + 3); - break; - - case SLANG_OPER_IF: - spaces(indent); - printf("IF\n"); - slang_print_tree(&op->children[0], indent + 3); - spaces(indent); - printf("THEN\n"); - slang_print_tree(&op->children[1], indent + 3); - spaces(indent); - printf("ELSE\n"); - slang_print_tree(&op->children[2], indent + 3); - spaces(indent); - printf("ENDIF\n"); - break; - - case SLANG_OPER_WHILE: - assert(op->num_children == 2); - spaces(indent); - printf("WHILE LOOP: locals = %p\n", (void *) op->locals); - indent += 3; - spaces(indent); - printf("WHILE cond:\n"); - slang_print_tree(&op->children[0], indent + 3); - spaces(indent); - printf("WHILE body:\n"); - slang_print_tree(&op->children[1], indent + 3); - indent -= 3; - spaces(indent); - printf("END WHILE LOOP\n"); - break; - - case SLANG_OPER_DO: - spaces(indent); - printf("DO LOOP: locals = %p\n", (void *) op->locals); - indent += 3; - spaces(indent); - printf("DO body:\n"); - slang_print_tree(&op->children[0], indent + 3); - spaces(indent); - printf("DO cond:\n"); - slang_print_tree(&op->children[1], indent + 3); - indent -= 3; - spaces(indent); - printf("END DO LOOP\n"); - break; - - case SLANG_OPER_FOR: - spaces(indent); - printf("FOR LOOP: locals = %p\n", (void *) op->locals); - indent += 3; - spaces(indent); - printf("FOR init:\n"); - slang_print_tree(&op->children[0], indent + 3); - spaces(indent); - printf("FOR condition:\n"); - slang_print_tree(&op->children[1], indent + 3); - spaces(indent); - printf("FOR step:\n"); - slang_print_tree(&op->children[2], indent + 3); - spaces(indent); - printf("FOR body:\n"); - slang_print_tree(&op->children[3], indent + 3); - indent -= 3; - spaces(indent); - printf("ENDFOR\n"); - /* - print_generic(op, "FOR", indent + 3); - */ - break; - - case SLANG_OPER_VOID: - spaces(indent); - printf("(oper-void)\n"); - break; - - case SLANG_OPER_LITERAL_BOOL: - spaces(indent); - printf("LITERAL ("); - for (i = 0; i < op->literal_size; i++) - printf("%s ", op->literal[0] ? "TRUE" : "FALSE"); - printf(")\n"); - - break; - - case SLANG_OPER_LITERAL_INT: - spaces(indent); - printf("LITERAL ("); - for (i = 0; i < op->literal_size; i++) - printf("%d ", (int) op->literal[i]); - printf(")\n"); - break; - - case SLANG_OPER_LITERAL_FLOAT: - spaces(indent); - printf("LITERAL ("); - for (i = 0; i < op->literal_size; i++) - printf("%f ", op->literal[i]); - printf(")\n"); - break; - - case SLANG_OPER_IDENTIFIER: - { - const slang_variable_scope *scope; - spaces(indent); - if (op->var && op->var->a_name) { - scope = find_scope(op->locals, op->var->a_name); - printf("VAR %s (in scope %p)\n", (char *) op->var->a_name, - (void *) scope); - assert(scope); - } - else { - scope = find_scope(op->locals, op->a_id); - printf("VAR' %s (in scope %p) locals=%p outer=%p\n", - (char *) op->a_id, - (void *) scope, - (void *) op->locals, - (void *) op->locals->outer_scope); - /*assert(scope);*/ - } - } - break; - - case SLANG_OPER_SEQUENCE: - print_generic(op, "COMMA-SEQ", indent+3); - break; - - case SLANG_OPER_ASSIGN: - spaces(indent); - printf("ASSIGNMENT locals=%p outer=%p\n", - (void *) op->locals, - (void *) op->locals->outer_scope); - print_binary(op, ":=", indent); - break; - - case SLANG_OPER_ADDASSIGN: - spaces(indent); - printf("ASSIGN\n"); - print_binary(op, "+=", indent); - break; - - case SLANG_OPER_SUBASSIGN: - spaces(indent); - printf("ASSIGN\n"); - print_binary(op, "-=", indent); - break; - - case SLANG_OPER_MULASSIGN: - spaces(indent); - printf("ASSIGN\n"); - print_binary(op, "*=", indent); - break; - - case SLANG_OPER_DIVASSIGN: - spaces(indent); - printf("ASSIGN\n"); - print_binary(op, "/=", indent); - break; - - /*SLANG_OPER_MODASSIGN,*/ - /*SLANG_OPER_LSHASSIGN,*/ - /*SLANG_OPER_RSHASSIGN,*/ - /*SLANG_OPER_ORASSIGN,*/ - /*SLANG_OPER_XORASSIGN,*/ - /*SLANG_OPER_ANDASSIGN,*/ - case SLANG_OPER_SELECT: - spaces(indent); - printf("SLANG_OPER_SELECT n=%d\n", op->num_children); - assert(op->num_children == 3); - slang_print_tree(&op->children[0], indent+3); - spaces(indent); - printf("?\n"); - slang_print_tree(&op->children[1], indent+3); - spaces(indent); - printf(":\n"); - slang_print_tree(&op->children[2], indent+3); - break; - - case SLANG_OPER_LOGICALOR: - print_binary(op, "||", indent); - break; - - case SLANG_OPER_LOGICALXOR: - print_binary(op, "^^", indent); - break; - - case SLANG_OPER_LOGICALAND: - print_binary(op, "&&", indent); - break; - - /*SLANG_OPER_BITOR*/ - /*SLANG_OPER_BITXOR*/ - /*SLANG_OPER_BITAND*/ - case SLANG_OPER_EQUAL: - print_binary(op, "==", indent); - break; - - case SLANG_OPER_NOTEQUAL: - print_binary(op, "!=", indent); - break; - - case SLANG_OPER_LESS: - print_binary(op, "<", indent); - break; - - case SLANG_OPER_GREATER: - print_binary(op, ">", indent); - break; - - case SLANG_OPER_LESSEQUAL: - print_binary(op, "<=", indent); - break; - - case SLANG_OPER_GREATEREQUAL: - print_binary(op, ">=", indent); - break; - - /*SLANG_OPER_LSHIFT*/ - /*SLANG_OPER_RSHIFT*/ - case SLANG_OPER_ADD: - print_binary(op, "+", indent); - break; - - case SLANG_OPER_SUBTRACT: - print_binary(op, "-", indent); - break; - - case SLANG_OPER_MULTIPLY: - print_binary(op, "*", indent); - break; - - case SLANG_OPER_DIVIDE: - print_binary(op, "/", indent); - break; - - /*SLANG_OPER_MODULUS*/ - case SLANG_OPER_PREINCREMENT: - spaces(indent); - printf("PRE++\n"); - slang_print_tree(&op->children[0], indent+3); - break; - - case SLANG_OPER_PREDECREMENT: - spaces(indent); - printf("PRE--\n"); - slang_print_tree(&op->children[0], indent+3); - break; - - case SLANG_OPER_PLUS: - spaces(indent); - printf("SLANG_OPER_PLUS\n"); - break; - - case SLANG_OPER_MINUS: - spaces(indent); - printf("SLANG_OPER_MINUS\n"); - break; - - /*SLANG_OPER_COMPLEMENT*/ - case SLANG_OPER_NOT: - spaces(indent); - printf("NOT\n"); - slang_print_tree(&op->children[0], indent+3); - break; - - case SLANG_OPER_SUBSCRIPT: - spaces(indent); - printf("SLANG_OPER_SUBSCRIPT locals=%p outer=%p\n", - (void *) op->locals, - (void *) op->locals->outer_scope); - print_generic(op, NULL, indent+3); - break; - - case SLANG_OPER_CALL: -#if 0 - slang_function *fun - = _slang_function_locate(A->space.funcs, oper->a_id, - oper->children, - oper->num_children, &A->space, A->atoms); -#endif - spaces(indent); - printf("CALL %s(\n", (char *) op->a_id); - for (i = 0; i < op->num_children; i++) { - slang_print_tree(&op->children[i], indent+3); - if (i + 1 < op->num_children) { - spaces(indent + 3); - printf(",\n"); - } - } - spaces(indent); - printf(")\n"); - break; - - case SLANG_OPER_METHOD: - spaces(indent); - printf("METHOD CALL %s.%s\n", (char *) op->a_obj, (char *) op->a_id); - break; - - case SLANG_OPER_FIELD: - spaces(indent); - printf("FIELD %s of\n", (char*) op->a_id); - slang_print_tree(&op->children[0], indent+3); - break; - - case SLANG_OPER_POSTINCREMENT: - spaces(indent); - printf("POST++\n"); - slang_print_tree(&op->children[0], indent+3); - break; - - case SLANG_OPER_POSTDECREMENT: - spaces(indent); - printf("POST--\n"); - slang_print_tree(&op->children[0], indent+3); - break; - - default: - printf("unknown op->type %d\n", (int) op->type); - } - -} - - - -void -slang_print_function(const slang_function *f, GLboolean body) -{ - GLuint i; - -#if 0 - if (strcmp((char *) f->header.a_name, "main") != 0) - return; -#endif - - printf("FUNCTION %s ( scope=%p\n", - (char *) f->header.a_name, (void *) f->parameters); - - for (i = 0; i < f->param_count; i++) { - print_variable(f->parameters->variables[i], 3); - } - - printf(") param scope = %p\n", (void *) f->parameters); - - if (body && f->body) - slang_print_tree(f->body, 0); -} - - - - - -const char * -slang_type_qual_string(slang_type_qualifier q) -{ - switch (q) { - case SLANG_QUAL_NONE: - return "none"; - case SLANG_QUAL_CONST: - return "const"; - case SLANG_QUAL_ATTRIBUTE: - return "attribute"; - case SLANG_QUAL_VARYING: - return "varying"; - case SLANG_QUAL_UNIFORM: - return "uniform"; - case SLANG_QUAL_OUT: - return "out"; - case SLANG_QUAL_INOUT: - return "inout"; - case SLANG_QUAL_FIXEDOUTPUT: - return "fixedoutput"; - case SLANG_QUAL_FIXEDINPUT: - return "fixedinputk"; - default: - return "qual?"; - } -} - - -static const char * -slang_type_string(slang_type_specifier_type t) -{ - switch (t) { - case SLANG_SPEC_VOID: - return "void"; - case SLANG_SPEC_BOOL: - return "bool"; - case SLANG_SPEC_BVEC2: - return "bvec2"; - case SLANG_SPEC_BVEC3: - return "bvec3"; - case SLANG_SPEC_BVEC4: - return "bvec4"; - case SLANG_SPEC_INT: - return "int"; - case SLANG_SPEC_IVEC2: - return "ivec2"; - case SLANG_SPEC_IVEC3: - return "ivec3"; - case SLANG_SPEC_IVEC4: - return "ivec4"; - case SLANG_SPEC_FLOAT: - return "float"; - case SLANG_SPEC_VEC2: - return "vec2"; - case SLANG_SPEC_VEC3: - return "vec3"; - case SLANG_SPEC_VEC4: - return "vec4"; - case SLANG_SPEC_MAT2: - return "mat2"; - case SLANG_SPEC_MAT3: - return "mat3"; - case SLANG_SPEC_MAT4: - return "mat4"; - case SLANG_SPEC_SAMPLER_1D: - return "sampler1D"; - case SLANG_SPEC_SAMPLER_2D: - return "sampler2D"; - case SLANG_SPEC_SAMPLER_3D: - return "sampler3D"; - case SLANG_SPEC_SAMPLER_CUBE: - return "samplerCube"; - case SLANG_SPEC_SAMPLER_1D_SHADOW: - return "sampler1DShadow"; - case SLANG_SPEC_SAMPLER_2D_SHADOW: - return "sampler2DShadow"; - case SLANG_SPEC_SAMPLER_RECT: - return "sampler2DRect"; - case SLANG_SPEC_SAMPLER_RECT_SHADOW: - return "sampler2DRectShadow"; - case SLANG_SPEC_STRUCT: - return "struct"; - case SLANG_SPEC_ARRAY: - return "array"; - default: - return "type?"; - } -} - - -static const char * -slang_fq_type_string(const slang_fully_specified_type *t) -{ - static char str[1000]; - _mesa_snprintf(str, sizeof(str), "%s %s", slang_type_qual_string(t->qualifier), - slang_type_string(t->specifier.type)); - return str; -} - - -void -slang_print_type(const slang_fully_specified_type *t) -{ - printf("%s %s", slang_type_qual_string(t->qualifier), - slang_type_string(t->specifier.type)); -} - - -#if 0 -static char * -slang_var_string(const slang_variable *v) -{ - static char str[1000]; - _mesa_snprintf(str, sizeof(str), "%s : %s", - (char *) v->a_name, - slang_fq_type_string(&v->type)); - return str; -} -#endif - - -void -slang_print_variable(const slang_variable *v) -{ - printf("Name: %s\n", (char *) v->a_name); - printf("Type: %s\n", slang_fq_type_string(&v->type)); -} - - -void -_slang_print_var_scope(const slang_variable_scope *vars, int indent) -{ - GLuint i; - - spaces(indent); - printf("Var scope %p %d vars:\n", (void *) vars, vars->num_variables); - for (i = 0; i < vars->num_variables; i++) { - spaces(indent + 3); - printf("%s (at %p)\n", (char *) vars->variables[i]->a_name, (void*) (vars->variables + i)); - } - spaces(indent + 3); - printf("outer_scope = %p\n", (void*) vars->outer_scope); - - if (vars->outer_scope) { - /*spaces(indent + 3);*/ - _slang_print_var_scope(vars->outer_scope, indent + 3); - } -} - - - -int -slang_checksum_tree(const slang_operation *op) -{ - int s = op->num_children; - GLuint i; - - for (i = 0; i < op->num_children; i++) { - s += slang_checksum_tree(&op->children[i]); - } - return s; -} diff --git a/src/mesa/slang/slang_print.h b/src/mesa/slang/slang_print.h deleted file mode 100644 index 99da304143..0000000000 --- a/src/mesa/slang/slang_print.h +++ /dev/null @@ -1,35 +0,0 @@ - - -#ifndef SLANG_PRINT -#define SLANG_PRINT - -#include "main/glheader.h" -#include "slang_compile_function.h" -#include "slang_compile_operation.h" -#include "slang_compile_variable.h" -#include "slang_typeinfo.h" - -extern void -slang_print_function(const slang_function *f, GLboolean body); - -extern void -slang_print_tree(const slang_operation *op, int indent); - -extern const char * -slang_type_qual_string(slang_type_qualifier q); - -extern void -slang_print_type(const slang_fully_specified_type *t); - -extern void -slang_print_variable(const slang_variable *v); - -extern void -_slang_print_var_scope(const slang_variable_scope *s, int indent); - - -extern int -slang_checksum_tree(const slang_operation *op); - -#endif /* SLANG_PRINT */ - diff --git a/src/mesa/slang/slang_simplify.c b/src/mesa/slang/slang_simplify.c deleted file mode 100644 index 13b9ca3c87..0000000000 --- a/src/mesa/slang/slang_simplify.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * Functions for constant folding, built-in constant lookup, and function - * call casting. - */ - - -#include "main/imports.h" -#include "main/macros.h" -#include "main/get.h" -#include "slang_compile.h" -#include "slang_codegen.h" -#include "slang_simplify.h" -#include "slang_print.h" - - -#ifndef GL_MAX_FRAGMENT_UNIFORM_VECTORS -#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD -#endif -#ifndef GL_MAX_VERTEX_UNIFORM_VECTORS -#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB -#endif -#ifndef GL_MAX_VARYING_VECTORS -#define GL_MAX_VARYING_VECTORS 0x8DFC -#endif - - -/** - * Lookup the value of named constant, such as gl_MaxLights. - * \return value of constant, or -1 if unknown - */ -GLint -_slang_lookup_constant(const char *name) -{ - struct constant_info { - const char *Name; - const GLenum Token; - }; - static const struct constant_info info[] = { - { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES }, - { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS }, - { "gl_MaxDrawBuffers", GL_MAX_DRAW_BUFFERS }, - { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS }, - { "gl_MaxLights", GL_MAX_LIGHTS }, - { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS }, - { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS }, - { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS }, - { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS }, - { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS }, - { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS }, - { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS }, -#if FEATURE_es2_glsl - { "gl_MaxVertexUniformVectors", GL_MAX_VERTEX_UNIFORM_VECTORS }, - { "gl_MaxVaryingVectors", GL_MAX_VARYING_VECTORS }, - { "gl_MaxFragmentUniformVectors", GL_MAX_FRAGMENT_UNIFORM_VECTORS }, -#endif - { NULL, 0 } - }; - GLuint i; - - for (i = 0; info[i].Name; i++) { - if (strcmp(info[i].Name, name) == 0) { - /* found */ - GLint values[16]; - values[0] = -1; - _mesa_GetIntegerv(info[i].Token, values); - ASSERT(values[0] >= 0); /* sanity check that glGetFloatv worked */ - return values[0]; - } - } - return -1; -} - - -static slang_operation_type -literal_type(slang_operation_type t1, slang_operation_type t2) -{ - if (t1 == SLANG_OPER_LITERAL_FLOAT || t2 == SLANG_OPER_LITERAL_FLOAT) - return SLANG_OPER_LITERAL_FLOAT; - else - return SLANG_OPER_LITERAL_INT; -} - - -/** - * Recursively traverse an AST tree, applying simplifications wherever - * possible. - * At the least, we do constant folding. We need to do that much so that - * compile-time expressions can be evaluated for things like array - * declarations. I.e.: float foo[3 + 5]; - */ -void -_slang_simplify(slang_operation *oper, - const slang_name_space * space, - slang_atom_pool * atoms) -{ - GLboolean isFloat[4]; - GLboolean isBool[4]; - GLuint i, n; - - if (oper->type == SLANG_OPER_IDENTIFIER) { - /* see if it's a named constant */ - GLint value = _slang_lookup_constant((char *) oper->a_id); - /*printf("value[%s] = %d\n", (char*) oper->a_id, value);*/ - if (value >= 0) { - oper->literal[0] = - oper->literal[1] = - oper->literal[2] = - oper->literal[3] = (GLfloat) value; - oper->type = SLANG_OPER_LITERAL_INT; - return; - } - /* look for user-defined constant */ - { - slang_variable *var; - var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); - if (var) { - if (var->type.qualifier == SLANG_QUAL_CONST && - var->initializer && - (var->initializer->type == SLANG_OPER_LITERAL_INT || - var->initializer->type == SLANG_OPER_LITERAL_FLOAT)) { - oper->literal[0] = var->initializer->literal[0]; - oper->literal[1] = var->initializer->literal[1]; - oper->literal[2] = var->initializer->literal[2]; - oper->literal[3] = var->initializer->literal[3]; - oper->literal_size = var->initializer->literal_size; - oper->type = var->initializer->type; - /* - printf("value[%s] = %f\n", - (char*) oper->a_id, oper->literal[0]); - */ - return; - } - } - } - } - - /* first, simplify children */ - for (i = 0; i < oper->num_children; i++) { - _slang_simplify(&oper->children[i], space, atoms); - } - - /* examine children */ - n = MIN2(oper->num_children, 4); - for (i = 0; i < n; i++) { - isFloat[i] = (oper->children[i].type == SLANG_OPER_LITERAL_FLOAT || - oper->children[i].type == SLANG_OPER_LITERAL_INT); - isBool[i] = (oper->children[i].type == SLANG_OPER_LITERAL_BOOL); - } - - if (oper->num_children == 2 && isFloat[0] && isFloat[1]) { - /* probably simple arithmetic */ - switch (oper->type) { - case SLANG_OPER_ADD: - for (i = 0; i < 4; i++) { - oper->literal[i] - = oper->children[0].literal[i] + oper->children[1].literal[i]; - } - oper->literal_size = oper->children[0].literal_size; - oper->type = literal_type(oper->children[0].type, - oper->children[1].type); - slang_operation_destruct(oper); /* frees unused children */ - return; - case SLANG_OPER_SUBTRACT: - for (i = 0; i < 4; i++) { - oper->literal[i] - = oper->children[0].literal[i] - oper->children[1].literal[i]; - } - oper->literal_size = oper->children[0].literal_size; - oper->type = literal_type(oper->children[0].type, - oper->children[1].type); - slang_operation_destruct(oper); - return; - case SLANG_OPER_MULTIPLY: - for (i = 0; i < 4; i++) { - oper->literal[i] - = oper->children[0].literal[i] * oper->children[1].literal[i]; - } - oper->literal_size = oper->children[0].literal_size; - oper->type = literal_type(oper->children[0].type, - oper->children[1].type); - slang_operation_destruct(oper); - return; - case SLANG_OPER_DIVIDE: - for (i = 0; i < 4; i++) { - oper->literal[i] - = oper->children[0].literal[i] / oper->children[1].literal[i]; - } - oper->literal_size = oper->children[0].literal_size; - oper->type = literal_type(oper->children[0].type, - oper->children[1].type); - slang_operation_destruct(oper); - return; - default: - ; /* nothing */ - } - } - - if (oper->num_children == 1 && isFloat[0]) { - switch (oper->type) { - case SLANG_OPER_MINUS: - for (i = 0; i < 4; i++) { - oper->literal[i] = -oper->children[0].literal[i]; - } - oper->literal_size = oper->children[0].literal_size; - slang_operation_destruct(oper); - oper->type = SLANG_OPER_LITERAL_FLOAT; - return; - case SLANG_OPER_PLUS: - COPY_4V(oper->literal, oper->children[0].literal); - oper->literal_size = oper->children[0].literal_size; - slang_operation_destruct(oper); - oper->type = SLANG_OPER_LITERAL_FLOAT; - return; - default: - ; /* nothing */ - } - } - - if (oper->num_children == 2 && isBool[0] && isBool[1]) { - /* simple boolean expression */ - switch (oper->type) { - case SLANG_OPER_LOGICALAND: - for (i = 0; i < 4; i++) { - const GLint a = oper->children[0].literal[i] ? 1 : 0; - const GLint b = oper->children[1].literal[i] ? 1 : 0; - oper->literal[i] = (GLfloat) (a && b); - } - oper->literal_size = oper->children[0].literal_size; - slang_operation_destruct(oper); - oper->type = SLANG_OPER_LITERAL_BOOL; - return; - case SLANG_OPER_LOGICALOR: - for (i = 0; i < 4; i++) { - const GLint a = oper->children[0].literal[i] ? 1 : 0; - const GLint b = oper->children[1].literal[i] ? 1 : 0; - oper->literal[i] = (GLfloat) (a || b); - } - oper->literal_size = oper->children[0].literal_size; - slang_operation_destruct(oper); - oper->type = SLANG_OPER_LITERAL_BOOL; - return; - case SLANG_OPER_LOGICALXOR: - for (i = 0; i < 4; i++) { - const GLint a = oper->children[0].literal[i] ? 1 : 0; - const GLint b = oper->children[1].literal[i] ? 1 : 0; - oper->literal[i] = (GLfloat) (a ^ b); - } - oper->literal_size = oper->children[0].literal_size; - slang_operation_destruct(oper); - oper->type = SLANG_OPER_LITERAL_BOOL; - return; - default: - ; /* nothing */ - } - } - - if (oper->num_children == 4 - && isFloat[0] && isFloat[1] && isFloat[2] && isFloat[3]) { - /* vec4(flt, flt, flt, flt) constructor */ - if (oper->type == SLANG_OPER_CALL) { - if (strcmp((char *) oper->a_id, "vec4") == 0) { - oper->literal[0] = oper->children[0].literal[0]; - oper->literal[1] = oper->children[1].literal[0]; - oper->literal[2] = oper->children[2].literal[0]; - oper->literal[3] = oper->children[3].literal[0]; - oper->literal_size = 4; - slang_operation_destruct(oper); - oper->type = SLANG_OPER_LITERAL_FLOAT; - return; - } - } - } - - if (oper->num_children == 3 && isFloat[0] && isFloat[1] && isFloat[2]) { - /* vec3(flt, flt, flt) constructor */ - if (oper->type == SLANG_OPER_CALL) { - if (strcmp((char *) oper->a_id, "vec3") == 0) { - oper->literal[0] = oper->children[0].literal[0]; - oper->literal[1] = oper->children[1].literal[0]; - oper->literal[2] = oper->children[2].literal[0]; - oper->literal[3] = oper->literal[2]; - oper->literal_size = 3; - slang_operation_destruct(oper); - oper->type = SLANG_OPER_LITERAL_FLOAT; - return; - } - } - } - - if (oper->num_children == 2 && isFloat[0] && isFloat[1]) { - /* vec2(flt, flt) constructor */ - if (oper->type == SLANG_OPER_CALL) { - if (strcmp((char *) oper->a_id, "vec2") == 0) { - oper->literal[0] = oper->children[0].literal[0]; - oper->literal[1] = oper->children[1].literal[0]; - oper->literal[2] = oper->literal[1]; - oper->literal[3] = oper->literal[1]; - oper->literal_size = 2; - slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */ - oper->type = SLANG_OPER_LITERAL_FLOAT; - assert(oper->num_children == 0); - return; - } - } - } - - if (oper->num_children == 1 && isFloat[0]) { - /* vec2/3/4(flt, flt) constructor */ - if (oper->type == SLANG_OPER_CALL) { - const char *func = (const char *) oper->a_id; - if (strncmp(func, "vec", 3) == 0 && func[3] >= '2' && func[3] <= '4') { - oper->literal[0] = - oper->literal[1] = - oper->literal[2] = - oper->literal[3] = oper->children[0].literal[0]; - oper->literal_size = func[3] - '0'; - assert(oper->literal_size >= 2); - assert(oper->literal_size <= 4); - slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */ - oper->type = SLANG_OPER_LITERAL_FLOAT; - assert(oper->num_children == 0); - return; - } - } - } -} - - - -/** - * Insert casts to try to adapt actual parameters to formal parameters for a - * function call when an exact match for the parameter types is not found. - * Example: - * void foo(int i, bool b) {} - * x = foo(3.15, 9); - * Gets translated into: - * x = foo(int(3.15), bool(9)) - */ -GLboolean -_slang_cast_func_params(slang_operation *callOper, const slang_function *fun, - const slang_name_space * space, - slang_atom_pool * atoms, slang_info_log *log) -{ - const GLboolean haveRetValue = _slang_function_has_return_value(fun); - const int numParams = fun->param_count - haveRetValue; - int i; - int dbg = 0; - - if (dbg) - printf("Adapt call of %d args to func %s (%d params)\n", - callOper->num_children, (char*) fun->header.a_name, numParams); - - for (i = 0; i < numParams; i++) { - slang_typeinfo argType; - slang_variable *paramVar = fun->parameters->variables[i]; - - /* Get type of arg[i] */ - if (!slang_typeinfo_construct(&argType)) - return GL_FALSE; - if (!_slang_typeof_operation(&callOper->children[i], space, - &argType, atoms, log)) { - slang_typeinfo_destruct(&argType); - return GL_FALSE; - } - - /* see if arg type matches parameter type */ - if (!slang_type_specifier_equal(&argType.spec, - ¶mVar->type.specifier)) { - /* need to adapt arg type to match param type */ - const char *constructorName = - slang_type_specifier_type_to_string(paramVar->type.specifier.type); - slang_operation *child = slang_operation_new(1); - - if (dbg) - printf("Need to adapt types of arg %d\n", i); - - slang_operation_copy(child, &callOper->children[i]); - child->locals->outer_scope = callOper->children[i].locals; - -#if 0 - if (_slang_sizeof_type_specifier(&argType.spec) > - _slang_sizeof_type_specifier(¶mVar->type.specifier)) { - } -#endif - - callOper->children[i].type = SLANG_OPER_CALL; - callOper->children[i].a_id = slang_atom_pool_atom(atoms, constructorName); - callOper->children[i].num_children = 1; - callOper->children[i].children = child; - } - - slang_typeinfo_destruct(&argType); - } - - if (dbg) { - printf("===== New call to %s with cast arguments ===============\n", - (char*) fun->header.a_name); - slang_print_tree(callOper, 5); - } - - return GL_TRUE; -} - - -/** - * Adapt the arguments for a function call to match the parameters of - * the given function. - * This is for: - * 1. converting/casting argument types to match parameters - * 2. breaking up vector/matrix types into individual components to - * satisfy constructors. - */ -GLboolean -_slang_adapt_call(slang_operation *callOper, const slang_function *fun, - const slang_name_space * space, - slang_atom_pool * atoms, slang_info_log *log) -{ - const GLboolean haveRetValue = _slang_function_has_return_value(fun); - const int numParams = fun->param_count - haveRetValue; - int i; - int dbg = 0; - - if (dbg) - printf("Adapt %d args to %d parameters for %s\n", - callOper->num_children, numParams, (char *) fun->header.a_name); - - /* Only try adapting for constructors */ - if (fun->kind != SLANG_FUNC_CONSTRUCTOR) - return GL_FALSE; - - if (callOper->num_children != numParams) { - /* number of arguments doesn't match number of parameters */ - - /* For constructor calls, we can try to unroll vector/matrix args - * into individual floats/ints and try to match the function params. - */ - for (i = 0; i < numParams; i++) { - slang_typeinfo argType; - GLint argSz, j; - - /* Get type of arg[i] */ - if (!slang_typeinfo_construct(&argType)) - return GL_FALSE; - if (!_slang_typeof_operation(&callOper->children[i], space, - &argType, atoms, log)) { - slang_typeinfo_destruct(&argType); - return GL_FALSE; - } - - /* - paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier); - assert(paramSz == 1); - */ - argSz = _slang_sizeof_type_specifier(&argType.spec); - if (argSz > 1) { - slang_operation origArg; - /* break up arg[i] into components */ - if (dbg) - printf("Break up arg %d from 1 to %d elements\n", i, argSz); - - slang_operation_construct(&origArg); - slang_operation_copy(&origArg, &callOper->children[i]); - - /* insert argSz-1 new children/args */ - for (j = 0; j < argSz - 1; j++) { - (void) slang_operation_insert(&callOper->num_children, - &callOper->children, i); - } - - /* replace arg[i+j] with subscript/index oper */ - for (j = 0; j < argSz; j++) { - callOper->children[i + j].type = SLANG_OPER_SUBSCRIPT; - callOper->children[i + j].locals = _slang_variable_scope_new(callOper->locals); - callOper->children[i + j].num_children = 2; - callOper->children[i + j].children = slang_operation_new(2); - slang_operation_copy(&callOper->children[i + j].children[0], - &origArg); - callOper->children[i + j].children[1].type - = SLANG_OPER_LITERAL_INT; - callOper->children[i + j].children[1].literal[0] = (GLfloat) j; - } - } - } - } - - if (callOper->num_children < (GLuint) numParams) { - /* still not enough args for all params */ - return GL_FALSE; - } - else if (callOper->num_children > (GLuint) numParams) { - /* now too many arguments */ - /* just truncate */ - callOper->num_children = (GLuint) numParams; - } - - if (dbg) { - printf("===== New call to %s with adapted arguments ===============\n", - (char*) fun->header.a_name); - slang_print_tree(callOper, 5); - } - - return GL_TRUE; -} diff --git a/src/mesa/slang/slang_simplify.h b/src/mesa/slang/slang_simplify.h deleted file mode 100644 index 37fb938d4f..0000000000 --- a/src/mesa/slang/slang_simplify.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SLANG_SIMPLIFY_H -#define SLANG_SIMPLIFY_H - - -#include "main/glheader.h" -#include "slang_compile.h" -#include "slang_compile_function.h" -#include "slang_compile_operation.h" -#include "slang_log.h" -#include "slang_utility.h" - -extern GLint -_slang_lookup_constant(const char *name); - - -extern void -_slang_simplify(slang_operation *oper, - const slang_name_space * space, - slang_atom_pool * atoms); - - -extern GLboolean -_slang_cast_func_params(slang_operation *callOper, const slang_function *fun, - const slang_name_space * space, - slang_atom_pool * atoms, slang_info_log *log); - -extern GLboolean -_slang_adapt_call(slang_operation *callOper, const slang_function *fun, - const slang_name_space * space, - slang_atom_pool * atoms, slang_info_log *log); - - -#endif /* SLANG_SIMPLIFY_H */ diff --git a/src/mesa/slang/slang_storage.c b/src/mesa/slang/slang_storage.c deleted file mode 100644 index 656e15670d..0000000000 --- a/src/mesa/slang/slang_storage.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_storage.c - * slang variable storage - * \author Michal Krol - */ - -#include "main/imports.h" -#include "slang_storage.h" -#include "slang_mem.h" - -/* slang_storage_array */ - -GLboolean -slang_storage_array_construct(slang_storage_array * arr) -{ - arr->type = SLANG_STORE_AGGREGATE; - arr->aggregate = NULL; - arr->length = 0; - return GL_TRUE; -} - -GLvoid -slang_storage_array_destruct(slang_storage_array * arr) -{ - if (arr->aggregate != NULL) { - slang_storage_aggregate_destruct(arr->aggregate); - _slang_free(arr->aggregate); - } -} - -/* slang_storage_aggregate */ - -GLboolean -slang_storage_aggregate_construct(slang_storage_aggregate * agg) -{ - agg->arrays = NULL; - agg->count = 0; - return GL_TRUE; -} - -GLvoid -slang_storage_aggregate_destruct(slang_storage_aggregate * agg) -{ - GLuint i; - - for (i = 0; i < agg->count; i++) - slang_storage_array_destruct(agg->arrays + i); - _slang_free(agg->arrays); -} - -static slang_storage_array * -slang_storage_aggregate_push_new(slang_storage_aggregate * agg) -{ - slang_storage_array *arr = NULL; - - agg->arrays = (slang_storage_array *) - _slang_realloc(agg->arrays, - agg->count * sizeof(slang_storage_array), - (agg->count + 1) * sizeof(slang_storage_array)); - if (agg->arrays != NULL) { - arr = agg->arrays + agg->count; - if (!slang_storage_array_construct(arr)) - return NULL; - agg->count++; - } - return arr; -} - -/* _slang_aggregate_variable() */ - -static GLboolean -aggregate_vector(slang_storage_aggregate * agg, slang_storage_type basic_type, - GLuint row_count) -{ - slang_storage_array *arr = slang_storage_aggregate_push_new(agg); - if (arr == NULL) - return GL_FALSE; - arr->type = basic_type; - arr->length = row_count; - return GL_TRUE; -} - -static GLboolean -aggregate_matrix(slang_storage_aggregate * agg, slang_storage_type basic_type, - GLuint columns, GLuint rows) -{ - slang_storage_array *arr = slang_storage_aggregate_push_new(agg); - if (arr == NULL) - return GL_FALSE; - arr->type = SLANG_STORE_AGGREGATE; - arr->length = columns; - arr->aggregate = (slang_storage_aggregate *) - _slang_alloc(sizeof(slang_storage_aggregate)); - if (arr->aggregate == NULL) - return GL_FALSE; - if (!slang_storage_aggregate_construct(arr->aggregate)) { - _slang_free(arr->aggregate); - arr->aggregate = NULL; - return GL_FALSE; - } - if (!aggregate_vector(arr->aggregate, basic_type, rows)) - return GL_FALSE; - return GL_TRUE; -} - - -static GLboolean -aggregate_variables(slang_storage_aggregate * agg, - slang_variable_scope * vars, slang_function_scope * funcs, - slang_struct_scope * structs, - slang_variable_scope * globals, - slang_atom_pool * atoms) -{ - GLuint i; - - for (i = 0; i < vars->num_variables; i++) - if (!_slang_aggregate_variable(agg, &vars->variables[i]->type.specifier, - vars->variables[i]->array_len, funcs, - structs, globals, atoms)) - return GL_FALSE; - return GL_TRUE; -} - - -GLboolean -_slang_aggregate_variable(slang_storage_aggregate * agg, - slang_type_specifier * spec, GLuint array_len, - slang_function_scope * funcs, - slang_struct_scope * structs, - slang_variable_scope * vars, - slang_atom_pool * atoms) -{ - switch (spec->type) { - case SLANG_SPEC_BOOL: - return aggregate_vector(agg, SLANG_STORE_BOOL, 1); - case SLANG_SPEC_BVEC2: - return aggregate_vector(agg, SLANG_STORE_BOOL, 2); - case SLANG_SPEC_BVEC3: - return aggregate_vector(agg, SLANG_STORE_BOOL, 3); - case SLANG_SPEC_BVEC4: - return aggregate_vector(agg, SLANG_STORE_BOOL, 4); - case SLANG_SPEC_INT: - return aggregate_vector(agg, SLANG_STORE_INT, 1); - case SLANG_SPEC_IVEC2: - return aggregate_vector(agg, SLANG_STORE_INT, 2); - case SLANG_SPEC_IVEC3: - return aggregate_vector(agg, SLANG_STORE_INT, 3); - case SLANG_SPEC_IVEC4: - return aggregate_vector(agg, SLANG_STORE_INT, 4); - case SLANG_SPEC_FLOAT: - return aggregate_vector(agg, SLANG_STORE_FLOAT, 1); - case SLANG_SPEC_VEC2: - return aggregate_vector(agg, SLANG_STORE_FLOAT, 2); - case SLANG_SPEC_VEC3: - return aggregate_vector(agg, SLANG_STORE_FLOAT, 3); - case SLANG_SPEC_VEC4: - return aggregate_vector(agg, SLANG_STORE_FLOAT, 4); - case SLANG_SPEC_MAT2: - return aggregate_matrix(agg, SLANG_STORE_FLOAT, 2, 2); - case SLANG_SPEC_MAT3: - return aggregate_matrix(agg, SLANG_STORE_FLOAT, 3, 3); - case SLANG_SPEC_MAT4: - return aggregate_matrix(agg, SLANG_STORE_FLOAT, 4, 4); - - case SLANG_SPEC_MAT23: - return aggregate_matrix(agg, SLANG_STORE_FLOAT, 2, 3); - case SLANG_SPEC_MAT32: - return aggregate_matrix(agg, SLANG_STORE_FLOAT, 3, 2); - case SLANG_SPEC_MAT24: - return aggregate_matrix(agg, SLANG_STORE_FLOAT, 2, 4); - case SLANG_SPEC_MAT42: - return aggregate_matrix(agg, SLANG_STORE_FLOAT, 4, 2); - case SLANG_SPEC_MAT34: - return aggregate_matrix(agg, SLANG_STORE_FLOAT, 3, 4); - case SLANG_SPEC_MAT43: - return aggregate_matrix(agg, SLANG_STORE_FLOAT, 4, 3); - - case SLANG_SPEC_SAMPLER_1D: - case SLANG_SPEC_SAMPLER_2D: - case SLANG_SPEC_SAMPLER_3D: - case SLANG_SPEC_SAMPLER_CUBE: - case SLANG_SPEC_SAMPLER_1D_SHADOW: - case SLANG_SPEC_SAMPLER_2D_SHADOW: - case SLANG_SPEC_SAMPLER_RECT: - case SLANG_SPEC_SAMPLER_RECT_SHADOW: - case SLANG_SPEC_SAMPLER_1D_ARRAY: - case SLANG_SPEC_SAMPLER_2D_ARRAY: - case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: - case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: - - return aggregate_vector(agg, SLANG_STORE_INT, 1); - case SLANG_SPEC_STRUCT: - return aggregate_variables(agg, spec->_struct->fields, funcs, structs, - vars, atoms); - case SLANG_SPEC_ARRAY: - { - slang_storage_array *arr; - - arr = slang_storage_aggregate_push_new(agg); - if (arr == NULL) - return GL_FALSE; - arr->type = SLANG_STORE_AGGREGATE; - arr->aggregate = (slang_storage_aggregate *) - _slang_alloc(sizeof(slang_storage_aggregate)); - if (arr->aggregate == NULL) - return GL_FALSE; - if (!slang_storage_aggregate_construct(arr->aggregate)) { - _slang_free(arr->aggregate); - arr->aggregate = NULL; - return GL_FALSE; - } - if (!_slang_aggregate_variable(arr->aggregate, spec->_array, 0, - funcs, structs, vars, atoms)) - return GL_FALSE; - arr->length = array_len; - /* TODO: check if 0 < arr->length <= 65535 */ - } - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -GLuint -_slang_sizeof_type(slang_storage_type type) -{ - if (type == SLANG_STORE_AGGREGATE) - return 0; - if (type == SLANG_STORE_VEC4) - return 4 * sizeof(GLfloat); - return sizeof(GLfloat); -} - - -GLuint -_slang_sizeof_aggregate(const slang_storage_aggregate * agg) -{ - GLuint i, size = 0; - - for (i = 0; i < agg->count; i++) { - slang_storage_array *arr = &agg->arrays[i]; - GLuint element_size; - - if (arr->type == SLANG_STORE_AGGREGATE) - element_size = _slang_sizeof_aggregate(arr->aggregate); - else - element_size = _slang_sizeof_type(arr->type); - size += element_size * arr->length; - } - return size; -} - - -#if 0 -GLboolean -_slang_flatten_aggregate(slang_storage_aggregate * flat, - const slang_storage_aggregate * agg) -{ - GLuint i; - - for (i = 0; i < agg->count; i++) { - GLuint j; - - for (j = 0; j < agg->arrays[i].length; j++) { - if (agg->arrays[i].type == SLANG_STORE_AGGREGATE) { - if (!_slang_flatten_aggregate(flat, agg->arrays[i].aggregate)) - return GL_FALSE; - } - else { - GLuint k, count; - slang_storage_type type; - - if (agg->arrays[i].type == SLANG_STORE_VEC4) { - count = 4; - type = SLANG_STORE_FLOAT; - } - else { - count = 1; - type = agg->arrays[i].type; - } - - for (k = 0; k < count; k++) { - slang_storage_array *arr; - - arr = slang_storage_aggregate_push_new(flat); - if (arr == NULL) - return GL_FALSE; - arr->type = type; - arr->length = 1; - } - } - } - } - return GL_TRUE; -} -#endif diff --git a/src/mesa/slang/slang_storage.h b/src/mesa/slang/slang_storage.h deleted file mode 100644 index 1876a36dd6..0000000000 --- a/src/mesa/slang/slang_storage.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SLANG_STORAGE_H -#define SLANG_STORAGE_H - -#include "slang_compile.h" - - -/* - * Program variable data storage is kept completely transparent to the - * front-end compiler. It is up to the back-end how the data is - * actually allocated. The slang_storage_type enum provides the basic - * information about how the memory is interpreted. This abstract - * piece of memory is called a data slot. A data slot of a particular - * type has a fixed size. - * - * For now, only the three basic types are supported, that is bool, - * int and float. Other built-in types like vector or matrix can - * easily be decomposed into a series of basic types. - * - * If the vec4 module is enabled, 4-component vectors of floats are - * used when possible. 4x4 matrices are constructed of 4 vec4 slots. - */ -typedef enum slang_storage_type_ -{ - /* core */ - SLANG_STORE_AGGREGATE, - SLANG_STORE_BOOL, - SLANG_STORE_INT, - SLANG_STORE_FLOAT, - /* vec4 */ - SLANG_STORE_VEC4 -} slang_storage_type; - - -/** - * The slang_storage_array structure groups data slots of the same - * type into an array. This array has a fixed length. Arrays are - * required to have a size equal to the sum of sizes of its - * elements. They are also required to support indirect - * addressing. That is, if B references first data slot in the array, - * S is the size of the data slot and I is the integral index that is - * not known at compile time, B+I*S references I-th data slot. - * - * This structure is also used to break down built-in data types that - * are not supported directly. Vectors, like vec3, are constructed - * from arrays of their basic types. Matrices are formed of an array - * of column vectors, which are in turn processed as other vectors. - */ -typedef struct slang_storage_array_ -{ - slang_storage_type type; - struct slang_storage_aggregate_ *aggregate; - GLuint length; -} slang_storage_array; - -GLboolean slang_storage_array_construct (slang_storage_array *); -GLvoid slang_storage_array_destruct (slang_storage_array *); - - -/** - * The slang_storage_aggregate structure relaxes the indirect - * addressing requirement for slang_storage_array - * structure. Aggregates are always accessed statically - its member - * addresses are well-known at compile time. For example, user-defined - * types are implemented as aggregates. Aggregates can collect data of - * a different type. - */ -typedef struct slang_storage_aggregate_ -{ - slang_storage_array *arrays; - GLuint count; -} slang_storage_aggregate; - -GLboolean slang_storage_aggregate_construct (slang_storage_aggregate *); -GLvoid slang_storage_aggregate_destruct (slang_storage_aggregate *); - - -extern GLboolean -_slang_aggregate_variable(slang_storage_aggregate *agg, - slang_type_specifier *spec, - GLuint array_len, - slang_function_scope *funcs, - slang_struct_scope *structs, - slang_variable_scope *vars, - slang_atom_pool *atoms); - -/* - * Returns the size (in machine units) of the given storage type. - * It is an error to pass-in SLANG_STORE_AGGREGATE. - * Returns 0 on error. - */ -extern GLuint -_slang_sizeof_type (slang_storage_type); - - -/** - * Returns total size (in machine units) of the given aggregate. - * Returns 0 on error. - */ -extern GLuint -_slang_sizeof_aggregate (const slang_storage_aggregate *); - - -#if 0 -/** - * Converts structured aggregate to a flat one, with arrays of generic - * type being one-element long. Returns GL_TRUE on success. Returns - * GL_FALSE otherwise. - */ -extern GLboolean -_slang_flatten_aggregate (slang_storage_aggregate *, - const slang_storage_aggregate *); - -#endif - -#endif /* SLANG_STORAGE_H */ diff --git a/src/mesa/slang/slang_typeinfo.c b/src/mesa/slang/slang_typeinfo.c deleted file mode 100644 index d039a12e98..0000000000 --- a/src/mesa/slang/slang_typeinfo.c +++ /dev/null @@ -1,1177 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_typeinfo.c - * slang type info - * \author Michal Krol - */ - -#include "main/imports.h" -#include "program/prog_instruction.h" -#include "slang_typeinfo.h" -#include "slang_compile.h" -#include "slang_log.h" -#include "slang_mem.h" - - -/** - * Checks if a field selector is a general swizzle (an r-value swizzle - * with replicated components or an l-value swizzle mask) for a - * vector. Returns GL_TRUE if this is the case, <swz> is filled with - * swizzle information. Returns GL_FALSE otherwise. - */ -GLboolean -_slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz) -{ - GLuint i; - GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE; - - /* init to undefined. - * We rely on undefined/nil values to distinguish between - * regular swizzles and writemasks. - * For example, the swizzle ".xNNN" is the writemask ".x". - * That's different than the swizzle ".xxxx". - */ - for (i = 0; i < 4; i++) - swz->swizzle[i] = SWIZZLE_NIL; - - /* the swizzle can be at most 4-component long */ - swz->num_components = slang_string_length(field); - if (swz->num_components > 4) - return GL_FALSE; - - for (i = 0; i < swz->num_components; i++) { - /* mark which swizzle group is used */ - switch (field[i]) { - case 'x': - case 'y': - case 'z': - case 'w': - xyzw = GL_TRUE; - break; - case 'r': - case 'g': - case 'b': - case 'a': - rgba = GL_TRUE; - break; - case 's': - case 't': - case 'p': - case 'q': - stpq = GL_TRUE; - break; - default: - return GL_FALSE; - } - - /* collect swizzle component */ - switch (field[i]) { - case 'x': - case 'r': - case 's': - swz->swizzle[i] = 0; - break; - case 'y': - case 'g': - case 't': - swz->swizzle[i] = 1; - break; - case 'z': - case 'b': - case 'p': - swz->swizzle[i] = 2; - break; - case 'w': - case 'a': - case 'q': - swz->swizzle[i] = 3; - break; - } - - /* check if the component is valid for given vector's row count */ - if (rows <= swz->swizzle[i]) - return GL_FALSE; - } - - /* only one swizzle group can be used */ - if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq)) - return GL_FALSE; - - return GL_TRUE; -} - - - -/** - * Checks if a general swizzle is an l-value swizzle - these swizzles - * do not have duplicated fields. Returns GL_TRUE if this is a - * swizzle mask. Returns GL_FALSE otherwise - */ -static GLboolean -_slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows) -{ - GLuint i, c = 0; - - /* the swizzle may not be longer than the vector dim */ - if (swz->num_components > rows) - return GL_FALSE; - - /* the swizzle components cannot be duplicated */ - for (i = 0; i < swz->num_components; i++) { - if ((c & (1 << swz->swizzle[i])) != 0) - return GL_FALSE; - c |= 1 << swz->swizzle[i]; - } - - return GL_TRUE; -} - - -/** - * Combines (multiplies) two swizzles to form single swizzle. - * Example: "vec.wzyx.yx" --> "vec.zw". - */ -static void -_slang_multiply_swizzles(slang_swizzle * dst, const slang_swizzle * left, - const slang_swizzle * right) -{ - GLuint i; - - dst->num_components = right->num_components; - for (i = 0; i < right->num_components; i++) - dst->swizzle[i] = left->swizzle[right->swizzle[i]]; -} - - -typedef struct -{ - const char *name; - slang_type_specifier_type type; -} type_specifier_type_name; - -static const type_specifier_type_name type_specifier_type_names[] = { - {"void", SLANG_SPEC_VOID}, - {"bool", SLANG_SPEC_BOOL}, - {"bvec2", SLANG_SPEC_BVEC2}, - {"bvec3", SLANG_SPEC_BVEC3}, - {"bvec4", SLANG_SPEC_BVEC4}, - {"int", SLANG_SPEC_INT}, - {"ivec2", SLANG_SPEC_IVEC2}, - {"ivec3", SLANG_SPEC_IVEC3}, - {"ivec4", SLANG_SPEC_IVEC4}, - {"float", SLANG_SPEC_FLOAT}, - {"vec2", SLANG_SPEC_VEC2}, - {"vec3", SLANG_SPEC_VEC3}, - {"vec4", SLANG_SPEC_VEC4}, - {"mat2", SLANG_SPEC_MAT2}, - {"mat3", SLANG_SPEC_MAT3}, - {"mat4", SLANG_SPEC_MAT4}, - {"mat2x3", SLANG_SPEC_MAT23}, - {"mat3x2", SLANG_SPEC_MAT32}, - {"mat2x4", SLANG_SPEC_MAT24}, - {"mat4x2", SLANG_SPEC_MAT42}, - {"mat3x4", SLANG_SPEC_MAT34}, - {"mat4x3", SLANG_SPEC_MAT43}, - {"sampler1D", SLANG_SPEC_SAMPLER_1D}, - {"sampler2D", SLANG_SPEC_SAMPLER_2D}, - {"sampler3D", SLANG_SPEC_SAMPLER_3D}, - {"samplerCube", SLANG_SPEC_SAMPLER_CUBE}, - {"sampler1DShadow", SLANG_SPEC_SAMPLER_1D_SHADOW}, - {"sampler2DShadow", SLANG_SPEC_SAMPLER_2D_SHADOW}, - {"sampler2DRect", SLANG_SPEC_SAMPLER_RECT}, - {"sampler2DRectShadow", SLANG_SPEC_SAMPLER_RECT_SHADOW}, - {"sampler1DArray", SLANG_SPEC_SAMPLER_1D_ARRAY}, - {"sampler2DArray", SLANG_SPEC_SAMPLER_2D_ARRAY}, - {"sampler1DArrayShadow", SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW}, - {"sampler2DArrayShadow", SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW}, - {NULL, SLANG_SPEC_VOID} -}; - -slang_type_specifier_type -slang_type_specifier_type_from_string(const char *name) -{ - const type_specifier_type_name *p = type_specifier_type_names; - while (p->name != NULL) { - if (slang_string_compare(p->name, name) == 0) - break; - p++; - } - return p->type; -} - -const char * -slang_type_specifier_type_to_string(slang_type_specifier_type type) -{ - const type_specifier_type_name *p = type_specifier_type_names; - while (p->name != NULL) { - if (p->type == type) - break; - p++; - } - return p->name; -} - -/* slang_fully_specified_type */ - -int -slang_fully_specified_type_construct(slang_fully_specified_type * type) -{ - type->qualifier = SLANG_QUAL_NONE; - slang_type_specifier_ctr(&type->specifier); - return 1; -} - -void -slang_fully_specified_type_destruct(slang_fully_specified_type * type) -{ - slang_type_specifier_dtr(&type->specifier); -} - -int -slang_fully_specified_type_copy(slang_fully_specified_type * x, - const slang_fully_specified_type * y) -{ - slang_fully_specified_type z; - - if (!slang_fully_specified_type_construct(&z)) - return 0; - z.qualifier = y->qualifier; - z.precision = y->precision; - z.variant = y->variant; - z.centroid = y->centroid; - z.layout = y->layout; - z.array_len = y->array_len; - if (!slang_type_specifier_copy(&z.specifier, &y->specifier)) { - slang_fully_specified_type_destruct(&z); - return 0; - } - slang_fully_specified_type_destruct(x); - *x = z; - return 1; -} - - -/** - * Test if two fully specified types are compatible. This is a bit - * looser than testing for equality. We don't check the precision, - * variant, centroid, etc. information. - * XXX this may need some tweaking. - */ -GLboolean -slang_fully_specified_types_compatible(const slang_fully_specified_type * x, - const slang_fully_specified_type * y) -{ - if (!slang_type_specifier_equal(&x->specifier, &y->specifier)) - return GL_FALSE; - - if (x->qualifier == SLANG_QUAL_FIXEDINPUT && - y->qualifier == SLANG_QUAL_VARYING) - ; /* ok */ - else if (x->qualifier != y->qualifier) - return GL_FALSE; - - /* Note: don't compare precision, variant, centroid */ - - /* XXX array length? */ - - return GL_TRUE; -} - - -GLvoid -slang_type_specifier_ctr(slang_type_specifier * self) -{ - self->type = SLANG_SPEC_VOID; - self->_struct = NULL; - self->_array = NULL; -} - -GLvoid -slang_type_specifier_dtr(slang_type_specifier * self) -{ - if (self->_struct != NULL) { - slang_struct_destruct(self->_struct); - _slang_free(self->_struct); - } - if (self->_array != NULL) { - slang_type_specifier_dtr(self->_array); - _slang_free(self->_array); - } -} - -slang_type_specifier * -slang_type_specifier_new(slang_type_specifier_type type, - struct slang_struct_ *_struct, - struct slang_type_specifier_ *_array) -{ - slang_type_specifier *spec = - (slang_type_specifier *) _slang_alloc(sizeof(slang_type_specifier)); - if (spec) { - spec->type = type; - spec->_struct = _struct; - spec->_array = _array; - } - return spec; -} - -GLboolean -slang_type_specifier_copy(slang_type_specifier * x, - const slang_type_specifier * y) -{ - slang_type_specifier z; - - slang_type_specifier_ctr(&z); - z.type = y->type; - if (z.type == SLANG_SPEC_STRUCT) { - z._struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); - if (z._struct == NULL) { - slang_type_specifier_dtr(&z); - return GL_FALSE; - } - if (!slang_struct_construct(z._struct)) { - _slang_free(z._struct); - slang_type_specifier_dtr(&z); - return GL_FALSE; - } - if (!slang_struct_copy(z._struct, y->_struct)) { - slang_type_specifier_dtr(&z); - return GL_FALSE; - } - } - else if (z.type == SLANG_SPEC_ARRAY) { - z._array = (slang_type_specifier *) - _slang_alloc(sizeof(slang_type_specifier)); - if (z._array == NULL) { - slang_type_specifier_dtr(&z); - return GL_FALSE; - } - slang_type_specifier_ctr(z._array); - if (!slang_type_specifier_copy(z._array, y->_array)) { - slang_type_specifier_dtr(&z); - return GL_FALSE; - } - } - slang_type_specifier_dtr(x); - *x = z; - return GL_TRUE; -} - - -/** - * Test if two types are equal. - */ -GLboolean -slang_type_specifier_equal(const slang_type_specifier * x, - const slang_type_specifier * y) -{ - if (x->type != y->type) - return GL_FALSE; - if (x->type == SLANG_SPEC_STRUCT) - return slang_struct_equal(x->_struct, y->_struct); - if (x->type == SLANG_SPEC_ARRAY) - return slang_type_specifier_equal(x->_array, y->_array); - return GL_TRUE; -} - - -/** - * As above, but allow float/int casting. - */ -GLboolean -slang_type_specifier_compatible(const slang_type_specifier * x, - const slang_type_specifier * y) -{ - /* special case: float == int */ - if (x->type == SLANG_SPEC_INT && y->type == SLANG_SPEC_FLOAT) { - return GL_TRUE; - } - /* XXX may need to add bool/int compatibility, etc */ - - if (x->type != y->type) - return GL_FALSE; - if (x->type == SLANG_SPEC_STRUCT) - return slang_struct_equal(x->_struct, y->_struct); - if (x->type == SLANG_SPEC_ARRAY) - return slang_type_specifier_compatible(x->_array, y->_array); - return GL_TRUE; -} - - -GLboolean -slang_typeinfo_construct(slang_typeinfo * ti) -{ - memset(ti, 0, sizeof(*ti)); - slang_type_specifier_ctr(&ti->spec); - ti->array_len = 0; - return GL_TRUE; -} - -GLvoid -slang_typeinfo_destruct(slang_typeinfo * ti) -{ - slang_type_specifier_dtr(&ti->spec); -} - - - -/** - * Determine the return type of a function. - * \param a_name the function name - * \param param function parameters (overloading) - * \param num_params number of parameters to function - * \param space namespace to search - * \param spec returns the type - * \param funFound returns pointer to the function, or NULL if not found. - * \return GL_TRUE for success, GL_FALSE if failure (bad function name) - */ -static GLboolean -_slang_typeof_function(slang_atom a_name, - slang_operation * params, GLuint num_params, - const slang_name_space * space, - slang_type_specifier * spec, - slang_function **funFound, - slang_atom_pool *atoms, slang_info_log *log) -{ - GLboolean error; - - *funFound = _slang_function_locate(space->funcs, a_name, params, - num_params, space, atoms, log, &error); - if (error) - return GL_FALSE; - - if (!*funFound) - return GL_TRUE; /* yes, not false */ - - return slang_type_specifier_copy(spec, &(*funFound)->header.type.specifier); -} - - -/** - * Determine the type of a math function. - * \param name name of the operator, one of +,-,*,/ or unary - - * \param params array of function parameters - * \param num_params number of parameters - * \param space namespace to use - * \param spec returns the function's type - * \param atoms atom pool - * \return GL_TRUE for success, GL_FALSE if failure - */ -static GLboolean -typeof_math_call(const char *name, slang_operation *call, - const slang_name_space * space, - slang_type_specifier * spec, - slang_atom_pool * atoms, - slang_info_log *log) -{ - if (call->fun) { - /* we've previously resolved this function call */ - slang_type_specifier_copy(spec, &call->fun->header.type.specifier); - return GL_TRUE; - } - else { - slang_atom atom; - slang_function *fun; - - /* number of params: */ - assert(call->num_children == 1 || call->num_children == 2); - - atom = slang_atom_pool_atom(atoms, name); - if (!_slang_typeof_function(atom, call->children, call->num_children, - space, spec, &fun, atoms, log)) - return GL_FALSE; - - if (fun) { - /* Save pointer to save time in future */ - call->fun = fun; - return GL_TRUE; - } - return GL_FALSE; - } -} - - -/** - * Determine the return type of an operation. - * \param op the operation node - * \param space the namespace to use - * \param ti the returned type - * \param atoms atom pool - * \return GL_TRUE for success, GL_FALSE if failure - */ -GLboolean -_slang_typeof_operation(slang_operation * op, - const slang_name_space * space, - slang_typeinfo * ti, - slang_atom_pool * atoms, - slang_info_log *log) -{ - ti->can_be_referenced = GL_FALSE; - ti->is_swizzled = GL_FALSE; - - switch (op->type) { - case SLANG_OPER_BLOCK_NO_NEW_SCOPE: - case SLANG_OPER_BLOCK_NEW_SCOPE: - case SLANG_OPER_ASM: - case SLANG_OPER_BREAK: - case SLANG_OPER_CONTINUE: - case SLANG_OPER_DISCARD: - case SLANG_OPER_RETURN: - case SLANG_OPER_IF: - case SLANG_OPER_WHILE: - case SLANG_OPER_DO: - case SLANG_OPER_FOR: - case SLANG_OPER_VOID: - ti->spec.type = SLANG_SPEC_VOID; - break; - case SLANG_OPER_EXPRESSION: - case SLANG_OPER_ASSIGN: - case SLANG_OPER_ADDASSIGN: - case SLANG_OPER_SUBASSIGN: - case SLANG_OPER_MULASSIGN: - case SLANG_OPER_DIVASSIGN: - case SLANG_OPER_PREINCREMENT: - case SLANG_OPER_PREDECREMENT: - if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) - return GL_FALSE; - break; - case SLANG_OPER_LITERAL_BOOL: - if (op->literal_size == 1) - ti->spec.type = SLANG_SPEC_BOOL; - else if (op->literal_size == 2) - ti->spec.type = SLANG_SPEC_BVEC2; - else if (op->literal_size == 3) - ti->spec.type = SLANG_SPEC_BVEC3; - else if (op->literal_size == 4) - ti->spec.type = SLANG_SPEC_BVEC4; - else { - _mesa_problem(NULL, - "Unexpected bool literal_size %d in _slang_typeof_operation()", - op->literal_size); - ti->spec.type = SLANG_SPEC_BOOL; - } - break; - case SLANG_OPER_LOGICALOR: - case SLANG_OPER_LOGICALXOR: - case SLANG_OPER_LOGICALAND: - case SLANG_OPER_EQUAL: - case SLANG_OPER_NOTEQUAL: - case SLANG_OPER_LESS: - case SLANG_OPER_GREATER: - case SLANG_OPER_LESSEQUAL: - case SLANG_OPER_GREATEREQUAL: - case SLANG_OPER_NOT: - ti->spec.type = SLANG_SPEC_BOOL; - break; - case SLANG_OPER_LITERAL_INT: - if (op->literal_size == 1) - ti->spec.type = SLANG_SPEC_INT; - else if (op->literal_size == 2) - ti->spec.type = SLANG_SPEC_IVEC2; - else if (op->literal_size == 3) - ti->spec.type = SLANG_SPEC_IVEC3; - else if (op->literal_size == 4) - ti->spec.type = SLANG_SPEC_IVEC4; - else { - _mesa_problem(NULL, - "Unexpected int literal_size %d in _slang_typeof_operation()", - op->literal_size); - ti->spec.type = SLANG_SPEC_INT; - } - break; - case SLANG_OPER_LITERAL_FLOAT: - if (op->literal_size == 1) - ti->spec.type = SLANG_SPEC_FLOAT; - else if (op->literal_size == 2) - ti->spec.type = SLANG_SPEC_VEC2; - else if (op->literal_size == 3) - ti->spec.type = SLANG_SPEC_VEC3; - else if (op->literal_size == 4) - ti->spec.type = SLANG_SPEC_VEC4; - else { - _mesa_problem(NULL, - "Unexpected float literal_size %d in _slang_typeof_operation()", - op->literal_size); - ti->spec.type = SLANG_SPEC_FLOAT; - } - break; - case SLANG_OPER_IDENTIFIER: - case SLANG_OPER_VARIABLE_DECL: - { - slang_variable *var; - var = _slang_variable_locate(op->locals, op->a_id, GL_TRUE); - if (!var) { - slang_info_log_error(log, "undefined variable '%s'", - (char *) op->a_id); - return GL_FALSE; - } - if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier)) { - slang_info_log_memory(log); - return GL_FALSE; - } - ti->can_be_referenced = GL_TRUE; - if (var->type.specifier.type == SLANG_SPEC_ARRAY && - var->type.array_len >= 1) { - /* the datatype is an array, ex: float[3] x; */ - ti->array_len = var->type.array_len; - } - else { - /* the variable is an array, ex: float x[3]; */ - ti->array_len = var->array_len; - } - } - break; - case SLANG_OPER_SEQUENCE: - /* TODO: check [0] and [1] if they match */ - if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) { - return GL_FALSE; - } - ti->can_be_referenced = GL_FALSE; - ti->is_swizzled = GL_FALSE; - break; - /*case SLANG_OPER_MODASSIGN: */ - /*case SLANG_OPER_LSHASSIGN: */ - /*case SLANG_OPER_RSHASSIGN: */ - /*case SLANG_OPER_ORASSIGN: */ - /*case SLANG_OPER_XORASSIGN: */ - /*case SLANG_OPER_ANDASSIGN: */ - case SLANG_OPER_SELECT: - /* TODO: check [1] and [2] if they match */ - if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) { - return GL_FALSE; - } - ti->can_be_referenced = GL_FALSE; - ti->is_swizzled = GL_FALSE; - break; - /*case SLANG_OPER_BITOR: */ - /*case SLANG_OPER_BITXOR: */ - /*case SLANG_OPER_BITAND: */ - /*case SLANG_OPER_LSHIFT: */ - /*case SLANG_OPER_RSHIFT: */ - case SLANG_OPER_ADD: - assert(op->num_children == 2); - if (!typeof_math_call("+", op, space, &ti->spec, atoms, log)) - return GL_FALSE; - break; - case SLANG_OPER_SUBTRACT: - assert(op->num_children == 2); - if (!typeof_math_call("-", op, space, &ti->spec, atoms, log)) - return GL_FALSE; - break; - case SLANG_OPER_MULTIPLY: - assert(op->num_children == 2); - if (!typeof_math_call("*", op, space, &ti->spec, atoms, log)) - return GL_FALSE; - break; - case SLANG_OPER_DIVIDE: - assert(op->num_children == 2); - if (!typeof_math_call("/", op, space, &ti->spec, atoms, log)) - return GL_FALSE; - break; - /*case SLANG_OPER_MODULUS: */ - case SLANG_OPER_PLUS: - if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) - return GL_FALSE; - ti->can_be_referenced = GL_FALSE; - ti->is_swizzled = GL_FALSE; - break; - case SLANG_OPER_MINUS: - assert(op->num_children == 1); - if (!typeof_math_call("-", op, space, &ti->spec, atoms, log)) - return GL_FALSE; - break; - /*case SLANG_OPER_COMPLEMENT: */ - case SLANG_OPER_SUBSCRIPT: - { - slang_typeinfo _ti; - - if (!slang_typeinfo_construct(&_ti)) - return GL_FALSE; - if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) { - slang_typeinfo_destruct(&_ti); - return GL_FALSE; - } - ti->can_be_referenced = _ti.can_be_referenced; - if (_ti.spec.type == SLANG_SPEC_ARRAY) { - if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) { - slang_typeinfo_destruct(&_ti); - return GL_FALSE; - } - } - else { - if (!_slang_type_is_vector(_ti.spec.type) - && !_slang_type_is_matrix(_ti.spec.type)) { - slang_typeinfo_destruct(&_ti); - slang_info_log_error(log, "cannot index a non-array type"); - return GL_FALSE; - } - ti->spec.type = _slang_type_base(_ti.spec.type); - } - slang_typeinfo_destruct(&_ti); - } - break; - case SLANG_OPER_CALL: - if (op->array_constructor) { - /* build array typeinfo */ - ti->spec.type = SLANG_SPEC_ARRAY; - ti->spec._array = (slang_type_specifier *) - _slang_alloc(sizeof(slang_type_specifier)); - slang_type_specifier_ctr(ti->spec._array); - - ti->spec._array->type = - slang_type_specifier_type_from_string((char *) op->a_id); - ti->array_len = op->num_children; - } - else if (op->fun) { - /* we've resolved this call before */ - slang_type_specifier_copy(&ti->spec, &op->fun->header.type.specifier); - } - else { - slang_function *fun; - if (!_slang_typeof_function(op->a_id, op->children, op->num_children, - space, &ti->spec, &fun, atoms, log)) - return GL_FALSE; - if (fun) { - /* save result for future use */ - op->fun = fun; - } - else { - slang_struct *s = - slang_struct_scope_find(space->structs, op->a_id, GL_TRUE); - if (s) { - /* struct initializer */ - ti->spec.type = SLANG_SPEC_STRUCT; - ti->spec._struct = - (slang_struct *) _slang_alloc(sizeof(slang_struct)); - if (ti->spec._struct == NULL) - return GL_FALSE; - if (!slang_struct_construct(ti->spec._struct)) { - _slang_free(ti->spec._struct); - ti->spec._struct = NULL; - return GL_FALSE; - } - if (!slang_struct_copy(ti->spec._struct, s)) - return GL_FALSE; - } - else { - /* float, int, vec4, mat3, etc. constructor? */ - const char *name; - slang_type_specifier_type type; - - name = slang_atom_pool_id(atoms, op->a_id); - type = slang_type_specifier_type_from_string(name); - if (type == SLANG_SPEC_VOID) { - slang_info_log_error(log, "undefined function '%s'", name); - return GL_FALSE; - } - ti->spec.type = type; - } - } - } - break; - case SLANG_OPER_METHOD: - /* at this time, GLSL 1.20 only has one method: array.length() - * which returns an integer. - */ - ti->spec.type = SLANG_SPEC_INT; - break; - case SLANG_OPER_FIELD: - { - slang_typeinfo _ti; - - if (!slang_typeinfo_construct(&_ti)) - return GL_FALSE; - if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) { - slang_typeinfo_destruct(&_ti); - return GL_FALSE; - } - if (_ti.spec.type == SLANG_SPEC_STRUCT) { - slang_variable *field; - - field = _slang_variable_locate(_ti.spec._struct->fields, op->a_id, - GL_FALSE); - if (field == NULL) { - slang_typeinfo_destruct(&_ti); - return GL_FALSE; - } - if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) { - slang_typeinfo_destruct(&_ti); - return GL_FALSE; - } - ti->can_be_referenced = _ti.can_be_referenced; - ti->array_len = field->array_len; - } - else { - GLuint rows; - const char *swizzle; - slang_type_specifier_type base; - - /* determine the swizzle of the field expression */ - if (!_slang_type_is_vector(_ti.spec.type)) { - slang_typeinfo_destruct(&_ti); - slang_info_log_error(log, "Can't swizzle scalar expression"); - return GL_FALSE; - } - rows = _slang_type_dim(_ti.spec.type); - swizzle = slang_atom_pool_id(atoms, op->a_id); - if (!_slang_is_swizzle(swizzle, rows, &ti->swz)) { - slang_typeinfo_destruct(&_ti); - slang_info_log_error(log, "bad swizzle '%s'", swizzle); - return GL_FALSE; - } - ti->is_swizzled = GL_TRUE; - ti->can_be_referenced = _ti.can_be_referenced - && _slang_is_swizzle_mask(&ti->swz, rows); - if (_ti.is_swizzled) { - slang_swizzle swz; - - /* swizzle the swizzle */ - _slang_multiply_swizzles(&swz, &_ti.swz, &ti->swz); - ti->swz = swz; - } - base = _slang_type_base(_ti.spec.type); - switch (ti->swz.num_components) { - case 1: - ti->spec.type = base; - break; - case 2: - switch (base) { - case SLANG_SPEC_FLOAT: - ti->spec.type = SLANG_SPEC_VEC2; - break; - case SLANG_SPEC_INT: - ti->spec.type = SLANG_SPEC_IVEC2; - break; - case SLANG_SPEC_BOOL: - ti->spec.type = SLANG_SPEC_BVEC2; - break; - default: - break; - } - break; - case 3: - switch (base) { - case SLANG_SPEC_FLOAT: - ti->spec.type = SLANG_SPEC_VEC3; - break; - case SLANG_SPEC_INT: - ti->spec.type = SLANG_SPEC_IVEC3; - break; - case SLANG_SPEC_BOOL: - ti->spec.type = SLANG_SPEC_BVEC3; - break; - default: - break; - } - break; - case 4: - switch (base) { - case SLANG_SPEC_FLOAT: - ti->spec.type = SLANG_SPEC_VEC4; - break; - case SLANG_SPEC_INT: - ti->spec.type = SLANG_SPEC_IVEC4; - break; - case SLANG_SPEC_BOOL: - ti->spec.type = SLANG_SPEC_BVEC4; - break; - default: - break; - } - break; - default: - break; - } - } - slang_typeinfo_destruct(&_ti); - } - break; - case SLANG_OPER_POSTINCREMENT: - case SLANG_OPER_POSTDECREMENT: - if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) - return GL_FALSE; - ti->can_be_referenced = GL_FALSE; - ti->is_swizzled = GL_FALSE; - break; - default: - return GL_FALSE; - } - - return GL_TRUE; -} - - -/** - * Determine if a type is a matrix. - * \return GL_TRUE if is a matrix, GL_FALSE otherwise. - */ -GLboolean -_slang_type_is_matrix(slang_type_specifier_type ty) -{ - switch (ty) { - case SLANG_SPEC_MAT2: - case SLANG_SPEC_MAT3: - case SLANG_SPEC_MAT4: - case SLANG_SPEC_MAT23: - case SLANG_SPEC_MAT32: - case SLANG_SPEC_MAT24: - case SLANG_SPEC_MAT42: - case SLANG_SPEC_MAT34: - case SLANG_SPEC_MAT43: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Determine if a type is a vector. - * \return GL_TRUE if is a vector, GL_FALSE otherwise. - */ -GLboolean -_slang_type_is_vector(slang_type_specifier_type ty) -{ - switch (ty) { - case SLANG_SPEC_VEC2: - case SLANG_SPEC_VEC3: - case SLANG_SPEC_VEC4: - case SLANG_SPEC_IVEC2: - case SLANG_SPEC_IVEC3: - case SLANG_SPEC_IVEC4: - case SLANG_SPEC_BVEC2: - case SLANG_SPEC_BVEC3: - case SLANG_SPEC_BVEC4: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Determine if a type is a float, float vector or float matrix. - * \return GL_TRUE if so, GL_FALSE otherwise - */ -GLboolean -_slang_type_is_float_vec_mat(slang_type_specifier_type ty) -{ - switch (ty) { - case SLANG_SPEC_FLOAT: - case SLANG_SPEC_VEC2: - case SLANG_SPEC_VEC3: - case SLANG_SPEC_VEC4: - case SLANG_SPEC_MAT2: - case SLANG_SPEC_MAT3: - case SLANG_SPEC_MAT4: - case SLANG_SPEC_MAT23: - case SLANG_SPEC_MAT32: - case SLANG_SPEC_MAT24: - case SLANG_SPEC_MAT42: - case SLANG_SPEC_MAT34: - case SLANG_SPEC_MAT43: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Given a vector type, return the type of the vector's elements. - * For a matrix, return the type of the columns. - */ -slang_type_specifier_type -_slang_type_base(slang_type_specifier_type ty) -{ - switch (ty) { - case SLANG_SPEC_FLOAT: - case SLANG_SPEC_VEC2: - case SLANG_SPEC_VEC3: - case SLANG_SPEC_VEC4: - return SLANG_SPEC_FLOAT; - case SLANG_SPEC_INT: - case SLANG_SPEC_IVEC2: - case SLANG_SPEC_IVEC3: - case SLANG_SPEC_IVEC4: - return SLANG_SPEC_INT; - case SLANG_SPEC_BOOL: - case SLANG_SPEC_BVEC2: - case SLANG_SPEC_BVEC3: - case SLANG_SPEC_BVEC4: - return SLANG_SPEC_BOOL; - case SLANG_SPEC_MAT2: - return SLANG_SPEC_VEC2; - case SLANG_SPEC_MAT3: - return SLANG_SPEC_VEC3; - case SLANG_SPEC_MAT4: - return SLANG_SPEC_VEC4; - case SLANG_SPEC_MAT23: - return SLANG_SPEC_VEC3; - case SLANG_SPEC_MAT32: - return SLANG_SPEC_VEC2; - case SLANG_SPEC_MAT24: - return SLANG_SPEC_VEC4; - case SLANG_SPEC_MAT42: - return SLANG_SPEC_VEC2; - case SLANG_SPEC_MAT34: - return SLANG_SPEC_VEC4; - case SLANG_SPEC_MAT43: - return SLANG_SPEC_VEC3; - default: - return SLANG_SPEC_VOID; - } -} - - -/** - * Return the dimensionality of a vector, or for a matrix, return number - * of columns. - */ -GLuint -_slang_type_dim(slang_type_specifier_type ty) -{ - switch (ty) { - case SLANG_SPEC_FLOAT: - case SLANG_SPEC_INT: - case SLANG_SPEC_BOOL: - return 1; - case SLANG_SPEC_VEC2: - case SLANG_SPEC_IVEC2: - case SLANG_SPEC_BVEC2: - case SLANG_SPEC_MAT2: - return 2; - case SLANG_SPEC_VEC3: - case SLANG_SPEC_IVEC3: - case SLANG_SPEC_BVEC3: - case SLANG_SPEC_MAT3: - return 3; - case SLANG_SPEC_VEC4: - case SLANG_SPEC_IVEC4: - case SLANG_SPEC_BVEC4: - case SLANG_SPEC_MAT4: - return 4; - - case SLANG_SPEC_MAT23: - return 2; - case SLANG_SPEC_MAT32: - return 3; - case SLANG_SPEC_MAT24: - return 2; - case SLANG_SPEC_MAT42: - return 4; - case SLANG_SPEC_MAT34: - return 3; - case SLANG_SPEC_MAT43: - return 4; - - default: - return 0; - } -} - - -/** - * Return the GL_* type that corresponds to a SLANG_SPEC_* type. - */ -GLenum -_slang_gltype_from_specifier(const slang_type_specifier *type) -{ - switch (type->type) { - case SLANG_SPEC_BOOL: - return GL_BOOL; - case SLANG_SPEC_BVEC2: - return GL_BOOL_VEC2; - case SLANG_SPEC_BVEC3: - return GL_BOOL_VEC3; - case SLANG_SPEC_BVEC4: - return GL_BOOL_VEC4; - case SLANG_SPEC_INT: - return GL_INT; - case SLANG_SPEC_IVEC2: - return GL_INT_VEC2; - case SLANG_SPEC_IVEC3: - return GL_INT_VEC3; - case SLANG_SPEC_IVEC4: - return GL_INT_VEC4; - case SLANG_SPEC_FLOAT: - return GL_FLOAT; - case SLANG_SPEC_VEC2: - return GL_FLOAT_VEC2; - case SLANG_SPEC_VEC3: - return GL_FLOAT_VEC3; - case SLANG_SPEC_VEC4: - return GL_FLOAT_VEC4; - case SLANG_SPEC_MAT2: - return GL_FLOAT_MAT2; - case SLANG_SPEC_MAT3: - return GL_FLOAT_MAT3; - case SLANG_SPEC_MAT4: - return GL_FLOAT_MAT4; - case SLANG_SPEC_MAT23: - return GL_FLOAT_MAT2x3; - case SLANG_SPEC_MAT32: - return GL_FLOAT_MAT3x2; - case SLANG_SPEC_MAT24: - return GL_FLOAT_MAT2x4; - case SLANG_SPEC_MAT42: - return GL_FLOAT_MAT4x2; - case SLANG_SPEC_MAT34: - return GL_FLOAT_MAT3x4; - case SLANG_SPEC_MAT43: - return GL_FLOAT_MAT4x3; - case SLANG_SPEC_SAMPLER_1D: - return GL_SAMPLER_1D; - case SLANG_SPEC_SAMPLER_2D: - return GL_SAMPLER_2D; - case SLANG_SPEC_SAMPLER_3D: - return GL_SAMPLER_3D; - case SLANG_SPEC_SAMPLER_CUBE: - return GL_SAMPLER_CUBE; - case SLANG_SPEC_SAMPLER_1D_SHADOW: - return GL_SAMPLER_1D_SHADOW; - case SLANG_SPEC_SAMPLER_2D_SHADOW: - return GL_SAMPLER_2D_SHADOW; - case SLANG_SPEC_SAMPLER_RECT: - return GL_SAMPLER_2D_RECT_ARB; - case SLANG_SPEC_SAMPLER_RECT_SHADOW: - return GL_SAMPLER_2D_RECT_SHADOW_ARB; - case SLANG_SPEC_SAMPLER_1D_ARRAY: - return GL_SAMPLER_1D_ARRAY_EXT; - case SLANG_SPEC_SAMPLER_2D_ARRAY: - return GL_SAMPLER_2D_ARRAY_EXT; - case SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW: - return GL_SAMPLER_1D_ARRAY_SHADOW_EXT; - case SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW: - return GL_SAMPLER_2D_ARRAY_SHADOW_EXT; - case SLANG_SPEC_ARRAY: - return _slang_gltype_from_specifier(type->_array); - case SLANG_SPEC_STRUCT: - /* fall-through */ - default: - return GL_NONE; - } -} - diff --git a/src/mesa/slang/slang_typeinfo.h b/src/mesa/slang/slang_typeinfo.h deleted file mode 100644 index 2251b06325..0000000000 --- a/src/mesa/slang/slang_typeinfo.h +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SLANG_TYPEINFO_H -#define SLANG_TYPEINFO_H 1 - -#include "main/imports.h" -#include "main/mtypes.h" -#include "slang_log.h" -#include "slang_utility.h" -#include "slang_vartable.h" - - -struct slang_operation_; - -struct slang_name_space_; - - - -/** - * Holds complete information about vector swizzle - the <swizzle> - * array contains vector component source indices, where 0 is "x", 1 - * is "y", 2 is "z" and 3 is "w". - * Example: "xwz" --> { 3, { 0, 3, 2, not used } }. - */ -typedef struct slang_swizzle_ -{ - GLuint num_components; - GLuint swizzle[4]; -} slang_swizzle; - -extern GLboolean -_slang_is_swizzle(const char *field, GLuint rows, slang_swizzle *swz); - - -typedef enum slang_type_variant_ -{ - SLANG_VARIANT, /* the default */ - SLANG_INVARIANT /* indicates the "invariant" keyword */ -} slang_type_variant; - - -typedef enum slang_type_centroid_ -{ - SLANG_CENTER, /* the default */ - SLANG_CENTROID /* indicates the "centroid" keyword */ -} slang_type_centroid; - - -/** - * These only apply to gl_FragCoord, but other layout qualifiers may - * appear in the future. - */ -typedef enum slang_layout_qualifier_ -{ - SLANG_LAYOUT_NONE = 0x0, - SLANG_LAYOUT_UPPER_LEFT_BIT = 0x1, - SLANG_LAYOUT_PIXEL_CENTER_INTEGER_BIT = 0x2 -} slang_layout_qualifier; - - -typedef enum slang_type_qualifier_ -{ - SLANG_QUAL_NONE, - SLANG_QUAL_CONST, - SLANG_QUAL_ATTRIBUTE, - SLANG_QUAL_VARYING, - SLANG_QUAL_UNIFORM, - SLANG_QUAL_OUT, - SLANG_QUAL_INOUT, - SLANG_QUAL_FIXEDOUTPUT, /* internal */ - SLANG_QUAL_FIXEDINPUT /* internal */ -} slang_type_qualifier; - -typedef enum slang_varying_kind_ -{ - SLANG_VARYING_IN, - SLANG_VARYING_OUT, -} slang_varying_kind; - -typedef enum slang_type_precision_ -{ - SLANG_PREC_DEFAULT, - SLANG_PREC_LOW, - SLANG_PREC_MEDIUM, - SLANG_PREC_HIGH -} slang_type_precision; - - -/** - * The basic shading language types (float, vec4, mat3, etc) - */ -typedef enum slang_type_specifier_type_ -{ - SLANG_SPEC_VOID, - SLANG_SPEC_BOOL, - SLANG_SPEC_BVEC2, - SLANG_SPEC_BVEC3, - SLANG_SPEC_BVEC4, - SLANG_SPEC_INT, - SLANG_SPEC_IVEC2, - SLANG_SPEC_IVEC3, - SLANG_SPEC_IVEC4, - SLANG_SPEC_FLOAT, - SLANG_SPEC_VEC2, - SLANG_SPEC_VEC3, - SLANG_SPEC_VEC4, - SLANG_SPEC_MAT2, - SLANG_SPEC_MAT3, - SLANG_SPEC_MAT4, - SLANG_SPEC_MAT23, - SLANG_SPEC_MAT32, - SLANG_SPEC_MAT24, - SLANG_SPEC_MAT42, - SLANG_SPEC_MAT34, - SLANG_SPEC_MAT43, - SLANG_SPEC_SAMPLER_1D, - SLANG_SPEC_SAMPLER_2D, - SLANG_SPEC_SAMPLER_3D, - SLANG_SPEC_SAMPLER_CUBE, - SLANG_SPEC_SAMPLER_RECT, - SLANG_SPEC_SAMPLER_1D_SHADOW, - SLANG_SPEC_SAMPLER_2D_SHADOW, - SLANG_SPEC_SAMPLER_RECT_SHADOW, - SLANG_SPEC_SAMPLER_1D_ARRAY, - SLANG_SPEC_SAMPLER_2D_ARRAY, - SLANG_SPEC_SAMPLER_1D_ARRAY_SHADOW, - SLANG_SPEC_SAMPLER_2D_ARRAY_SHADOW, - SLANG_SPEC_STRUCT, - SLANG_SPEC_ARRAY -} slang_type_specifier_type; - - -extern slang_type_specifier_type -slang_type_specifier_type_from_string(const char *); - -extern const char * -slang_type_specifier_type_to_string(slang_type_specifier_type); - - -/** - * Describes more sophisticated types, like structs and arrays. - */ -typedef struct slang_type_specifier_ -{ - slang_type_specifier_type type; - struct slang_struct_ *_struct; /**< if type == SLANG_SPEC_STRUCT */ - struct slang_type_specifier_ *_array; /**< if type == SLANG_SPEC_ARRAY */ -} slang_type_specifier; - - -extern GLvoid -slang_type_specifier_ctr(slang_type_specifier *); - -extern GLvoid -slang_type_specifier_dtr(slang_type_specifier *); - -extern slang_type_specifier * -slang_type_specifier_new(slang_type_specifier_type type, - struct slang_struct_ *_struct, - struct slang_type_specifier_ *_array); - - -extern GLboolean -slang_type_specifier_copy(slang_type_specifier *, const slang_type_specifier *); - -extern GLboolean -slang_type_specifier_equal(const slang_type_specifier *, - const slang_type_specifier *); - - -extern GLboolean -slang_type_specifier_compatible(const slang_type_specifier *x, - const slang_type_specifier *y); - - -typedef struct slang_fully_specified_type_ -{ - slang_type_qualifier qualifier; - slang_type_specifier specifier; - slang_type_precision precision; - slang_type_variant variant; - slang_type_centroid centroid; - slang_layout_qualifier layout; - GLint array_len; /**< -1 if not an array type */ - slang_varying_kind varying_kind; -} slang_fully_specified_type; - -extern int -slang_fully_specified_type_construct(slang_fully_specified_type *); - -extern void -slang_fully_specified_type_destruct(slang_fully_specified_type *); - -extern int -slang_fully_specified_type_copy(slang_fully_specified_type *, - const slang_fully_specified_type *); - -GLboolean -slang_fully_specified_types_compatible(const slang_fully_specified_type * x, - const slang_fully_specified_type * y); - - -typedef struct slang_typeinfo_ -{ - GLboolean can_be_referenced; - GLboolean is_swizzled; - slang_swizzle swz; - slang_type_specifier spec; - GLuint array_len; -} slang_typeinfo; - -extern GLboolean -slang_typeinfo_construct(slang_typeinfo *); - -extern GLvoid -slang_typeinfo_destruct(slang_typeinfo *); - - -extern GLboolean -_slang_typeof_operation(struct slang_operation_ *, - const struct slang_name_space_ *, - slang_typeinfo *, slang_atom_pool *, - slang_info_log *log); - -extern GLboolean -_slang_type_is_matrix(slang_type_specifier_type); - -extern GLboolean -_slang_type_is_vector(slang_type_specifier_type); - -extern GLboolean -_slang_type_is_float_vec_mat(slang_type_specifier_type); - -extern slang_type_specifier_type -_slang_type_base(slang_type_specifier_type); - -extern GLuint -_slang_type_dim(slang_type_specifier_type); - -extern GLenum -_slang_gltype_from_specifier(const slang_type_specifier *type); - -#endif diff --git a/src/mesa/slang/slang_utility.c b/src/mesa/slang/slang_utility.c deleted file mode 100644 index c1d57409a4..0000000000 --- a/src/mesa/slang/slang_utility.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file slang_utility.c - * slang utilities - * \author Michal Krol - */ - -#include "main/imports.h" -#include "slang_utility.h" -#include "slang_mem.h" - -char * -slang_string_concat (char *dst, const char *src) -{ - return strcpy (dst + strlen (dst), src); -} - - -/* slang_string */ - -GLvoid -slang_string_init (slang_string *self) -{ - self->data = NULL; - self->capacity = 0; - self->length = 0; - self->fail = GL_FALSE; -} - -GLvoid -slang_string_free (slang_string *self) -{ - if (self->data != NULL) - free(self->data); -} - -GLvoid -slang_string_reset (slang_string *self) -{ - self->length = 0; - self->fail = GL_FALSE; -} - -static GLboolean -grow (slang_string *self, GLuint size) -{ - if (self->fail) - return GL_FALSE; - if (size > self->capacity) { - /* do not overflow 32-bit range */ - assert (size < 0x80000000); - - self->data = (char *) (_mesa_realloc (self->data, self->capacity, size * 2)); - self->capacity = size * 2; - if (self->data == NULL) { - self->capacity = 0; - self->fail = GL_TRUE; - return GL_FALSE; - } - } - return GL_TRUE; -} - -GLvoid -slang_string_push (slang_string *self, const slang_string *str) -{ - if (str->fail) { - self->fail = GL_TRUE; - return; - } - if (grow (self, self->length + str->length)) { - memcpy (&self->data[self->length], str->data, str->length); - self->length += str->length; - } -} - -GLvoid -slang_string_pushc (slang_string *self, const char c) -{ - if (grow (self, self->length + 1)) { - self->data[self->length] = c; - self->length++; - } -} - -GLvoid -slang_string_pushs (slang_string *self, const char *cstr, GLuint len) -{ - if (grow (self, self->length + len)) { - memcpy (&self->data[self->length], cstr, len); - self->length += len; - } -} - -GLvoid -slang_string_pushi (slang_string *self, GLint i) -{ - char buffer[12]; - - _mesa_snprintf (buffer, sizeof(buffer), "%d", i); - slang_string_pushs (self, buffer, strlen (buffer)); -} - -const char * -slang_string_cstr (slang_string *self) -{ - if (grow (self, self->length + 1)) - self->data[self->length] = '\0'; - return self->data; -} - -/* slang_atom_pool */ - -void -slang_atom_pool_construct(slang_atom_pool * pool) -{ - GLuint i; - - for (i = 0; i < SLANG_ATOM_POOL_SIZE; i++) - pool->entries[i] = NULL; -} - -void -slang_atom_pool_destruct (slang_atom_pool * pool) -{ - GLuint i; - - for (i = 0; i < SLANG_ATOM_POOL_SIZE; i++) { - slang_atom_entry * entry; - - entry = pool->entries[i]; - while (entry != NULL) { - slang_atom_entry *next = entry->next; - _slang_free(entry->id); - _slang_free(entry); - entry = next; - } - } -} - -/* - * Search the atom pool for an atom with a given name. - * If atom is not found, create and add it to the pool. - * Returns ATOM_NULL if the atom was not found and the function failed - * to create a new atom. - */ -slang_atom -slang_atom_pool_atom(slang_atom_pool * pool, const char * id) -{ - GLuint hash; - const char * p = id; - slang_atom_entry ** entry; - - /* Hash a given string to a number in the range [0, ATOM_POOL_SIZE). */ - hash = 0; - while (*p != '\0') { - GLuint g; - - hash = (hash << 4) + (GLuint) (*p++); - g = hash & 0xf0000000; - if (g != 0) - hash ^= g >> 24; - hash &= ~g; - } - hash %= SLANG_ATOM_POOL_SIZE; - - /* Now the hash points to a linked list of atoms with names that - * have the same hash value. Search the linked list for a given - * name. - */ - entry = &pool->entries[hash]; - while (*entry != NULL) { - /* If the same, return the associated atom. */ - if (slang_string_compare((**entry).id, id) == 0) - return (slang_atom) (**entry).id; - /* Grab the next atom in the linked list. */ - entry = &(**entry).next; - } - - /* Okay, we have not found an atom. Create a new entry for it. - * Note that the <entry> points to the last entry's <next> field. - */ - *entry = (slang_atom_entry *) _slang_alloc(sizeof(slang_atom_entry)); - if (*entry == NULL) - return SLANG_ATOM_NULL; - - /* Initialize a new entry. Because we'll need the actual name of - * the atom, we use the pointer to this string as an actual atom's - * value. - */ - (**entry).next = NULL; - (**entry).id = _slang_strdup(id); - if ((**entry).id == NULL) - return SLANG_ATOM_NULL; - return (slang_atom) (**entry).id; -} - -/** - * Return the name of a given atom. - */ -const char * -slang_atom_pool_id(slang_atom_pool * pool, slang_atom atom) -{ - return (const char *) (atom); -} diff --git a/src/mesa/slang/slang_utility.h b/src/mesa/slang/slang_utility.h deleted file mode 100644 index cb9b6d2aaa..0000000000 --- a/src/mesa/slang/slang_utility.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SLANG_UTILITY_H -#define SLANG_UTILITY_H - - -#include "main/glheader.h" - -/* Compile-time assertions. If the expression is zero, try to declare an - * array of size [-1] to cause compilation error. - */ -#define static_assert(expr) do { int _array[(expr) ? 1 : -1]; (void) _array[0]; } while (0) - - -#define slang_string_compare(str1, str2) strcmp (str1, str2) -#define slang_string_copy(dst, src) strcpy (dst, src) -#define slang_string_length(str) strlen (str) - -char *slang_string_concat (char *, const char *); - -/* slang_string */ - -typedef struct -{ - char *data; - GLuint length; - GLuint capacity; - GLboolean fail; -} slang_string; - -GLvoid -slang_string_init (slang_string *); - -GLvoid -slang_string_free (slang_string *); - -GLvoid -slang_string_reset (slang_string *); - -GLvoid -slang_string_push (slang_string *, const slang_string *); - -GLvoid -slang_string_pushc (slang_string *, const char); - -GLvoid -slang_string_pushs (slang_string *, const char *, GLuint); - -GLvoid -slang_string_pushi (slang_string *, GLint); - -const char * -slang_string_cstr (slang_string *); - -/* slang_atom */ - -typedef GLvoid *slang_atom; - -#define SLANG_ATOM_NULL ((slang_atom) 0) - -typedef struct slang_atom_entry_ -{ - char *id; - struct slang_atom_entry_ *next; -} slang_atom_entry; - -#define SLANG_ATOM_POOL_SIZE 1023 - -typedef struct slang_atom_pool_ -{ - slang_atom_entry *entries[SLANG_ATOM_POOL_SIZE]; -} slang_atom_pool; - -GLvoid slang_atom_pool_construct (slang_atom_pool *); -GLvoid slang_atom_pool_destruct (slang_atom_pool *); -slang_atom slang_atom_pool_atom (slang_atom_pool *, const char *); -const char *slang_atom_pool_id (slang_atom_pool *, slang_atom); - - -#endif diff --git a/src/mesa/slang/slang_vartable.c b/src/mesa/slang/slang_vartable.c deleted file mode 100644 index 8371631578..0000000000 --- a/src/mesa/slang/slang_vartable.c +++ /dev/null @@ -1,362 +0,0 @@ - -#include "main/imports.h" -#include "program/program.h" -#include "program/prog_print.h" -#include "slang_compile.h" -#include "slang_compile_variable.h" -#include "slang_emit.h" -#include "slang_mem.h" -#include "slang_vartable.h" -#include "slang_ir.h" - - -static int dbg = 0; - - -typedef enum { - FREE, - VAR, - TEMP -} TempState; - - -/** - * Variable/register info for one variable scope. - */ -struct table -{ - int Level; - int NumVars; - slang_variable **Vars; /* array [NumVars] */ - - TempState Temps[MAX_PROGRAM_TEMPS * 4]; /* per-component state */ - int ValSize[MAX_PROGRAM_TEMPS * 4]; /**< For debug only */ - - struct table *Parent; /** Parent scope table */ -}; - - -/** - * A variable table is a stack of tables, one per scope. - */ -struct slang_var_table_ -{ - GLint CurLevel; - GLuint MaxRegisters; - struct table *Top; /**< Table at top of stack */ -}; - - - -slang_var_table * -_slang_new_var_table(GLuint maxRegisters) -{ - slang_var_table *vt - = (slang_var_table *) _slang_alloc(sizeof(slang_var_table)); - if (vt) { - vt->MaxRegisters = maxRegisters; - } - return vt; -} - - -void -_slang_delete_var_table(slang_var_table *vt) -{ - if (vt->Top) { - _mesa_problem(NULL, "non-empty var table in _slang_delete_var_table()"); - return; - } - _slang_free(vt); -} - - - -/** - * Create new table on top of vartable stack. - * Used when we enter a {} block. - */ -void -_slang_push_var_table(slang_var_table *vt) -{ - struct table *t = (struct table *) _slang_alloc(sizeof(struct table)); - if (t) { - t->Level = vt->CurLevel++; - t->Parent = vt->Top; - if (t->Parent) { - /* copy the info indicating which temp regs are in use */ - memcpy(t->Temps, t->Parent->Temps, sizeof(t->Temps)); - memcpy(t->ValSize, t->Parent->ValSize, sizeof(t->ValSize)); - } - vt->Top = t; - if (dbg) printf("Pushing level %d\n", t->Level); - } -} - - -/** - * Pop top entry from variable table. - * Used when we leave a {} block. - */ -void -_slang_pop_var_table(slang_var_table *vt) -{ - struct table *t = vt->Top; - int i; - - if (dbg) printf("Popping level %d\n", t->Level); - - /* free the storage allocated for each variable */ - for (i = 0; i < t->NumVars; i++) { - slang_ir_storage *store = t->Vars[i]->store; - GLint j; - GLuint comp; - if (dbg) printf(" Free var %s, size %d at %d.%s\n", - (char*) t->Vars[i]->a_name, store->Size, - store->Index, - _mesa_swizzle_string(store->Swizzle, 0, 0)); - - if (store->File == PROGRAM_SAMPLER) { - /* samplers have no storage */ - continue; - } - - if (store->Size == 1) - comp = GET_SWZ(store->Swizzle, 0); - else - comp = 0; - - /* store->Index may be -1 if we run out of registers */ - if (store->Index >= 0) { - for (j = 0; j < store->Size; j++) { - assert(t->Temps[store->Index * 4 + j + comp] == VAR); - t->Temps[store->Index * 4 + j + comp] = FREE; - } - } - store->Index = -1; - } - if (t->Parent) { - /* just verify that any remaining allocations in this scope - * were for temps - */ - for (i = 0; i < (int) vt->MaxRegisters * 4; i++) { - if (t->Temps[i] != FREE && t->Parent->Temps[i] == FREE) { - if (dbg) printf(" Free reg %d\n", i/4); - assert(t->Temps[i] == TEMP); - } - } - } - - if (t->Vars) { - _slang_free(t->Vars); - t->Vars = NULL; - } - - vt->Top = t->Parent; - _slang_free(t); - vt->CurLevel--; -} - - -/** - * Add a new variable to the given var/symbol table. - */ -void -_slang_add_variable(slang_var_table *vt, slang_variable *v) -{ - struct table *t; - assert(vt); - t = vt->Top; - assert(t); - if (dbg) printf("Adding var %s, store %p\n", (char *) v->a_name, (void *) v->store); - t->Vars = (slang_variable **) - _slang_realloc(t->Vars, - t->NumVars * sizeof(slang_variable *), - (t->NumVars + 1) * sizeof(slang_variable *)); - t->Vars[t->NumVars] = v; - t->NumVars++; -} - - -/** - * Look for variable by name in given table. - * If not found, Parent table will be searched. - */ -slang_variable * -_slang_find_variable(const slang_var_table *vt, slang_atom name) -{ - struct table *t = vt->Top; - while (1) { - int i; - for (i = 0; i < t->NumVars; i++) { - if (t->Vars[i]->a_name == name) - return t->Vars[i]; - } - if (t->Parent) - t = t->Parent; - else - return NULL; - } -} - - -/** - * Allocation helper. - * \param size var size in floats - * \return position for var, measured in floats - */ -static GLint -alloc_reg(slang_var_table *vt, GLint size, GLboolean isTemp) -{ - struct table *t = vt->Top; - /* if size == 1, allocate anywhere, else, pos must be multiple of 4 */ - const GLuint step = (size == 1) ? 1 : 4; - GLuint i, j; - assert(size > 0); /* number of floats */ - - for (i = 0; i <= vt->MaxRegisters * 4 - size; i += step) { - GLuint found = 0; - for (j = 0; j < (GLuint) size; j++) { - assert(i + j < 4 * MAX_PROGRAM_TEMPS); - if (i + j < vt->MaxRegisters * 4 && t->Temps[i + j] == FREE) { - found++; - } - else { - break; - } - } - if (found == size) { - /* found block of size free regs */ - if (size > 1) - assert(i % 4 == 0); - for (j = 0; j < (GLuint) size; j++) { - assert(i + j < 4 * MAX_PROGRAM_TEMPS); - t->Temps[i + j] = isTemp ? TEMP : VAR; - } - assert(i < MAX_PROGRAM_TEMPS * 4); - t->ValSize[i] = size; - return i; - } - } - - /* if we get here, we ran out of registers */ - return -1; -} - - -/** - * Allocate temp register(s) for storing a variable. - * \param size size needed, in floats - * \param swizzle returns swizzle mask for accessing var in register - * \return register allocated, or -1 - */ -GLboolean -_slang_alloc_var(slang_var_table *vt, slang_ir_storage *store) -{ - struct table *t = vt->Top; - int i; - - if (store->File == PROGRAM_SAMPLER) { - /* don't really allocate storage */ - store->Index = 0; - return GL_TRUE; - } - - i = alloc_reg(vt, store->Size, GL_FALSE); - if (i < 0) - return GL_FALSE; - - store->Index = i / 4; - store->Swizzle = _slang_var_swizzle(store->Size, i % 4); - - if (dbg) - printf("Alloc var storage sz %d at %d.%s (level %d) store %p\n", - store->Size, store->Index, - _mesa_swizzle_string(store->Swizzle, 0, 0), - t->Level, - (void*) store); - - return GL_TRUE; -} - - - -/** - * Allocate temp register(s) for storing an unnamed intermediate value. - */ -GLboolean -_slang_alloc_temp(slang_var_table *vt, slang_ir_storage *store) -{ - struct table *t = vt->Top; - const int i = alloc_reg(vt, store->Size, GL_TRUE); - if (i < 0) - return GL_FALSE; - - assert(store->Index < 0); - - store->Index = i / 4; - store->Swizzle = _slang_var_swizzle(store->Size, i % 4); - - if (dbg) printf("Alloc temp sz %d at %d.%s (level %d) store %p\n", - store->Size, store->Index, - _mesa_swizzle_string(store->Swizzle, 0, 0), t->Level, - (void *) store); - - return GL_TRUE; -} - - -void -_slang_free_temp(slang_var_table *vt, slang_ir_storage *store) -{ - struct table *t = vt->Top; - GLuint i; - GLint r = store->Index; - assert(store->Size > 0); - assert(r >= 0); - assert((GLuint)r + store->Size <= vt->MaxRegisters * 4); - if (dbg) printf("Free temp sz %d at %d.%s (level %d) store %p\n", - store->Size, r, - _mesa_swizzle_string(store->Swizzle, 0, 0), - t->Level, (void *) store); - if (store->Size == 1) { - const GLuint comp = GET_SWZ(store->Swizzle, 0); - /* we can actually fail some of these assertions because of the - * troublesome IR_SWIZZLE handling. - */ -#if 0 - assert(store->Swizzle == MAKE_SWIZZLE4(comp, comp, comp, comp)); - assert(comp < 4); - assert(t->ValSize[r * 4 + comp] == 1); -#endif - assert(t->Temps[r * 4 + comp] == TEMP); - t->Temps[r * 4 + comp] = FREE; - } - else { - /*assert(store->Swizzle == SWIZZLE_NOOP);*/ - assert(t->ValSize[r*4] == store->Size); - for (i = 0; i < (GLuint) store->Size; i++) { - assert(t->Temps[r * 4 + i] == TEMP); - t->Temps[r * 4 + i] = FREE; - } - } -} - - -GLboolean -_slang_is_temp(const slang_var_table *vt, const slang_ir_storage *store) -{ - struct table *t = vt->Top; - GLuint comp; - assert(store->Index >= 0); - assert(store->Index < (int) vt->MaxRegisters); - if (store->Swizzle == SWIZZLE_NOOP) - comp = 0; - else - comp = GET_SWZ(store->Swizzle, 0); - - if (t->Temps[store->Index * 4 + comp] == TEMP) - return GL_TRUE; - else - return GL_FALSE; -} diff --git a/src/mesa/slang/slang_vartable.h b/src/mesa/slang/slang_vartable.h deleted file mode 100644 index 97945b89d0..0000000000 --- a/src/mesa/slang/slang_vartable.h +++ /dev/null @@ -1,45 +0,0 @@ - -#ifndef SLANG_VARTABLE_H -#define SLANG_VARTABLE_H - -#include "main/glheader.h" -#include "slang_utility.h" - -struct slang_ir_storage_; - -typedef struct slang_var_table_ slang_var_table; - -struct slang_variable_; - -extern slang_var_table * -_slang_new_var_table(GLuint maxRegisters); - -extern void -_slang_delete_var_table(slang_var_table *vt); - -extern void -_slang_push_var_table(slang_var_table *parent); - -extern void -_slang_pop_var_table(slang_var_table *t); - -extern void -_slang_add_variable(slang_var_table *t, struct slang_variable_ *v); - -extern struct slang_variable_ * -_slang_find_variable(const slang_var_table *t, slang_atom name); - -extern GLboolean -_slang_alloc_var(slang_var_table *t, struct slang_ir_storage_ *store); - -extern GLboolean -_slang_alloc_temp(slang_var_table *t, struct slang_ir_storage_ *store); - -extern void -_slang_free_temp(slang_var_table *t, struct slang_ir_storage_ *store); - -extern GLboolean -_slang_is_temp(const slang_var_table *t, const struct slang_ir_storage_ *store); - - -#endif /* SLANG_VARTABLE_H */ diff --git a/src/mesa/sources.mak b/src/mesa/sources.mak index f01b60c4fc..9156024d47 100644 --- a/src/mesa/sources.mak +++ b/src/mesa/sources.mak @@ -250,26 +250,8 @@ PROGRAM_SOURCES = \ program/programopt.c \ program/symbol_table.c -SLANG_SOURCES = \ - slang/slang_builtin.c \ - slang/slang_codegen.c \ - slang/slang_compile.c \ - slang/slang_compile_function.c \ - slang/slang_compile_operation.c \ - slang/slang_compile_struct.c \ - slang/slang_compile_variable.c \ - slang/slang_emit.c \ - slang/slang_ir.c \ - slang/slang_label.c \ - slang/slang_link.c \ - slang/slang_log.c \ - slang/slang_mem.c \ - slang/slang_print.c \ - slang/slang_simplify.c \ - slang/slang_storage.c \ - slang/slang_typeinfo.c \ - slang/slang_vartable.c \ - slang/slang_utility.c +SHADER_CXX_SOURCES = \ + program/ir_to_mesa.cpp ASM_C_SOURCES = \ x86/common_x86.c \ @@ -324,8 +306,10 @@ MESA_SOURCES = \ $(SWRAST_SOURCES) \ $(SWRAST_SETUP_SOURCES) \ $(COMMON_DRIVER_SOURCES)\ - $(ASM_C_SOURCES) \ - $(SLANG_SOURCES) + $(ASM_C_SOURCES) + +MESA_CXX_SOURCES = \ + $(SHADER_CXX_SOURCES) # Sources for building Gallium drivers MESA_GALLIUM_SOURCES = \ @@ -335,12 +319,15 @@ MESA_GALLIUM_SOURCES = \ $(STATETRACKER_SOURCES) \ $(PROGRAM_SOURCES) \ ppc/common_ppc.c \ - x86/common_x86.c \ - $(SLANG_SOURCES) + x86/common_x86.c + +MESA_GALLIUM_CXX_SOURCES = \ + $(SHADER_CXX_SOURCES) # All the core C sources, for dependency checking ALL_SOURCES = \ $(MESA_SOURCES) \ + $(MESA_CXX_SOURCES) \ $(MESA_ASM_SOURCES) \ $(STATETRACKER_SOURCES) @@ -349,10 +336,12 @@ ALL_SOURCES = \ MESA_OBJECTS = \ $(MESA_SOURCES:.c=.o) \ + $(MESA_CXX_SOURCES:.cpp=.o) \ $(MESA_ASM_SOURCES:.S=.o) MESA_GALLIUM_OBJECTS = \ $(MESA_GALLIUM_SOURCES:.c=.o) \ + $(MESA_GALLIUM_CXX_SOURCES:.cpp=.o) \ $(MESA_ASM_SOURCES:.S=.o) @@ -362,8 +351,7 @@ COMMON_DRIVER_OBJECTS = $(COMMON_DRIVER_SOURCES:.c=.o) ### Other archives/libraries GLSL_LIBS = \ - $(TOP)/src/glsl/pp/libglslpp.a \ - $(TOP)/src/glsl/cl/libglslcl.a + $(TOP)/src/glsl/libglsl.a ### Include directories diff --git a/src/mesa/state_tracker/st_cb_accum.h b/src/mesa/state_tracker/st_cb_accum.h index 7d52481c82..06425dc8a3 100644 --- a/src/mesa/state_tracker/st_cb_accum.h +++ b/src/mesa/state_tracker/st_cb_accum.h @@ -41,6 +41,8 @@ extern void st_init_accum_functions(struct dd_function_table *functions); #else +#include "main/compiler.h" + static INLINE void st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) { diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c index 0b8ecd27cb..8da5cbb5e6 100644 --- a/src/mesa/state_tracker/st_cb_bitmap.c +++ b/src/mesa/state_tracker/st_cb_bitmap.c @@ -275,7 +275,7 @@ make_bitmap_texture(GLcontext *ctx, GLsizei width, GLsizei height, /** * Create texture to hold bitmap pattern. */ - pt = st_texture_create(st, PIPE_TEXTURE_2D, st->bitmap.tex_format, + pt = st_texture_create(st, st->internal_target, st->bitmap.tex_format, 0, width, height, 1, PIPE_BIND_SAMPLER_VIEW); if (!pt) { @@ -304,7 +304,7 @@ make_bitmap_texture(GLcontext *ctx, GLsizei width, GLsizei height, } static GLuint -setup_bitmap_vertex_data(struct st_context *st, +setup_bitmap_vertex_data(struct st_context *st, bool normalized, int x, int y, int width, int height, float z, const float color[4]) { @@ -316,12 +316,20 @@ setup_bitmap_vertex_data(struct st_context *st, const GLfloat x1 = (GLfloat)(x + width); const GLfloat y0 = (GLfloat)y; const GLfloat y1 = (GLfloat)(y + height); - const GLfloat sLeft = (GLfloat)0.0, sRight = (GLfloat)1.0; - const GLfloat tTop = (GLfloat)0.0, tBot = (GLfloat)1.0 - tTop; + GLfloat sLeft = (GLfloat)0.0, sRight = (GLfloat)1.0; + GLfloat tTop = (GLfloat)0.0, tBot = (GLfloat)1.0 - tTop; const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0); const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0); const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0); const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0); + const GLuint max_slots = 1; /* 4096 / sizeof(st->bitmap.vertices); */ + GLuint i; + + if(!normalized) + { + sRight = width; + tBot = height; + } /* XXX: Need to improve buffer_write to allow NO_WAIT (as well as * no_flush) updates to buffers where we know there is no conflict @@ -333,9 +341,6 @@ setup_bitmap_vertex_data(struct st_context *st, * price of allocating a new buffer for each bitmap cache-flush to * avoid synchronous rendering. */ - const GLuint max_slots = 1; /* 4096 / sizeof(st->bitmap.vertices); */ - GLuint i; - if (st->bitmap.vbuf_slot >= max_slots) { pipe_resource_reference(&st->bitmap.vbuf, NULL); st->bitmap.vbuf_slot = 0; @@ -462,7 +467,7 @@ draw_bitmap_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, for (i = 0; i < st->state.num_samplers; i++) { samplers[i] = &st->state.samplers[i]; } - samplers[stfp->bitmap_sampler] = &st->bitmap.sampler; + samplers[stfp->bitmap_sampler] = &st->bitmap.samplers[sv->texture->target != PIPE_TEXTURE_RECT]; cso_set_samplers(cso, num, (const struct pipe_sampler_state **) samplers); } @@ -499,7 +504,7 @@ draw_bitmap_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, z = z * 2.0 - 1.0; /* draw textured quad */ - offset = setup_bitmap_vertex_data(st, x, y, width, height, z, color); + offset = setup_bitmap_vertex_data(st, sv->texture->target != PIPE_TEXTURE_RECT, x, y, width, height, z, color); util_draw_vertex_buffer(pipe, st->bitmap.vbuf, offset, PIPE_PRIM_TRIANGLE_FAN, @@ -761,7 +766,7 @@ st_Bitmap(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, if (pt) { struct pipe_sampler_view *sv = st_create_texture_sampler_view(st->pipe, pt); - assert(pt->target == PIPE_TEXTURE_2D); + assert(pt->target == PIPE_TEXTURE_2D || pt->target == PIPE_TEXTURE_RECT); if (sv) { draw_bitmap_quad(ctx, x, y, ctx->Current.RasterPos[2], @@ -789,7 +794,7 @@ st_init_bitmap_functions(struct dd_function_table *functions) void st_init_bitmap(struct st_context *st) { - struct pipe_sampler_state *sampler = &st->bitmap.sampler; + struct pipe_sampler_state *sampler = &st->bitmap.samplers[0]; struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; @@ -801,7 +806,8 @@ st_init_bitmap(struct st_context *st) sampler->min_img_filter = PIPE_TEX_FILTER_NEAREST; sampler->min_mip_filter = PIPE_TEX_MIPFILTER_NONE; sampler->mag_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler->normalized_coords = 1; + st->bitmap.samplers[1] = *sampler; + st->bitmap.samplers[1].normalized_coords = 1; /* init baseline rasterizer state once */ memset(&st->bitmap.rasterizer, 0, sizeof(st->bitmap.rasterizer)); diff --git a/src/mesa/state_tracker/st_cb_blit.c b/src/mesa/state_tracker/st_cb_blit.c index 1f73f503f6..536748402f 100644 --- a/src/mesa/state_tracker/st_cb_blit.c +++ b/src/mesa/state_tracker/st_cb_blit.c @@ -40,6 +40,7 @@ #include "st_cb_fbo.h" #include "util/u_blit.h" +#include "util/u_inlines.h" void @@ -152,38 +153,33 @@ st_BlitFramebuffer(GLcontext *ctx, /* depth and/or stencil blit */ /* get src/dst depth surfaces */ - struct st_renderbuffer *srcDepthRb = + struct gl_renderbuffer_attachment *srcDepth = + &readFB->Attachment[BUFFER_DEPTH]; + struct gl_renderbuffer_attachment *dstDepth = + &drawFB->Attachment[BUFFER_DEPTH]; + struct gl_renderbuffer_attachment *srcStencil = + &readFB->Attachment[BUFFER_STENCIL]; + struct gl_renderbuffer_attachment *dstStencil = + &drawFB->Attachment[BUFFER_STENCIL]; + + struct st_renderbuffer *srcDepthRb = st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct st_renderbuffer *dstDepthRb = st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer); - struct pipe_surface *srcDepthSurf = - srcDepthRb ? srcDepthRb->surface : NULL; struct pipe_surface *dstDepthSurf = dstDepthRb ? dstDepthRb->surface : NULL; - /* get src/dst stencil surfaces */ - struct st_renderbuffer *srcStencilRb = - st_renderbuffer(readFB->Attachment[BUFFER_STENCIL].Renderbuffer); - struct st_renderbuffer *dstStencilRb = - st_renderbuffer(drawFB->Attachment[BUFFER_STENCIL].Renderbuffer); - struct pipe_surface *srcStencilSurf = - srcStencilRb ? srcStencilRb->surface : NULL; - struct pipe_surface *dstStencilSurf = - dstStencilRb ? dstStencilRb->surface : NULL; - if ((mask & depthStencil) == depthStencil && - srcDepthSurf == srcStencilSurf && - dstDepthSurf == dstStencilSurf) { - struct pipe_subresource srcSub; - - srcSub.face = srcDepthRb->surface->face; - srcSub.level = srcDepthRb->surface->level; + st_is_depth_stencil_combined(srcDepth, srcStencil) && + st_is_depth_stencil_combined(dstDepth, dstStencil)) { /* Blitting depth and stencil values between combined * depth/stencil buffers. This is the ideal case for such buffers. */ - util_blit_pixels(st->blit, - srcDepthRb->texture, srcSub, srcX0, srcY0, srcX1, srcY1, + util_blit_pixels(st->blit, srcDepthRb->texture, + u_subresource(srcDepthRb->surface->face, + srcDepthRb->surface->level), + srcX0, srcY0, srcX1, srcY1, srcDepthRb->surface->zslice, dstDepthSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter); @@ -192,8 +188,13 @@ st_BlitFramebuffer(GLcontext *ctx, /* blitting depth and stencil separately */ if (mask & GL_DEPTH_BUFFER_BIT) { - /* blit Z only */ - _mesa_problem(ctx, "st_BlitFramebuffer(DEPTH) not completed"); + util_blit_pixels(st->blit, srcDepthRb->texture, + u_subresource(srcDepthRb->surface->face, + srcDepthRb->surface->level), + srcX0, srcY0, srcX1, srcY1, + srcDepthRb->surface->zslice, + dstDepthSurf, dstX0, dstY0, dstX1, dstY1, + 0.0, pFilter); } if (mask & GL_STENCIL_BUFFER_BIT) { diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c index 69a3dd45e8..1147b1950e 100644 --- a/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -301,37 +301,10 @@ static struct pipe_resource * alloc_texture(struct st_context *st, GLsizei width, GLsizei height, enum pipe_format texFormat) { - struct pipe_context *pipe = st->pipe; - struct pipe_screen *screen = pipe->screen; struct pipe_resource *pt; - int ptw, pth; - - ptw = width; - pth = height; - - /* Need to use POT texture? */ - if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) { - int l2pt, maxSize; - - l2pt = util_logbase2(width); - if (1 << l2pt != width) { - ptw = 1 << (l2pt + 1); - } - - l2pt = util_logbase2(height); - if (1 << l2pt != height) { - pth = 1 << (l2pt + 1); - } - - /* Check against maximum texture size */ - maxSize = 1 << (pipe->screen->get_param(pipe->screen, - PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); - assert(ptw <= maxSize); - assert(pth <= maxSize); - } - pt = st_texture_create(st, PIPE_TEXTURE_2D, texFormat, 0, - ptw, pth, 1, PIPE_BIND_SAMPLER_VIEW); + pt = st_texture_create(st, st->internal_target, texFormat, 0, + width, height, 1, PIPE_BIND_SAMPLER_VIEW); return pt; } @@ -536,6 +509,7 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, struct cso_context *cso = st->cso_context; GLfloat x0, y0, x1, y1; GLsizei maxSize; + boolean normalized = sv->texture->target != PIPE_TEXTURE_RECT; /* limit checks */ /* XXX if DrawPixels image is larger than max texture size, break @@ -579,7 +553,7 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.normalized_coords = 1; + sampler.normalized_coords = normalized; cso_single_sampler(cso, 0, &sampler); if (st->pixel_xfer.pixelmap_enabled) { @@ -635,8 +609,8 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, z = z * 2.0 - 1.0; draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, - (GLfloat) width / sv->texture->width0, - (GLfloat) height / sv->texture->height0); + normalized ? ((GLfloat) width / sv->texture->width0) : (GLfloat)width, + normalized ? ((GLfloat) height / sv->texture->height0) : (GLfloat)height); /* restore state */ cso_restore_rasterizer(cso); @@ -1002,7 +976,7 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, srcFormat = rbRead->texture->format; - if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D, sample_count, + if (screen->is_format_supported(screen, srcFormat, st->internal_target, sample_count, PIPE_BIND_SAMPLER_VIEW, 0)) { texFormat = srcFormat; } @@ -1010,13 +984,13 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, /* srcFormat can't be used as a texture format */ if (type == GL_DEPTH) { texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, - PIPE_TEXTURE_2D, sample_count, + st->internal_target, sample_count, PIPE_BIND_DEPTH_STENCIL); assert(texFormat != PIPE_FORMAT_NONE); } else { /* default color format */ - texFormat = st_choose_format(screen, GL_RGBA, PIPE_TEXTURE_2D, + texFormat = st_choose_format(screen, GL_RGBA, st->internal_target, sample_count, PIPE_BIND_SAMPLER_VIEW); assert(texFormat != PIPE_FORMAT_NONE); } diff --git a/src/mesa/state_tracker/st_cb_eglimage.c b/src/mesa/state_tracker/st_cb_eglimage.c index 037e576fab..3145416383 100644 --- a/src/mesa/state_tracker/st_cb_eglimage.c +++ b/src/mesa/state_tracker/st_cb_eglimage.c @@ -128,7 +128,8 @@ st_bind_surface(GLcontext *ctx, GLenum target, _mesa_set_fetch_functions(texImage, 2); /* FIXME create a non-default sampler view from the pipe_surface? */ - pipe_resource_reference(&stImage->pt, ps->texture); + pipe_resource_reference(&stObj->pt, ps->texture); + pipe_resource_reference(&stImage->pt, stObj->pt); stObj->width0 = ps->width; stObj->height0 = ps->height; diff --git a/src/mesa/state_tracker/st_cb_fbo.c b/src/mesa/state_tracker/st_cb_fbo.c index 13119ce203..71bd4729e0 100644 --- a/src/mesa/state_tracker/st_cb_fbo.c +++ b/src/mesa/state_tracker/st_cb_fbo.c @@ -108,7 +108,7 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, /* Setup new texture template. */ memset(&template, 0, sizeof(template)); - template.target = PIPE_TEXTURE_2D; + template.target = st->internal_target; template.format = format; template.width0 = width; template.height0 = height; @@ -448,6 +448,30 @@ st_validate_attachment(struct pipe_screen *screen, /** + * Check if two renderbuffer attachments name a combined depth/stencil + * renderbuffer. + */ +GLboolean +st_is_depth_stencil_combined(const struct gl_renderbuffer_attachment *depth, + const struct gl_renderbuffer_attachment *stencil) +{ + assert(depth && stencil); + + if (depth->Type == stencil->Type) { + if (depth->Type == GL_RENDERBUFFER_EXT && + depth->Renderbuffer == stencil->Renderbuffer) + return GL_TRUE; + + if (depth->Type == GL_TEXTURE && + depth->Texture == stencil->Texture) + return GL_TRUE; + } + + return GL_FALSE; +} + + +/** * Check that the framebuffer configuration is valid in terms of what * the driver can support. * @@ -543,6 +567,7 @@ st_ReadBuffer(GLcontext *ctx, GLenum buffer) void st_init_fbo_functions(struct dd_function_table *functions) { +#if FEATURE_EXT_framebuffer_object functions->NewFramebuffer = st_new_framebuffer; functions->NewRenderbuffer = st_new_renderbuffer; functions->BindFramebuffer = st_bind_framebuffer; @@ -550,6 +575,7 @@ void st_init_fbo_functions(struct dd_function_table *functions) functions->RenderTexture = st_render_texture; functions->FinishRenderTexture = st_finish_render_texture; functions->ValidateFramebuffer = st_validate_framebuffer; +#endif /* no longer needed by core Mesa, drivers handle resizes... functions->ResizeBuffers = st_resize_buffers; */ diff --git a/src/mesa/state_tracker/st_cb_fbo.h b/src/mesa/state_tracker/st_cb_fbo.h index 62a9bbcb25..3e9815c1b1 100644 --- a/src/mesa/state_tracker/st_cb_fbo.h +++ b/src/mesa/state_tracker/st_cb_fbo.h @@ -88,4 +88,9 @@ st_get_renderbuffer_sampler_view(struct st_renderbuffer *rb, struct pipe_context *pipe); +extern GLboolean +st_is_depth_stencil_combined(const struct gl_renderbuffer_attachment *depth, + const struct gl_renderbuffer_attachment *stencil); + + #endif /* ST_CB_FBO_H */ diff --git a/src/mesa/state_tracker/st_cb_readpixels.c b/src/mesa/state_tracker/st_cb_readpixels.c index b8493dab93..6ab03ec939 100644 --- a/src/mesa/state_tracker/st_cb_readpixels.c +++ b/src/mesa/state_tracker/st_cb_readpixels.c @@ -68,16 +68,20 @@ st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y, ubyte *stmap; GLint j; + if (strb->Base.Wrapped) { + strb = st_renderbuffer(strb->Base.Wrapped); + } + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { y = ctx->DrawBuffer->Height - y - height; } /* Create a read transfer from the renderbuffer's texture */ - pt = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, - 0, 0, 0, - PIPE_TRANSFER_READ, x, y, - width, height); + pt = pipe_get_transfer(pipe, strb->texture, + 0, 0, 0, /* face, level, zslice */ + PIPE_TRANSFER_READ, + x, y, width, height); /* map the stencil buffer */ stmap = pipe_transfer_map(pipe, pt); @@ -230,10 +234,10 @@ st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb, y = strb->texture->height0 - y - height; } - trans = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, - 0, 0, 0, - PIPE_TRANSFER_READ, x, y, - width, height); + trans = pipe_get_transfer(pipe, strb->texture, + 0, 0, 0, /* face, level, zslice */ + PIPE_TRANSFER_READ, + x, y, width, height); if (!trans) { return GL_FALSE; } @@ -359,6 +363,9 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, } else if (format == GL_DEPTH_COMPONENT) { strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); + if (strb->Base.Wrapped) { + strb = st_renderbuffer(strb->Base.Wrapped); + } } else { /* Read color buffer */ @@ -394,10 +401,10 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, } /* Create a read transfer from the renderbuffer's texture */ - trans = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, - 0, 0, 0, - PIPE_TRANSFER_READ, x, y, - width, height); + trans = pipe_get_transfer(pipe, strb->texture, + 0, 0, 0, /* face, level, zslice */ + PIPE_TRANSFER_READ, + x, y, width, height); /* determine bottom-to-top vs. top-to-bottom order */ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index 4c3e3688dd..9eb14033ee 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -74,9 +74,11 @@ gl_target_to_pipe(GLenum target) return PIPE_TEXTURE_1D; case GL_TEXTURE_2D: - case GL_TEXTURE_RECTANGLE_NV: return PIPE_TEXTURE_2D; + case GL_TEXTURE_RECTANGLE_NV: + return PIPE_TEXTURE_RECT; + case GL_TEXTURE_3D: return PIPE_TEXTURE_3D; @@ -449,7 +451,7 @@ compress_with_blit(GLcontext * ctx, /* Create the temporary source texture */ memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; + templ.target = st->internal_target; templ.format = st_mesa_format_to_pipe_format(mesa_format); templ.width0 = width; templ.height0 = height; @@ -546,6 +548,14 @@ st_TexImage(GLcontext * ctx, /* switch to "normal" */ if (stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj); + pipe_resource_reference(&stObj->pt, NULL); + + /* oops, need to init this image again */ + _mesa_init_teximage_fields(ctx, target, texImage, + width, height, depth, border, internalFormat); + _mesa_choose_texture_format(ctx, texObj, texImage, target, level, + internalFormat, format, type); + stObj->surface_based = GL_FALSE; } diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c index 2ce5f08753..3b046962ef 100644 --- a/src/mesa/state_tracker/st_context.c +++ b/src/mesa/state_tracker/st_context.c @@ -125,6 +125,11 @@ st_create_context_priv( GLcontext *ctx, struct pipe_context *pipe ) st_init_generate_mipmap(st); st_init_blit(st); + if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES)) + st->internal_target = PIPE_TEXTURE_2D; + else + st->internal_target = PIPE_TEXTURE_RECT; + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) st->state.sampler_list[i] = &st->state.samplers[i]; diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index 60c25fb8f0..991feee300 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -149,7 +149,7 @@ struct st_context /** for glBitmap */ struct { struct pipe_rasterizer_state rasterizer; - struct pipe_sampler_state sampler; + struct pipe_sampler_state samplers[2]; enum pipe_format tex_format; void *vs; float vertices[4][3][4]; /**< vertex pos + color + texcoord */ @@ -182,6 +182,7 @@ struct st_context void *passthrough_fs; /**< simple pass-through frag shader */ + enum pipe_texture_target internal_target; struct gen_mipmap_state *gen_mipmap; struct blit_state *blit; diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c index 5b05489270..318e08886c 100644 --- a/src/mesa/state_tracker/st_draw.c +++ b/src/mesa/state_tracker/st_draw.c @@ -691,9 +691,6 @@ st_draw_vbo(GLcontext *ctx, pipe->set_vertex_buffers(pipe, num_vbuffers, vbuffer); cso_set_vertex_elements(st->cso_context, num_velements, velements); - if (num_vbuffers == 0 || num_velements == 0) - return; - setup_index_buffer(ctx, ib, &ibuffer); pipe->set_index_buffer(pipe, &ibuffer); diff --git a/src/mesa/state_tracker/st_draw_feedback.c b/src/mesa/state_tracker/st_draw_feedback.c index 5cf2666334..df05c7f70d 100644 --- a/src/mesa/state_tracker/st_draw_feedback.c +++ b/src/mesa/state_tracker/st_draw_feedback.c @@ -104,14 +104,15 @@ st_feedback_draw_vbo(GLcontext *ctx, struct draw_context *draw = st->draw; const struct st_vertex_program *vp; const struct pipe_shader_state *vs; - struct pipe_resource *index_buffer_handle = 0; struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; + struct pipe_index_buffer ibuffer; struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; struct pipe_transfer *ib_transfer = NULL; struct pipe_transfer *cb_transfer; GLuint attr, i; ubyte *mapped_constants; + const void *mapped_indices = NULL; assert(draw); @@ -204,17 +205,19 @@ st_feedback_draw_vbo(GLcontext *ctx, draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); draw_set_vertex_elements(draw, vp->num_inputs, velements); + memset(&ibuffer, 0, sizeof(ibuffer)); if (ib) { struct gl_buffer_object *bufobj = ib->obj; - unsigned indexSize; - void *map; switch (ib->type) { case GL_UNSIGNED_INT: - indexSize = 4; + ibuffer.index_size = 4; break; case GL_UNSIGNED_SHORT: - indexSize = 2; + ibuffer.index_size = 2; + break; + case GL_UNSIGNED_BYTE: + ibuffer.index_size = 1; break; default: assert(0); @@ -224,23 +227,20 @@ st_feedback_draw_vbo(GLcontext *ctx, if (bufobj && bufobj->Name) { struct st_buffer_object *stobj = st_buffer_object(bufobj); - index_buffer_handle = stobj->buffer; - - map = pipe_buffer_map(pipe, index_buffer_handle, - PIPE_TRANSFER_READ, &ib_transfer); + pipe_resource_reference(&ibuffer.buffer, stobj->buffer); + ibuffer.offset = pointer_to_offset(ib->ptr); - draw_set_mapped_element_buffer(draw, indexSize, 0, map); + mapped_indices = pipe_buffer_map(pipe, stobj->buffer, + PIPE_TRANSFER_READ, &ib_transfer); } else { - draw_set_mapped_element_buffer(draw, indexSize, 0, (void *) ib->ptr); - ib_transfer = NULL; + /* skip setting ibuffer.buffer as the draw module does not use it */ + mapped_indices = ib->ptr; } - } - else { - /* no index/element buffer */ - draw_set_mapped_element_buffer(draw, 0, 0, NULL); - } + draw_set_index_buffer(draw, &ibuffer); + draw_set_mapped_index_buffer(draw, mapped_indices); + } /* map constant buffers */ mapped_constants = pipe_buffer_map(pipe, @@ -273,9 +273,14 @@ st_feedback_draw_vbo(GLcontext *ctx, draw_set_mapped_vertex_buffer(draw, i, NULL); } } - if (index_buffer_handle) { - pipe_buffer_unmap(pipe, index_buffer_handle, ib_transfer); - draw_set_mapped_element_buffer(draw, 0, 0, NULL); + + if (ib) { + draw_set_mapped_index_buffer(draw, NULL); + draw_set_index_buffer(draw, NULL); + + if (ib_transfer) + pipe_buffer_unmap(pipe, ibuffer.buffer, ib_transfer); + pipe_resource_reference(&ibuffer.buffer, NULL); } } diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c index 90e78679e4..6cd74db897 100644 --- a/src/mesa/state_tracker/st_extensions.c +++ b/src/mesa/state_tracker/st_extensions.c @@ -161,6 +161,13 @@ void st_init_limits(struct st_context *st) pc->MaxNativeTemps = screen->get_param(screen, PIPE_CAP_MAX_VS_TEMPS); pc->MaxNativeAddressRegs = screen->get_param(screen, PIPE_CAP_MAX_VS_ADDRS); pc->MaxNativeParameters = screen->get_param(screen, PIPE_CAP_MAX_VS_CONSTS); + + /* PIPE_CAP_MAX_FS_INPUTS specifies the number of COLORn + GENERICn inputs + * and is set in MaxNativeAttribs. It's always 2 colors + N generic + * attributes. The GLSL compiler never uses COLORn for varyings, so we + * subtract the 2 colors to get the maximum number of varyings (generic + * attributes) supported by a driver. */ + c->MaxVarying = screen->get_param(screen, PIPE_CAP_MAX_FS_INPUTS) - 2; } diff --git a/src/mesa/state_tracker/st_format.c b/src/mesa/state_tracker/st_format.c index c9fa7a62e1..1ed79524b2 100644 --- a/src/mesa/state_tracker/st_format.c +++ b/src/mesa/state_tracker/st_format.c @@ -35,7 +35,6 @@ #include "main/imports.h" #include "main/context.h" #include "main/texstore.h" -#include "main/enums.h" #include "main/image.h" #include "main/macros.h" @@ -78,7 +77,9 @@ st_format_datatype(enum pipe_format format) return GL_UNSIGNED_SHORT; } else if (format == PIPE_FORMAT_Z24_UNORM_S8_USCALED || - format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) { + format == PIPE_FORMAT_S8_USCALED_Z24_UNORM || + format == PIPE_FORMAT_Z24X8_UNORM || + format == PIPE_FORMAT_X8Z24_UNORM) { return GL_UNSIGNED_INT_24_8; } else { diff --git a/src/mesa/state_tracker/st_manager.c b/src/mesa/state_tracker/st_manager.c index 2afc682e0b..ccce574c36 100644 --- a/src/mesa/state_tracker/st_manager.c +++ b/src/mesa/state_tracker/st_manager.c @@ -42,6 +42,7 @@ #include "main/texstate.h" #include "main/texfetch.h" #include "main/framebuffer.h" +#include "main/fbobject.h" #include "main/renderbuffer.h" #include "st_texture.h" @@ -247,6 +248,9 @@ st_framebuffer_add_renderbuffer(struct st_framebuffer *stfb, int samples; boolean sw; + if (!stfb->iface) + return FALSE; + /* do not distinguish depth/stencil buffers */ if (idx == BUFFER_STENCIL) idx = BUFFER_DEPTH; @@ -299,6 +303,10 @@ st_visual_to_context_mode(const struct st_visual *visual, { memset(mode, 0, sizeof(*mode)); + /* FBO-only context */ + if (!visual) + return; + if (st_visual_have_buffers(visual, ST_ATTACHMENT_BACK_LEFT_MASK)) mode->doubleBufferMode = GL_TRUE; if (st_visual_have_buffers(visual, @@ -422,6 +430,15 @@ st_framebuffer_create(struct st_framebuffer_iface *stfbi) if (!stfb) return NULL; + /* for FBO-only context */ + if (!stfbi) { + GLframebuffer *base = _mesa_get_incomplete_framebuffer(); + + stfb->Base = *base; + + return stfb; + } + st_visual_to_context_mode(stfbi->visual, &mode); _mesa_initialize_window_framebuffer(&stfb->Base, &mode); @@ -693,10 +710,14 @@ st_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi, st_framebuffer_validate(stread, st); /* modify the draw/read buffers of the context */ - st_visual_to_default_buffer(stdraw->iface->visual, - &st->ctx->Color.DrawBuffer[0], NULL); - st_visual_to_default_buffer(stread->iface->visual, - &st->ctx->Pixel.ReadBuffer, NULL); + if (stdraw->iface) { + st_visual_to_default_buffer(stdraw->iface->visual, + &st->ctx->Color.DrawBuffer[0], NULL); + } + if (stread->iface) { + st_visual_to_default_buffer(stread->iface->visual, + &st->ctx->Pixel.ReadBuffer, NULL); + } ret = _mesa_make_current(st->ctx, &stdraw->Base, &stread->Base); } @@ -748,6 +769,8 @@ st_manager_flush_frontbuffer(struct st_context *st) if (!strb) return; + /* never a dummy fb */ + assert(stfb->iface); stfb->iface->flush_front(stfb->iface, ST_ATTACHMENT_FRONT_LEFT); } diff --git a/src/mesa/state_tracker/st_mesa_to_tgsi.c b/src/mesa/state_tracker/st_mesa_to_tgsi.c index a19dcc9253..0ed822b8c2 100644 --- a/src/mesa/state_tracker/st_mesa_to_tgsi.c +++ b/src/mesa/state_tracker/st_mesa_to_tgsi.c @@ -32,9 +32,10 @@ */ #include "pipe/p_compiler.h" +#include "pipe/p_context.h" +#include "pipe/p_screen.h" #include "pipe/p_shader_tokens.h" #include "pipe/p_state.h" -#include "pipe/p_context.h" #include "tgsi/tgsi_ureg.h" #include "st_mesa_to_tgsi.h" #include "st_context.h" diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index 91528c227b..8c2d8b6154 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -207,6 +207,9 @@ st_translate_vertex_program(struct st_context *st, enum pipe_error error; unsigned num_outputs; + _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT); + _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING); + ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); if (ureg == NULL) { FREE(vpv); @@ -298,6 +301,8 @@ st_translate_fragment_program(struct st_context *st, ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; uint fs_num_outputs = 0; + _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT); + /* * Convert Mesa program inputs to TGSI input register semantics. */ @@ -485,6 +490,9 @@ st_translate_geometry_program(struct st_context *st, GLuint maxSlot = 0; struct ureg_program *ureg; + _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT); + _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING); + ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY ); if (ureg == NULL) { return; diff --git a/src/mesa/state_tracker/st_texture.c b/src/mesa/state_tracker/st_texture.c index add6e949df..c6cf2ba061 100644 --- a/src/mesa/state_tracker/st_texture.c +++ b/src/mesa/state_tracker/st_texture.c @@ -64,7 +64,7 @@ st_texture_create(struct st_context *st, struct pipe_resource pt, *newtex; struct pipe_screen *screen = st->pipe->screen; - assert(target <= PIPE_TEXTURE_CUBE); + assert(target < PIPE_MAX_TEXTURE_TYPES); assert(width0 > 0); assert(height0 > 0); assert(depth0 > 0); diff --git a/src/mesa/swrast/s_context.c b/src/mesa/swrast/s_context.c index d8d8a80b7d..f76a2b68ec 100644 --- a/src/mesa/swrast/s_context.c +++ b/src/mesa/swrast/s_context.c @@ -950,7 +950,7 @@ _swrast_print_vertex( GLcontext *ctx, const SWvertex *v ) v->attrib[FRAG_ATTRIB_COL1][2], v->attrib[FRAG_ATTRIB_COL1][3]); _mesa_debug(ctx, "fog %f\n", v->attrib[FRAG_ATTRIB_FOGC][0]); - _mesa_debug(ctx, "index %d\n", v->attrib[FRAG_ATTRIB_CI][0]); + _mesa_debug(ctx, "index %f\n", v->attrib[FRAG_ATTRIB_CI][0]); _mesa_debug(ctx, "pointsize %f\n", v->pointSize); _mesa_debug(ctx, "\n"); } diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index c32a504443..1759e57887 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -785,7 +785,7 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, start, end, count, type, indices, ctx->Array.ArrayObj->_MaxElement - 1, ctx->Array.ElementArrayBufferObj->Name, - ctx->Array.ElementArrayBufferObj->Size); + (int) ctx->Array.ElementArrayBufferObj->Size); } if (0) @@ -811,7 +811,7 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, start, end, count, type, indices, max, ctx->Array.ArrayObj->_MaxElement - 1, ctx->Array.ElementArrayBufferObj->Name, - ctx->Array.ElementArrayBufferObj->Size); + (int) ctx->Array.ElementArrayBufferObj->Size); } } /* XXX we could also find the min index and compare to 'start' diff --git a/src/mesa/x86/3dnow.h b/src/mesa/x86/3dnow.h index df9f2638d7..1c1fedcd4f 100644 --- a/src/mesa/x86/3dnow.h +++ b/src/mesa/x86/3dnow.h @@ -31,8 +31,6 @@ #ifndef __3DNOW_H__ #define __3DNOW_H__ -#include "math/m_xform.h" - void _mesa_init_3dnow_transform_asm( void ); #endif diff --git a/src/mesa/x86/common_x86.c b/src/mesa/x86/common_x86.c index 5efdb4f24a..f763a3aa8a 100644 --- a/src/mesa/x86/common_x86.c +++ b/src/mesa/x86/common_x86.c @@ -55,7 +55,7 @@ /** Bitmask of X86_FEATURE_x bits */ int _mesa_x86_cpu_features = 0x0; - +static int detection_debug = GL_FALSE; /* No reason for this to be public. */ @@ -190,7 +190,8 @@ void _mesa_check_os_sse_support( void ) #else /* Do nothing on other platforms for now. */ - _mesa_debug(NULL, "Not testing OS support for SSE, leaving enabled.\n"); + if (detection_debug) + _mesa_debug(NULL, "Not testing OS support for SSE, leaving enabled.\n"); #endif /* __FreeBSD__ */ } @@ -232,7 +233,8 @@ _mesa_get_x86_features(void) _mesa_x86_cpuid(0, &result, (GLuint *)(cpu_vendor + 0), (GLuint *)(cpu_vendor + 8), (GLuint *)(cpu_vendor + 4)); cpu_vendor[12] = '\0'; - _mesa_debug(NULL, "CPU vendor: %s\n", cpu_vendor); + if (detection_debug) + _mesa_debug(NULL, "CPU vendor: %s\n", cpu_vendor); /* get cpu features */ cpu_features = _mesa_x86_cpuid_edx(1); @@ -284,10 +286,49 @@ _mesa_get_x86_features(void) _mesa_x86_cpuid(0x80000002+ofs, (GLuint *)(cpu_name + (16*ofs)+0), (GLuint *)(cpu_name + (16*ofs)+4), (GLuint *)(cpu_name + (16*ofs)+8), (GLuint *)(cpu_name + (16*ofs)+12)); cpu_name[48] = '\0'; /* the name should be NULL terminated, but just to be sure */ - _mesa_debug(NULL, "CPU name: %s\n", cpu_name); + if (detection_debug) + _mesa_debug(NULL, "CPU name: %s\n", cpu_name); } } } + +#ifdef USE_MMX_ASM + if ( cpu_has_mmx ) { + if ( _mesa_getenv( "MESA_NO_MMX" ) == 0 ) { + if (detection_debug) + _mesa_debug(NULL, "MMX cpu detected.\n"); + } else { + _mesa_x86_cpu_features &= ~(X86_FEATURE_MMX); + } + } +#endif + +#ifdef USE_3DNOW_ASM + if ( cpu_has_3dnow ) { + if ( _mesa_getenv( "MESA_NO_3DNOW" ) == 0 ) { + if (detection_debug) + _mesa_debug(NULL, "3DNow! cpu detected.\n"); + } else { + _mesa_x86_cpu_features &= ~(X86_FEATURE_3DNOW); + } + } +#endif + +#ifdef USE_SSE_ASM + if ( cpu_has_xmm ) { + if ( _mesa_getenv( "MESA_NO_SSE" ) == 0 ) { + if (detection_debug) + _mesa_debug(NULL, "SSE cpu detected.\n"); + if ( _mesa_getenv( "MESA_FORCE_SSE" ) == 0 ) { + _mesa_check_os_sse_support(); + } + } else { + _mesa_debug(NULL, "SSE cpu detected, but switched off by user.\n"); + _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM); + } + } +#endif + #endif /* USE_X86_ASM */ } diff --git a/src/mesa/x86/mmx.h b/src/mesa/x86/mmx.h index 5641936bdb..47a0d4b54d 100644 --- a/src/mesa/x86/mmx.h +++ b/src/mesa/x86/mmx.h @@ -26,6 +26,9 @@ #ifndef ASM_MMX_H #define ASM_MMX_H +#include "main/compiler.h" +#include "main/mtypes.h" + extern void _ASMAPI _mesa_mmx_blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[], GLvoid *rgba, const GLvoid *dest, diff --git a/src/mesa/x86/sse.h b/src/mesa/x86/sse.h index 521f91e411..e92ddc1394 100644 --- a/src/mesa/x86/sse.h +++ b/src/mesa/x86/sse.h @@ -31,8 +31,6 @@ #ifndef __SSE_H__ #define __SSE_H__ -#include "math/m_xform.h" - void _mesa_init_sse_transform_asm( void ); #endif diff --git a/src/mesa/x86/x86_xform.c b/src/mesa/x86/x86_xform.c index c834e2b468..3dcc55e16b 100644 --- a/src/mesa/x86/x86_xform.c +++ b/src/mesa/x86/x86_xform.c @@ -114,42 +114,13 @@ void _mesa_init_all_x86_transform_asm( void ) _mesa_init_x86_transform_asm(); } -#ifdef USE_MMX_ASM - if ( cpu_has_mmx ) { - if ( _mesa_getenv( "MESA_NO_MMX" ) == 0 ) { - _mesa_debug(NULL, "MMX cpu detected.\n"); - } else { - _mesa_x86_cpu_features &= ~(X86_FEATURE_MMX); - } + if (cpu_has_3dnow) { + _mesa_init_3dnow_transform_asm(); } -#endif - -#ifdef USE_3DNOW_ASM - if ( cpu_has_3dnow ) { - if ( _mesa_getenv( "MESA_NO_3DNOW" ) == 0 ) { - _mesa_debug(NULL, "3DNow! cpu detected.\n"); - _mesa_init_3dnow_transform_asm(); - } else { - _mesa_x86_cpu_features &= ~(X86_FEATURE_3DNOW); - } - } -#endif -#ifdef USE_SSE_ASM if ( cpu_has_xmm ) { - if ( _mesa_getenv( "MESA_NO_SSE" ) == 0 ) { - _mesa_debug(NULL, "SSE cpu detected.\n"); - if ( _mesa_getenv( "MESA_FORCE_SSE" ) == 0 ) { - _mesa_check_os_sse_support(); - } - if ( cpu_has_xmm ) { - _mesa_init_sse_transform_asm(); - } - } else { - _mesa_debug(NULL, "SSE cpu detected, but switched off by user.\n"); - _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM); - } + _mesa_init_sse_transform_asm(); } -#endif + #endif } diff --git a/src/talloc/SConscript b/src/talloc/SConscript new file mode 100644 index 0000000000..3bf7029bb2 --- /dev/null +++ b/src/talloc/SConscript @@ -0,0 +1,20 @@ +Import('*') + +if env['platform'] != 'windows': + Return() + +env = env.Clone() + +talloc = env.SharedLibrary( + target = 'talloc', + source = ['talloc.c', 'talloc.def'], +) + +env.InstallSharedLibrary(talloc) + +if env['platform'] == 'windows': + talloc = env.FindIxes(talloc, 'LIBPREFIX', 'LIBSUFFIX') +else: + talloc = env.FindIxes(talloc, 'SHLIBPREFIX', 'SHLIBSUFFIX') + +Export('talloc') diff --git a/src/talloc/gpl-3.0.txt b/src/talloc/gpl-3.0.txt new file mode 100644 index 0000000000..94a9ed024d --- /dev/null +++ b/src/talloc/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/src/talloc/lgpl-3.0.txt b/src/talloc/lgpl-3.0.txt new file mode 100644 index 0000000000..65c5ca88a6 --- /dev/null +++ b/src/talloc/lgpl-3.0.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/src/talloc/talloc.c b/src/talloc/talloc.c new file mode 100644 index 0000000000..cc01346a7f --- /dev/null +++ b/src/talloc/talloc.c @@ -0,0 +1,2034 @@ +/* + Samba Unix SMB/CIFS implementation. + + Samba trivial allocation library - new interface + + NOTE: Please read talloc_guide.txt for full documentation + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 2006 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + inspired by http://swapped.cc/halloc/ +*/ + +#include "talloc.h" +#include <string.h> + +#define TALLOC_MIN(a,b) ((a)<(b)?(a):(b)) + +/* Visual C++ 2008 compatibility */ +#if defined(_MSC_VER) && !defined(_cplusplus) +typedef size_t ssize_t; +#define inline __inline +#endif + +/* Xcode/gcc4.0 compatibility */ +#if defined(__APPLE__) || defined(__MINGW32__) +static size_t strnlen (const char* s, size_t n) +{ + size_t i; + for (i = 0; i < n; ++i) + { + if (s[i] == '\0') + break; + } + return i; +} +#endif + +/* Visual C++ 2008 & Xcode/gcc4.0 compatibility */ +#if !defined(_cplusplus) && (defined(WIN32) || defined(__APPLE__)) +typedef int bool; +#define false 0 +#define true 1 +#endif + + +#ifdef TALLOC_BUILD_VERSION_MAJOR +#if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR) +#error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR" +#endif +#endif + +#ifdef TALLOC_BUILD_VERSION_MINOR +#if (TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR) +#error "TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR" +#endif +#endif + +/* use this to force every realloc to change the pointer, to stress test + code that might not cope */ +#define ALWAYS_REALLOC 0 + + +#define MAX_TALLOC_SIZE 0x10000000 +#define TALLOC_MAGIC_BASE 0xe814ec70 +#define TALLOC_MAGIC ( \ + TALLOC_MAGIC_BASE + \ + (TALLOC_VERSION_MAJOR << 12) + \ + (TALLOC_VERSION_MINOR << 4) \ +) + +#define TALLOC_FLAG_FREE 0x01 +#define TALLOC_FLAG_LOOP 0x02 +#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */ +#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */ +#define TALLOC_MAGIC_REFERENCE ((const char *)1) + +/* by default we abort when given a bad pointer (such as when talloc_free() is called + on a pointer that came from malloc() */ +#ifndef TALLOC_ABORT +#define TALLOC_ABORT(reason) abort() +#endif + +#ifndef discard_const_p +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) +# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) +#else +# define discard_const_p(type, ptr) ((type *)(ptr)) +#endif +#endif + +/* these macros gain us a few percent of speed on gcc */ +#if (__GNUC__ >= 3) +/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1 + as its first argument */ +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif +#else +#ifndef likely +#define likely(x) (x) +#endif +#ifndef unlikely +#define unlikely(x) (x) +#endif +#endif + +/* this null_context is only used if talloc_enable_leak_report() or + talloc_enable_leak_report_full() is called, otherwise it remains + NULL +*/ +static void *null_context; +static void *autofree_context; + +struct talloc_reference_handle { + struct talloc_reference_handle *next, *prev; + void *ptr; + const char *location; +}; + +typedef int (*talloc_destructor_t)(void *); + +struct talloc_chunk { + struct talloc_chunk *next, *prev; + struct talloc_chunk *parent, *child; + struct talloc_reference_handle *refs; + talloc_destructor_t destructor; + const char *name; + size_t size; + unsigned flags; + + /* + * "pool" has dual use: + * + * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool" + * marks the end of the currently allocated area. + * + * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool" + * is a pointer to the struct talloc_chunk of the pool that it was + * allocated from. This way children can quickly find the pool to chew + * from. + */ + void *pool; +}; + +/* 16 byte alignment seems to keep everyone happy */ +#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15) +#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc)) + +int talloc_version_major(void) +{ + return TALLOC_VERSION_MAJOR; +} + +int talloc_version_minor(void) +{ + return TALLOC_VERSION_MINOR; +} + +static void (*talloc_log_fn)(const char *message); + +void talloc_set_log_fn(void (*log_fn)(const char *message)) +{ + talloc_log_fn = log_fn; +} + +static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); +static void talloc_log(const char *fmt, ...) +{ + va_list ap; + char *message; + + if (!talloc_log_fn) { + return; + } + + va_start(ap, fmt); + message = talloc_vasprintf(NULL, fmt, ap); + va_end(ap); + + talloc_log_fn(message); + talloc_free(message); +} + +static void talloc_log_stderr(const char *message) +{ + fprintf(stderr, "%s", message); +} + +void talloc_set_log_stderr(void) +{ + talloc_set_log_fn(talloc_log_stderr); +} + +static void (*talloc_abort_fn)(const char *reason); + +void talloc_set_abort_fn(void (*abort_fn)(const char *reason)) +{ + talloc_abort_fn = abort_fn; +} + +static void talloc_abort(const char *reason) +{ + talloc_log("%s\n", reason); + + if (!talloc_abort_fn) { + TALLOC_ABORT(reason); + } + + talloc_abort_fn(reason); +} + +static void talloc_abort_magic(unsigned magic) +{ + unsigned striped = magic - TALLOC_MAGIC_BASE; + unsigned major = (striped & 0xFFFFF000) >> 12; + unsigned minor = (striped & 0x00000FF0) >> 4; + talloc_log("Bad talloc magic[0x%08X/%u/%u] expected[0x%08X/%u/%u]\n", + magic, major, minor, + TALLOC_MAGIC, TALLOC_VERSION_MAJOR, TALLOC_VERSION_MINOR); + talloc_abort("Bad talloc magic value - wrong talloc version used/mixed"); +} + +static void talloc_abort_double_free(void) +{ + talloc_abort("Bad talloc magic value - double free"); +} + +static void talloc_abort_unknown_value(void) +{ + talloc_abort("Bad talloc magic value - unknown value"); +} + +/* panic if we get a bad magic value */ +static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) +{ + const char *pp = (const char *)ptr; + struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE); + if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { + if ((tc->flags & (~0xFFF)) == TALLOC_MAGIC_BASE) { + talloc_abort_magic(tc->flags & (~0xF)); + return NULL; + } + + if (tc->flags & TALLOC_FLAG_FREE) { + talloc_log("talloc: double free error - first free may be at %s\n", tc->name); + talloc_abort_double_free(); + return NULL; + } else { + talloc_abort_unknown_value(); + return NULL; + } + } + return tc; +} + +/* hook into the front of the list */ +#define _TLIST_ADD(list, p) \ +do { \ + if (!(list)) { \ + (list) = (p); \ + (p)->next = (p)->prev = NULL; \ + } else { \ + (list)->prev = (p); \ + (p)->next = (list); \ + (p)->prev = NULL; \ + (list) = (p); \ + }\ +} while (0) + +/* remove an element from a list - element doesn't have to be in list. */ +#define _TLIST_REMOVE(list, p) \ +do { \ + if ((p) == (list)) { \ + (list) = (p)->next; \ + if (list) (list)->prev = NULL; \ + } else { \ + if ((p)->prev) (p)->prev->next = (p)->next; \ + if ((p)->next) (p)->next->prev = (p)->prev; \ + } \ + if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \ +} while (0) + + +/* + return the parent chunk of a pointer +*/ +static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return NULL; + } + + tc = talloc_chunk_from_ptr(ptr); + while (tc->prev) tc=tc->prev; + + return tc->parent; +} + +void *talloc_parent(const void *ptr) +{ + struct talloc_chunk *tc = talloc_parent_chunk(ptr); + return tc? TC_PTR_FROM_CHUNK(tc) : NULL; +} + +/* + find parents name +*/ +const char *talloc_parent_name(const void *ptr) +{ + struct talloc_chunk *tc = talloc_parent_chunk(ptr); + return tc? tc->name : NULL; +} + +/* + A pool carries an in-pool object count count in the first 16 bytes. + bytes. This is done to support talloc_steal() to a parent outside of the + pool. The count includes the pool itself, so a talloc_free() on a pool will + only destroy the pool if the count has dropped to zero. A talloc_free() of a + pool member will reduce the count, and eventually also call free(3) on the + pool memory. + + The object count is not put into "struct talloc_chunk" because it is only + relevant for talloc pools and the alignment to 16 bytes would increase the + memory footprint of each talloc chunk by those 16 bytes. +*/ + +#define TALLOC_POOL_HDR_SIZE 16 + +static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc) +{ + return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk)); +} + +/* + Allocate from a pool +*/ + +static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, + size_t size) +{ + struct talloc_chunk *pool_ctx = NULL; + size_t space_left; + struct talloc_chunk *result; + size_t chunk_size; + + if (parent == NULL) { + return NULL; + } + + if (parent->flags & TALLOC_FLAG_POOL) { + pool_ctx = parent; + } + else if (parent->flags & TALLOC_FLAG_POOLMEM) { + pool_ctx = (struct talloc_chunk *)parent->pool; + } + + if (pool_ctx == NULL) { + return NULL; + } + + space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size) + - ((char *)pool_ctx->pool); + + /* + * Align size to 16 bytes + */ + chunk_size = ((size + 15) & ~15); + + if (space_left < chunk_size) { + return NULL; + } + + result = (struct talloc_chunk *)pool_ctx->pool; + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) + VALGRIND_MAKE_MEM_UNDEFINED(result, size); +#endif + + pool_ctx->pool = (void *)((char *)result + chunk_size); + + result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; + result->pool = pool_ctx; + + *talloc_pool_objectcount(pool_ctx) += 1; + + return result; +} + +/* + Allocate a bit of memory as a child of an existing pointer +*/ +static inline void *__talloc(const void *context, size_t size) +{ + struct talloc_chunk *tc = NULL; + + if (unlikely(context == NULL)) { + context = null_context; + } + + if (unlikely(size >= MAX_TALLOC_SIZE)) { + return NULL; + } + + if (context != NULL) { + tc = talloc_alloc_pool(talloc_chunk_from_ptr(context), + TC_HDR_SIZE+size); + } + + if (tc == NULL) { + tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); + if (unlikely(tc == NULL)) return NULL; + tc->flags = TALLOC_MAGIC; + tc->pool = NULL; + } + + tc->size = size; + tc->destructor = NULL; + tc->child = NULL; + tc->name = NULL; + tc->refs = NULL; + + if (likely(context)) { + struct talloc_chunk *parent = talloc_chunk_from_ptr(context); + + if (parent->child) { + parent->child->parent = NULL; + tc->next = parent->child; + tc->next->prev = tc; + } else { + tc->next = NULL; + } + tc->parent = parent; + tc->prev = NULL; + parent->child = tc; + } else { + tc->next = tc->prev = tc->parent = NULL; + } + + return TC_PTR_FROM_CHUNK(tc); +} + +/* + * Create a talloc pool + */ + +void *talloc_pool(const void *context, size_t size) +{ + void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE); + struct talloc_chunk *tc; + + if (unlikely(result == NULL)) { + return NULL; + } + + tc = talloc_chunk_from_ptr(result); + + tc->flags |= TALLOC_FLAG_POOL; + tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE; + + *talloc_pool_objectcount(tc) = 1; + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) + VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size); +#endif + + return result; +} + +/* + setup a destructor to be called on free of a pointer + the destructor should return 0 on success, or -1 on failure. + if the destructor fails then the free is failed, and the memory can + be continued to be used +*/ +void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + tc->destructor = destructor; +} + +/* + increase the reference count on a piece of memory. +*/ +int talloc_increase_ref_count(const void *ptr) +{ + if (unlikely(!talloc_reference(null_context, ptr))) { + return -1; + } + return 0; +} + +/* + helper for talloc_reference() + + this is referenced by a function pointer and should not be inline +*/ +static int talloc_reference_destructor(struct talloc_reference_handle *handle) +{ + struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr); + _TLIST_REMOVE(ptr_tc->refs, handle); + return 0; +} + +/* + more efficient way to add a name to a pointer - the name must point to a + true string constant +*/ +static inline void _talloc_set_name_const(const void *ptr, const char *name) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + tc->name = name; +} + +/* + internal talloc_named_const() +*/ +static inline void *_talloc_named_const(const void *context, size_t size, const char *name) +{ + void *ptr; + + ptr = __talloc(context, size); + if (unlikely(ptr == NULL)) { + return NULL; + } + + _talloc_set_name_const(ptr, name); + + return ptr; +} + +/* + make a secondary reference to a pointer, hanging off the given context. + the pointer remains valid until both the original caller and this given + context are freed. + + the major use for this is when two different structures need to reference the + same underlying data, and you want to be able to free the two instances separately, + and in either order +*/ +void *_talloc_reference_loc(const void *context, const void *ptr, const char *location) +{ + struct talloc_chunk *tc; + struct talloc_reference_handle *handle; + if (unlikely(ptr == NULL)) return NULL; + + tc = talloc_chunk_from_ptr(ptr); + handle = (struct talloc_reference_handle *)_talloc_named_const(context, + sizeof(struct talloc_reference_handle), + TALLOC_MAGIC_REFERENCE); + if (unlikely(handle == NULL)) return NULL; + + /* note that we hang the destructor off the handle, not the + main context as that allows the caller to still setup their + own destructor on the context if they want to */ + talloc_set_destructor(handle, talloc_reference_destructor); + handle->ptr = discard_const_p(void, ptr); + handle->location = location; + _TLIST_ADD(tc->refs, handle); + return handle->ptr; +} + +static void *_talloc_steal_internal(const void *new_ctx, const void *ptr); + +/* + internal talloc_free call +*/ +static inline int _talloc_free_internal(void *ptr, const char *location) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return -1; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (unlikely(tc->refs)) { + int is_child; + /* check this is a reference from a child or grantchild + * back to it's parent or grantparent + * + * in that case we need to remove the reference and + * call another instance of talloc_free() on the current + * pointer. + */ + is_child = talloc_is_parent(tc->refs, ptr); + _talloc_free_internal(tc->refs, location); + if (is_child) { + return _talloc_free_internal(ptr, location); + } + return -1; + } + + if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) { + /* we have a free loop - stop looping */ + return 0; + } + + if (unlikely(tc->destructor)) { + talloc_destructor_t d = tc->destructor; + if (d == (talloc_destructor_t)-1) { + return -1; + } + tc->destructor = (talloc_destructor_t)-1; + if (d(ptr) == -1) { + tc->destructor = d; + return -1; + } + tc->destructor = NULL; + } + + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->flags |= TALLOC_FLAG_LOOP; + + while (tc->child) { + /* we need to work out who will own an abandoned child + if it cannot be freed. In priority order, the first + choice is owner of any remaining reference to this + pointer, the second choice is our parent, and the + final choice is the null context. */ + void *child = TC_PTR_FROM_CHUNK(tc->child); + const void *new_parent = null_context; + if (unlikely(tc->child->refs)) { + struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + if (unlikely(_talloc_free_internal(child, location) == -1)) { + if (new_parent == null_context) { + struct talloc_chunk *p = talloc_parent_chunk(ptr); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + _talloc_steal_internal(new_parent, child); + } + } + + tc->flags |= TALLOC_FLAG_FREE; + + /* we mark the freed memory with where we called the free + * from. This means on a double free error we can report where + * the first free came from + */ + tc->name = location; + + if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) { + struct talloc_chunk *pool; + unsigned int *pool_object_count; + + pool = (tc->flags & TALLOC_FLAG_POOL) + ? tc : (struct talloc_chunk *)tc->pool; + + pool_object_count = talloc_pool_objectcount(pool); + + if (*pool_object_count == 0) { + talloc_abort("Pool object count zero!"); + return 0; + } + + *pool_object_count -= 1; + + if (*pool_object_count == 0) { + free(pool); + } + } + else { + free(tc); + } + return 0; +} + +/* + move a lump of memory from one talloc context to another return the + ptr on success, or NULL if it could not be transferred. + passing NULL as ptr will always return NULL with no side effects. +*/ +static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) +{ + struct talloc_chunk *tc, *new_tc; + + if (unlikely(!ptr)) { + return NULL; + } + + if (unlikely(new_ctx == NULL)) { + new_ctx = null_context; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (unlikely(new_ctx == NULL)) { + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->parent = tc->next = tc->prev = NULL; + return discard_const_p(void, ptr); + } + + new_tc = talloc_chunk_from_ptr(new_ctx); + + if (unlikely(tc == new_tc || tc->parent == new_tc)) { + return discard_const_p(void, ptr); + } + + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->parent = new_tc; + if (new_tc->child) new_tc->child->parent = NULL; + _TLIST_ADD(new_tc->child, tc); + + return discard_const_p(void, ptr); +} + +/* + move a lump of memory from one talloc context to another return the + ptr on success, or NULL if it could not be transferred. + passing NULL as ptr will always return NULL with no side effects. +*/ +void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *location) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return NULL; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) { + struct talloc_reference_handle *h; + + talloc_log("WARNING: talloc_steal with references at %s\n", + location); + + for (h=tc->refs; h; h=h->next) { + talloc_log("\treference at %s\n", + h->location); + } + } + + return _talloc_steal_internal(new_ctx, ptr); +} + +/* + this is like a talloc_steal(), but you must supply the old + parent. This resolves the ambiguity in a talloc_steal() which is + called on a context that has more than one parent (via references) + + The old parent can be either a reference or a parent +*/ +void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr) +{ + struct talloc_chunk *tc; + struct talloc_reference_handle *h; + + if (unlikely(ptr == NULL)) { + return NULL; + } + + if (old_parent == talloc_parent(ptr)) { + return _talloc_steal_internal(new_parent, ptr); + } + + tc = talloc_chunk_from_ptr(ptr); + for (h=tc->refs;h;h=h->next) { + if (talloc_parent(h) == old_parent) { + if (_talloc_steal_internal(new_parent, h) != h) { + return NULL; + } + return discard_const_p(void, ptr); + } + } + + /* it wasn't a parent */ + return NULL; +} + +/* + remove a secondary reference to a pointer. This undo's what + talloc_reference() has done. The context and pointer arguments + must match those given to a talloc_reference() +*/ +static inline int talloc_unreference(const void *context, const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + struct talloc_reference_handle *h; + + if (unlikely(context == NULL)) { + context = null_context; + } + + for (h=tc->refs;h;h=h->next) { + struct talloc_chunk *p = talloc_parent_chunk(h); + if (p == NULL) { + if (context == NULL) break; + } else if (TC_PTR_FROM_CHUNK(p) == context) { + break; + } + } + if (h == NULL) { + return -1; + } + + return _talloc_free_internal(h, __location__); +} + +/* + remove a specific parent context from a pointer. This is a more + controlled varient of talloc_free() +*/ +int talloc_unlink(const void *context, void *ptr) +{ + struct talloc_chunk *tc_p, *new_p; + void *new_parent; + + if (ptr == NULL) { + return -1; + } + + if (context == NULL) { + context = null_context; + } + + if (talloc_unreference(context, ptr) == 0) { + return 0; + } + + if (context == NULL) { + if (talloc_parent_chunk(ptr) != NULL) { + return -1; + } + } else { + if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) { + return -1; + } + } + + tc_p = talloc_chunk_from_ptr(ptr); + + if (tc_p->refs == NULL) { + return _talloc_free_internal(ptr, __location__); + } + + new_p = talloc_parent_chunk(tc_p->refs); + if (new_p) { + new_parent = TC_PTR_FROM_CHUNK(new_p); + } else { + new_parent = NULL; + } + + if (talloc_unreference(new_parent, ptr) != 0) { + return -1; + } + + _talloc_steal_internal(new_parent, ptr); + + return 0; +} + +/* + add a name to an existing pointer - va_list version +*/ +static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); + +static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + tc->name = talloc_vasprintf(ptr, fmt, ap); + if (likely(tc->name)) { + _talloc_set_name_const(tc->name, ".name"); + } + return tc->name; +} + +/* + add a name to an existing pointer +*/ +const char *talloc_set_name(const void *ptr, const char *fmt, ...) +{ + const char *name; + va_list ap; + va_start(ap, fmt); + name = talloc_set_name_v(ptr, fmt, ap); + va_end(ap); + return name; +} + + +/* + create a named talloc pointer. Any talloc pointer can be named, and + talloc_named() operates just like talloc() except that it allows you + to name the pointer. +*/ +void *talloc_named(const void *context, size_t size, const char *fmt, ...) +{ + va_list ap; + void *ptr; + const char *name; + + ptr = __talloc(context, size); + if (unlikely(ptr == NULL)) return NULL; + + va_start(ap, fmt); + name = talloc_set_name_v(ptr, fmt, ap); + va_end(ap); + + if (unlikely(name == NULL)) { + _talloc_free_internal(ptr, __location__); + return NULL; + } + + return ptr; +} + +/* + return the name of a talloc ptr, or "UNNAMED" +*/ +const char *talloc_get_name(const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) { + return ".reference"; + } + if (likely(tc->name)) { + return tc->name; + } + return "UNNAMED"; +} + + +/* + check if a pointer has the given name. If it does, return the pointer, + otherwise return NULL +*/ +void *talloc_check_name(const void *ptr, const char *name) +{ + const char *pname; + if (unlikely(ptr == NULL)) return NULL; + pname = talloc_get_name(ptr); + if (likely(pname == name || strcmp(pname, name) == 0)) { + return discard_const_p(void, ptr); + } + return NULL; +} + +static void talloc_abort_type_missmatch(const char *location, + const char *name, + const char *expected) +{ + const char *reason; + + reason = talloc_asprintf(NULL, + "%s: Type mismatch: name[%s] expected[%s]", + location, + name?name:"NULL", + expected); + if (!reason) { + reason = "Type mismatch"; + } + + talloc_abort(reason); +} + +void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location) +{ + const char *pname; + + if (unlikely(ptr == NULL)) { + talloc_abort_type_missmatch(location, NULL, name); + return NULL; + } + + pname = talloc_get_name(ptr); + if (likely(pname == name || strcmp(pname, name) == 0)) { + return discard_const_p(void, ptr); + } + + talloc_abort_type_missmatch(location, pname, name); + return NULL; +} + +/* + this is for compatibility with older versions of talloc +*/ +void *talloc_init(const char *fmt, ...) +{ + va_list ap; + void *ptr; + const char *name; + + /* + * samba3 expects talloc_report_depth_cb(NULL, ...) + * reports all talloc'ed memory, so we need to enable + * null_tracking + */ + talloc_enable_null_tracking(); + + ptr = __talloc(NULL, 0); + if (unlikely(ptr == NULL)) return NULL; + + va_start(ap, fmt); + name = talloc_set_name_v(ptr, fmt, ap); + va_end(ap); + + if (unlikely(name == NULL)) { + _talloc_free_internal(ptr, __location__); + return NULL; + } + + return ptr; +} + +/* + this is a replacement for the Samba3 talloc_destroy_pool functionality. It + should probably not be used in new code. It's in here to keep the talloc + code consistent across Samba 3 and 4. +*/ +void talloc_free_children(void *ptr) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return; + } + + tc = talloc_chunk_from_ptr(ptr); + + while (tc->child) { + /* we need to work out who will own an abandoned child + if it cannot be freed. In priority order, the first + choice is owner of any remaining reference to this + pointer, the second choice is our parent, and the + final choice is the null context. */ + void *child = TC_PTR_FROM_CHUNK(tc->child); + const void *new_parent = null_context; + if (unlikely(tc->child->refs)) { + struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + if (unlikely(talloc_free(child) == -1)) { + if (new_parent == null_context) { + struct talloc_chunk *p = talloc_parent_chunk(ptr); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + _talloc_steal_internal(new_parent, child); + } + } + + if ((tc->flags & TALLOC_FLAG_POOL) + && (*talloc_pool_objectcount(tc) == 1)) { + tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE); +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) + VALGRIND_MAKE_MEM_NOACCESS( + tc->pool, tc->size - TALLOC_POOL_HDR_SIZE); +#endif + } +} + +/* + Allocate a bit of memory as a child of an existing pointer +*/ +void *_talloc(const void *context, size_t size) +{ + return __talloc(context, size); +} + +/* + externally callable talloc_set_name_const() +*/ +void talloc_set_name_const(const void *ptr, const char *name) +{ + _talloc_set_name_const(ptr, name); +} + +/* + create a named talloc pointer. Any talloc pointer can be named, and + talloc_named() operates just like talloc() except that it allows you + to name the pointer. +*/ +void *talloc_named_const(const void *context, size_t size, const char *name) +{ + return _talloc_named_const(context, size, name); +} + +/* + free a talloc pointer. This also frees all child pointers of this + pointer recursively + + return 0 if the memory is actually freed, otherwise -1. The memory + will not be freed if the ref_count is > 1 or the destructor (if + any) returns non-zero +*/ +int _talloc_free(void *ptr, const char *location) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return -1; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (unlikely(tc->refs != NULL)) { + struct talloc_reference_handle *h; + + talloc_log("ERROR: talloc_free with references at %s\n", + location); + + for (h=tc->refs; h; h=h->next) { + talloc_log("\treference at %s\n", + h->location); + } + return -1; + } + + return _talloc_free_internal(ptr, location); +} + + + +/* + A talloc version of realloc. The context argument is only used if + ptr is NULL +*/ +void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name) +{ + struct talloc_chunk *tc; + void *new_ptr; + bool malloced = false; + + /* size zero is equivalent to free() */ + if (unlikely(size == 0)) { + talloc_unlink(context, ptr); + return NULL; + } + + if (unlikely(size >= MAX_TALLOC_SIZE)) { + return NULL; + } + + /* realloc(NULL) is equivalent to malloc() */ + if (ptr == NULL) { + return _talloc_named_const(context, size, name); + } + + tc = talloc_chunk_from_ptr(ptr); + + /* don't allow realloc on referenced pointers */ + if (unlikely(tc->refs)) { + return NULL; + } + + /* don't let anybody try to realloc a talloc_pool */ + if (unlikely(tc->flags & TALLOC_FLAG_POOL)) { + return NULL; + } + + /* don't shrink if we have less than 1k to gain */ + if ((size < tc->size) && ((tc->size - size) < 1024)) { + tc->size = size; + return ptr; + } + + /* by resetting magic we catch users of the old memory */ + tc->flags |= TALLOC_FLAG_FREE; + +#if ALWAYS_REALLOC + new_ptr = malloc(size + TC_HDR_SIZE); + if (new_ptr) { + memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE); + free(tc); + } +#else + if (tc->flags & TALLOC_FLAG_POOLMEM) { + + new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE); + *talloc_pool_objectcount((struct talloc_chunk *) + (tc->pool)) -= 1; + + if (new_ptr == NULL) { + new_ptr = malloc(TC_HDR_SIZE+size); + malloced = true; + } + + if (new_ptr) { + memcpy(new_ptr, tc, TALLOC_MIN(tc->size,size) + TC_HDR_SIZE); + } + } + else { + new_ptr = realloc(tc, size + TC_HDR_SIZE); + } +#endif + if (unlikely(!new_ptr)) { + tc->flags &= ~TALLOC_FLAG_FREE; + return NULL; + } + + tc = (struct talloc_chunk *)new_ptr; + tc->flags &= ~TALLOC_FLAG_FREE; + if (malloced) { + tc->flags &= ~TALLOC_FLAG_POOLMEM; + } + if (tc->parent) { + tc->parent->child = tc; + } + if (tc->child) { + tc->child->parent = tc; + } + + if (tc->prev) { + tc->prev->next = tc; + } + if (tc->next) { + tc->next->prev = tc; + } + + tc->size = size; + _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); + + return TC_PTR_FROM_CHUNK(tc); +} + +/* + a wrapper around talloc_steal() for situations where you are moving a pointer + between two structures, and want the old pointer to be set to NULL +*/ +void *_talloc_move(const void *new_ctx, const void *_pptr) +{ + const void **pptr = discard_const_p(const void *,_pptr); + void *ret = talloc_steal(new_ctx, discard_const_p(void, *pptr)); + (*pptr) = NULL; + return ret; +} + +/* + return the total size of a talloc pool (subtree) +*/ +size_t talloc_total_size(const void *ptr) +{ + size_t total = 0; + struct talloc_chunk *c, *tc; + + if (ptr == NULL) { + ptr = null_context; + } + if (ptr == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (tc->flags & TALLOC_FLAG_LOOP) { + return 0; + } + + tc->flags |= TALLOC_FLAG_LOOP; + + if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { + total = tc->size; + } + for (c=tc->child;c;c=c->next) { + total += talloc_total_size(TC_PTR_FROM_CHUNK(c)); + } + + tc->flags &= ~TALLOC_FLAG_LOOP; + + return total; +} + +/* + return the total number of blocks in a talloc pool (subtree) +*/ +size_t talloc_total_blocks(const void *ptr) +{ + size_t total = 0; + struct talloc_chunk *c, *tc; + + if (ptr == NULL) { + ptr = null_context; + } + if (ptr == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (tc->flags & TALLOC_FLAG_LOOP) { + return 0; + } + + tc->flags |= TALLOC_FLAG_LOOP; + + total++; + for (c=tc->child;c;c=c->next) { + total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c)); + } + + tc->flags &= ~TALLOC_FLAG_LOOP; + + return total; +} + +/* + return the number of external references to a pointer +*/ +size_t talloc_reference_count(const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + struct talloc_reference_handle *h; + size_t ret = 0; + + for (h=tc->refs;h;h=h->next) { + ret++; + } + return ret; +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, + void (*callback)(const void *ptr, + int depth, int max_depth, + int is_ref, + void *private_data), + void *private_data) +{ + struct talloc_chunk *c, *tc; + + if (ptr == NULL) { + ptr = null_context; + } + if (ptr == NULL) return; + + tc = talloc_chunk_from_ptr(ptr); + + if (tc->flags & TALLOC_FLAG_LOOP) { + return; + } + + callback(ptr, depth, max_depth, 0, private_data); + + if (max_depth >= 0 && depth >= max_depth) { + return; + } + + tc->flags |= TALLOC_FLAG_LOOP; + for (c=tc->child;c;c=c->next) { + if (c->name == TALLOC_MAGIC_REFERENCE) { + struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c); + callback(h->ptr, depth + 1, max_depth, 1, private_data); + } else { + talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data); + } + } + tc->flags &= ~TALLOC_FLAG_LOOP; +} + +static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f) +{ + const char *name = talloc_get_name(ptr); + FILE *f = (FILE *)_f; + + if (is_ref) { + fprintf(f, "%*sreference to: %s\n", depth*4, "", name); + return; + } + + if (depth == 0) { + fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", + (max_depth < 0 ? "full " :""), name, + (unsigned long)talloc_total_size(ptr), + (unsigned long)talloc_total_blocks(ptr)); + return; + } + + fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", + depth*4, "", + name, + (unsigned long)talloc_total_size(ptr), + (unsigned long)talloc_total_blocks(ptr), + (int)talloc_reference_count(ptr), ptr); + +#if 0 + fprintf(f, "content: "); + if (talloc_total_size(ptr)) { + int tot = talloc_total_size(ptr); + int i; + + for (i = 0; i < tot; i++) { + if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) { + fprintf(f, "%c", ((char *)ptr)[i]); + } else { + fprintf(f, "~%02x", ((char *)ptr)[i]); + } + } + } + fprintf(f, "\n"); +#endif +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f) +{ + if (f) { + talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f); + fflush(f); + } +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +void talloc_report_full(const void *ptr, FILE *f) +{ + talloc_report_depth_file(ptr, 0, -1, f); +} + +/* + report on memory usage by all children of a pointer +*/ +void talloc_report(const void *ptr, FILE *f) +{ + talloc_report_depth_file(ptr, 0, 1, f); +} + +/* + report on any memory hanging off the null context +*/ +static void talloc_report_null(void) +{ + if (talloc_total_size(null_context) != 0) { + talloc_report(null_context, stderr); + } +} + +/* + report on any memory hanging off the null context +*/ +static void talloc_report_null_full(void) +{ + if (talloc_total_size(null_context) != 0) { + talloc_report_full(null_context, stderr); + } +} + +/* + enable tracking of the NULL context +*/ +void talloc_enable_null_tracking(void) +{ + if (null_context == NULL) { + null_context = _talloc_named_const(NULL, 0, "null_context"); + if (autofree_context != NULL) { + talloc_reparent(NULL, null_context, autofree_context); + } + } +} + +/* + enable tracking of the NULL context, not moving the autofree context + into the NULL context. This is needed for the talloc testsuite +*/ +void talloc_enable_null_tracking_no_autofree(void) +{ + if (null_context == NULL) { + null_context = _talloc_named_const(NULL, 0, "null_context"); + } +} + +/* + disable tracking of the NULL context +*/ +void talloc_disable_null_tracking(void) +{ + if (null_context != NULL) { + /* we have to move any children onto the real NULL + context */ + struct talloc_chunk *tc, *tc2; + tc = talloc_chunk_from_ptr(null_context); + for (tc2 = tc->child; tc2; tc2=tc2->next) { + if (tc2->parent == tc) tc2->parent = NULL; + if (tc2->prev == tc) tc2->prev = NULL; + } + for (tc2 = tc->next; tc2; tc2=tc2->next) { + if (tc2->parent == tc) tc2->parent = NULL; + if (tc2->prev == tc) tc2->prev = NULL; + } + tc->child = NULL; + tc->next = NULL; + } + talloc_free(null_context); + null_context = NULL; +} + +/* + enable leak reporting on exit +*/ +void talloc_enable_leak_report(void) +{ + talloc_enable_null_tracking(); + atexit(talloc_report_null); +} + +/* + enable full leak reporting on exit +*/ +void talloc_enable_leak_report_full(void) +{ + talloc_enable_null_tracking(); + atexit(talloc_report_null_full); +} + +/* + talloc and zero memory. +*/ +void *_talloc_zero(const void *ctx, size_t size, const char *name) +{ + void *p = _talloc_named_const(ctx, size, name); + + if (p) { + memset(p, '\0', size); + } + + return p; +} + +/* + memdup with a talloc. +*/ +void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) +{ + void *newp = _talloc_named_const(t, size, name); + + if (likely(newp)) { + memcpy(newp, p, size); + } + + return newp; +} + +static inline char *__talloc_strlendup(const void *t, const char *p, size_t len) +{ + char *ret; + + ret = (char *)__talloc(t, len + 1); + if (unlikely(!ret)) return NULL; + + memcpy(ret, p, len); + ret[len] = 0; + + _talloc_set_name_const(ret, ret); + return ret; +} + +/* + strdup with a talloc +*/ +char *talloc_strdup(const void *t, const char *p) +{ + if (unlikely(!p)) return NULL; + return __talloc_strlendup(t, p, strlen(p)); +} + +/* + strndup with a talloc +*/ +char *talloc_strndup(const void *t, const char *p, size_t n) +{ + if (unlikely(!p)) return NULL; + return __talloc_strlendup(t, p, strnlen(p, n)); +} + +static inline char *__talloc_strlendup_append(char *s, size_t slen, + const char *a, size_t alen) +{ + char *ret; + + ret = talloc_realloc(NULL, s, char, slen + alen + 1); + if (unlikely(!ret)) return NULL; + + /* append the string and the trailing \0 */ + memcpy(&ret[slen], a, alen); + ret[slen+alen] = 0; + + _talloc_set_name_const(ret, ret); + return ret; +} + +/* + * Appends at the end of the string. + */ +char *talloc_strdup_append(char *s, const char *a) +{ + if (unlikely(!s)) { + return talloc_strdup(NULL, a); + } + + if (unlikely(!a)) { + return s; + } + + return __talloc_strlendup_append(s, strlen(s), a, strlen(a)); +} + +/* + * Appends at the end of the talloc'ed buffer, + * not the end of the string. + */ +char *talloc_strdup_append_buffer(char *s, const char *a) +{ + size_t slen; + + if (unlikely(!s)) { + return talloc_strdup(NULL, a); + } + + if (unlikely(!a)) { + return s; + } + + slen = talloc_get_size(s); + if (likely(slen > 0)) { + slen--; + } + + return __talloc_strlendup_append(s, slen, a, strlen(a)); +} + +/* + * Appends at the end of the string. + */ +char *talloc_strndup_append(char *s, const char *a, size_t n) +{ + if (unlikely(!s)) { + return talloc_strdup(NULL, a); + } + + if (unlikely(!a)) { + return s; + } + + return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n)); +} + +/* + * Appends at the end of the talloc'ed buffer, + * not the end of the string. + */ +char *talloc_strndup_append_buffer(char *s, const char *a, size_t n) +{ + size_t slen; + + if (unlikely(!s)) { + return talloc_strdup(NULL, a); + } + + if (unlikely(!a)) { + return s; + } + + slen = talloc_get_size(s); + if (likely(slen > 0)) { + slen--; + } + + return __talloc_strlendup_append(s, slen, a, strnlen(a, n)); +} + +#ifndef va_copy +#ifdef HAVE___VA_COPY +#define va_copy(dest, src) __va_copy(dest, src) +#else +#define va_copy(dest, src) (dest) = (src) +#endif +#endif + +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) +{ + int len; + char *ret; + va_list ap2; + char c; + + /* this call looks strange, but it makes it work on older solaris boxes */ + va_copy(ap2, ap); + #ifdef _MSC_VER + /* MSVC runtime needs to use _vcsprintf to return buffer size; vsnprintf would return -1 */ + len = _vscprintf(fmt, ap2); + #else + len = vsnprintf(&c, 1, fmt, ap2); + #endif + va_end(ap2); + if (unlikely(len < 0)) { + return NULL; + } + + ret = (char *)__talloc(t, len+1); + if (unlikely(!ret)) return NULL; + + va_copy(ap2, ap); + vsnprintf(ret, len+1, fmt, ap2); + va_end(ap2); + + _talloc_set_name_const(ret, ret); + return ret; +} + + +/* + Perform string formatting, and return a pointer to newly allocated + memory holding the result, inside a memory pool. + */ +char *talloc_asprintf(const void *t, const char *fmt, ...) +{ + va_list ap; + char *ret; + + va_start(ap, fmt); + ret = talloc_vasprintf(t, fmt, ap); + va_end(ap); + return ret; +} + +static inline char *__talloc_vaslenprintf_append(char *s, size_t slen, + const char *fmt, va_list ap) + PRINTF_ATTRIBUTE(3,0); + +static inline char *__talloc_vaslenprintf_append(char *s, size_t slen, + const char *fmt, va_list ap) +{ + ssize_t alen; + va_list ap2; + char c; + + va_copy(ap2, ap); + #ifdef _MSC_VER + /* MSVC runtime needs to use _vcsprintf to return buffer size; vsnprintf would return -1 */ + alen = _vscprintf(fmt, ap2); + #else + alen = vsnprintf(&c, 1, fmt, ap2); + #endif + va_end(ap2); + + if (alen <= 0) { + /* Either the vsnprintf failed or the format resulted in + * no characters being formatted. In the former case, we + * ought to return NULL, in the latter we ought to return + * the original string. Most current callers of this + * function expect it to never return NULL. + */ + return s; + } + + s = talloc_realloc(NULL, s, char, slen + alen + 1); + if (!s) return NULL; + + va_copy(ap2, ap); + vsnprintf(s + slen, alen + 1, fmt, ap2); + va_end(ap2); + + _talloc_set_name_const(s, s); + return s; +} + +/** + * Realloc @p s to append the formatted result of @p fmt and @p ap, + * and return @p s, which may have moved. Good for gradually + * accumulating output into a string buffer. Appends at the end + * of the string. + **/ +char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) +{ + if (unlikely(!s)) { + return talloc_vasprintf(NULL, fmt, ap); + } + + return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap); +} + +/** + * Realloc @p s to append the formatted result of @p fmt and @p ap, + * and return @p s, which may have moved. Always appends at the + * end of the talloc'ed buffer, not the end of the string. + **/ +char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) +{ + size_t slen; + + if (unlikely(!s)) { + return talloc_vasprintf(NULL, fmt, ap); + } + + slen = talloc_get_size(s); + if (likely(slen > 0)) { + slen--; + } + + return __talloc_vaslenprintf_append(s, slen, fmt, ap); +} + +/* + Realloc @p s to append the formatted result of @p fmt and return @p + s, which may have moved. Good for gradually accumulating output + into a string buffer. + */ +char *talloc_asprintf_append(char *s, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + s = talloc_vasprintf_append(s, fmt, ap); + va_end(ap); + return s; +} + +/* + Realloc @p s to append the formatted result of @p fmt and return @p + s, which may have moved. Good for gradually accumulating output + into a buffer. + */ +char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + s = talloc_vasprintf_append_buffer(s, fmt, ap); + va_end(ap); + return s; +} + +/* + alloc an array, checking for integer overflow in the array size +*/ +void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + return _talloc_named_const(ctx, el_size * count, name); +} + +/* + alloc an zero array, checking for integer overflow in the array size +*/ +void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + return _talloc_zero(ctx, el_size * count, name); +} + +/* + realloc an array, checking for integer overflow in the array size +*/ +void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + return _talloc_realloc(ctx, ptr, el_size * count, name); +} + +/* + a function version of talloc_realloc(), so it can be passed as a function pointer + to libraries that want a realloc function (a realloc function encapsulates + all the basic capabilities of an allocation library, which is why this is useful) +*/ +void *talloc_realloc_fn(const void *context, void *ptr, size_t size) +{ + return _talloc_realloc(context, ptr, size, NULL); +} + + +static int talloc_autofree_destructor(void *ptr) +{ + autofree_context = NULL; + return 0; +} + +static void talloc_autofree(void) +{ + talloc_free(autofree_context); +} + +/* + return a context which will be auto-freed on exit + this is useful for reducing the noise in leak reports +*/ +void *talloc_autofree_context(void) +{ + if (autofree_context == NULL) { + autofree_context = _talloc_named_const(NULL, 0, "autofree_context"); + talloc_set_destructor(autofree_context, talloc_autofree_destructor); + atexit(talloc_autofree); + } + return autofree_context; +} + +size_t talloc_get_size(const void *context) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + context = null_context; + } + if (context == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(context); + + return tc->size; +} + +/* + find a parent of this context that has the given name, if any +*/ +void *talloc_find_parent_byname(const void *context, const char *name) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + return NULL; + } + + tc = talloc_chunk_from_ptr(context); + while (tc) { + if (tc->name && strcmp(tc->name, name) == 0) { + return TC_PTR_FROM_CHUNK(tc); + } + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + } + return NULL; +} + +/* + show the parentage of a context +*/ +void talloc_show_parents(const void *context, FILE *file) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + fprintf(file, "talloc no parents for NULL\n"); + return; + } + + tc = talloc_chunk_from_ptr(context); + fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context)); + while (tc) { + fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc))); + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + } + fflush(file); +} + +/* + return 1 if ptr is a parent of context +*/ +int talloc_is_parent(const void *context, const void *ptr) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(context); + while (tc) { + if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1; + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + } + return 0; +} diff --git a/src/talloc/talloc.def b/src/talloc/talloc.def new file mode 100644 index 0000000000..13d7a159ce --- /dev/null +++ b/src/talloc/talloc.def @@ -0,0 +1,63 @@ +EXPORTS + _talloc + _talloc_array + _talloc_free + _talloc_get_type_abort + _talloc_memdup + _talloc_move + _talloc_realloc + _talloc_realloc_array + _talloc_reference_loc + _talloc_set_destructor + _talloc_steal_loc + _talloc_zero + _talloc_zero_array + talloc_asprintf + talloc_asprintf_append + talloc_asprintf_append_buffer + talloc_autofree_context + talloc_check_name + talloc_disable_null_tracking + talloc_enable_leak_report + talloc_enable_leak_report_full + talloc_enable_null_tracking + talloc_enable_null_tracking_no_autofree + talloc_find_parent_byname + talloc_free_children + talloc_get_name + talloc_get_size + talloc_increase_ref_count + talloc_init + talloc_is_parent + talloc_named + talloc_named_const + talloc_parent + talloc_parent_name + talloc_pool + talloc_realloc_fn + talloc_reference_count + talloc_reparent + talloc_report + talloc_report_depth_cb + talloc_report_depth_file + talloc_report_full + talloc_set_abort_fn + talloc_set_log_fn + talloc_set_log_stderr + talloc_set_name + talloc_set_name_const + talloc_show_parents + talloc_strdup + talloc_strdup_append + talloc_strdup_append_buffer + talloc_strndup + talloc_strndup_append + talloc_strndup_append_buffer + talloc_total_blocks + talloc_total_size + talloc_unlink + talloc_vasprintf + talloc_vasprintf_append + talloc_vasprintf_append_buffer + talloc_version_major + talloc_version_minor diff --git a/src/talloc/talloc.h b/src/talloc/talloc.h new file mode 100644 index 0000000000..f549a17fba --- /dev/null +++ b/src/talloc/talloc.h @@ -0,0 +1,202 @@ +#ifndef _TALLOC_H_ +#define _TALLOC_H_ +/* + Unix SMB/CIFS implementation. + Samba temporary memory allocation functions + + Copyright (C) Andrew Tridgell 2004-2005 + Copyright (C) Stefan Metzmacher 2006 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> + +#define TALLOC_VERSION_MAJOR 2 +#define TALLOC_VERSION_MINOR 0 + +int talloc_version_major(void); +int talloc_version_minor(void); + +/* this is only needed for compatibility with the old talloc */ +typedef void TALLOC_CTX; + +/* + this uses a little trick to allow __LINE__ to be stringified +*/ +#ifndef __location__ +#define __TALLOC_STRING_LINE1__(s) #s +#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s) +#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__) +#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__ +#endif + +#ifndef TALLOC_DEPRECATED +#define TALLOC_DEPRECATED 0 +#endif + +#ifndef PRINTF_ATTRIBUTE +#if (__GNUC__ >= 3) +/** Use gcc attribute to check printf fns. a1 is the 1-based index of + * the parameter containing the format, and a2 the index of the first + * argument. Note that some gcc 2.x versions don't handle this + * properly **/ +#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) +#else +#define PRINTF_ATTRIBUTE(a1, a2) +#endif +#endif + +/* try to make talloc_set_destructor() and talloc_steal() type safe, + if we have a recent gcc */ +#if (__GNUC__ >= 3) +#define _TALLOC_TYPEOF(ptr) __typeof__(ptr) +#define talloc_set_destructor(ptr, function) \ + do { \ + int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function); \ + _talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \ + } while(0) +/* this extremely strange macro is to avoid some braindamaged warning + stupidity in gcc 4.1.x */ +#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal_loc((ctx),(ptr), __location__); __talloc_steal_ret; }) +#else +#define talloc_set_destructor(ptr, function) \ + _talloc_set_destructor((ptr), (int (*)(void *))(function)) +#define _TALLOC_TYPEOF(ptr) void * +#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal_loc((ctx),(ptr), __location__) +#endif + +#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference_loc((ctx),(ptr), __location__) +#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr)) + +/* useful macros for creating type checked pointers */ +#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type) +#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__) +#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr))) + +#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__) + +#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type) +#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__) + +#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type) +#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type) +#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__) +#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count) +#define talloc_array_length(ctx) (talloc_get_size(ctx)/sizeof(*ctx)) + +#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type) +#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__) + +#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__) + +#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type) +#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type) +#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__) + +#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type) +#define talloc_free(ctx) _talloc_free(ctx, __location__) + + +#if TALLOC_DEPRECATED +#define talloc_zero_p(ctx, type) talloc_zero(ctx, type) +#define talloc_p(ctx, type) talloc(ctx, type) +#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count) +#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count) +#define talloc_destroy(ctx) talloc_free(ctx) +#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a)) +#endif + +#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0) + +/* The following definitions come from talloc.c */ +void *_talloc(const void *context, size_t size); +void *talloc_pool(const void *context, size_t size); +void _talloc_set_destructor(const void *ptr, int (*_destructor)(void *)); +int talloc_increase_ref_count(const void *ptr); +size_t talloc_reference_count(const void *ptr); +void *_talloc_reference_loc(const void *context, const void *ptr, const char *location); +int talloc_unlink(const void *context, void *ptr); +const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); +void talloc_set_name_const(const void *ptr, const char *name); +void *talloc_named(const void *context, size_t size, + const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); +void *talloc_named_const(const void *context, size_t size, const char *name); +const char *talloc_get_name(const void *ptr); +void *talloc_check_name(const void *ptr, const char *name); +void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location); +void *talloc_parent(const void *ptr); +const char *talloc_parent_name(const void *ptr); +void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); +int _talloc_free(void *ptr, const char *location); +void talloc_free_children(void *ptr); +void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name); +void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *location); +void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr); +void *_talloc_move(const void *new_ctx, const void *pptr); +size_t talloc_total_size(const void *ptr); +size_t talloc_total_blocks(const void *ptr); +void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, + void (*callback)(const void *ptr, + int depth, int max_depth, + int is_ref, + void *private_data), + void *private_data); +void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f); +void talloc_report_full(const void *ptr, FILE *f); +void talloc_report(const void *ptr, FILE *f); +void talloc_enable_null_tracking(void); +void talloc_enable_null_tracking_no_autofree(void); +void talloc_disable_null_tracking(void); +void talloc_enable_leak_report(void); +void talloc_enable_leak_report_full(void); +void *_talloc_zero(const void *ctx, size_t size, const char *name); +void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name); +void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name); +void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name); +void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name); +void *talloc_realloc_fn(const void *context, void *ptr, size_t size); +void *talloc_autofree_context(void); +size_t talloc_get_size(const void *ctx); +void *talloc_find_parent_byname(const void *ctx, const char *name); +void talloc_show_parents(const void *context, FILE *file); +int talloc_is_parent(const void *context, const void *ptr); + +char *talloc_strdup(const void *t, const char *p); +char *talloc_strdup_append(char *s, const char *a); +char *talloc_strdup_append_buffer(char *s, const char *a); + +char *talloc_strndup(const void *t, const char *p, size_t n); +char *talloc_strndup_append(char *s, const char *a, size_t n); +char *talloc_strndup_append_buffer(char *s, const char *a, size_t n); + +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); +char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); +char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); + +char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); +char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); +char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); + +void talloc_set_abort_fn(void (*abort_fn)(const char *reason)); +void talloc_set_log_fn(void (*log_fn)(const char *message)); +void talloc_set_log_stderr(void); + +#endif diff --git a/src/talloc/talloc_guide.txt b/src/talloc/talloc_guide.txt new file mode 100644 index 0000000000..01de806662 --- /dev/null +++ b/src/talloc/talloc_guide.txt @@ -0,0 +1,757 @@ +Using talloc in Samba4 +====================== + +.. contents:: + +Andrew Tridgell +August 2009 + +The most current version of this document is available at + http://samba.org/ftp/unpacked/talloc/talloc_guide.txt + +If you are used to the "old" talloc from Samba3 before 3.0.20 then please read +this carefully, as talloc has changed a lot. With 3.0.20 (or 3.0.14?) the +Samba4 talloc has been ported back to Samba3, so this guide applies to both. + +The new talloc is a hierarchical, reference counted memory pool system +with destructors. Quite a mouthful really, but not too bad once you +get used to it. + +Perhaps the biggest change from Samba3 is that there is no distinction +between a "talloc context" and a "talloc pointer". Any pointer +returned from talloc() is itself a valid talloc context. This means +you can do this:: + + struct foo *X = talloc(mem_ctx, struct foo); + X->name = talloc_strdup(X, "foo"); + +and the pointer X->name would be a "child" of the talloc context "X" +which is itself a child of mem_ctx. So if you do talloc_free(mem_ctx) +then it is all destroyed, whereas if you do talloc_free(X) then just X +and X->name are destroyed, and if you do talloc_free(X->name) then +just the name element of X is destroyed. + +If you think about this, then what this effectively gives you is an +n-ary tree, where you can free any part of the tree with +talloc_free(). + +If you find this confusing, then I suggest you run the testsuite to +watch talloc in action. You may also like to add your own tests to +testsuite.c to clarify how some particular situation is handled. + + +Performance +----------- + +All the additional features of talloc() over malloc() do come at a +price. We have a simple performance test in Samba4 that measures +talloc() versus malloc() performance, and it seems that talloc() is +about 4% slower than malloc() on my x86 Debian Linux box. For Samba, +the great reduction in code complexity that we get by using talloc +makes this worthwhile, especially as the total overhead of +talloc/malloc in Samba is already quite small. + + +talloc API +---------- + +The following is a complete guide to the talloc API. Read it all at +least twice. + +Multi-threading +--------------- + +talloc itself does not deal with threads. It is thread-safe (assuming +the underlying "malloc" is), as long as each thread uses different +memory contexts. +If two threads uses the same context then they need to synchronize in +order to be safe. In particular: +- when using talloc_enable_leak_report(), giving directly NULL as a +parent context implicitly refers to a hidden "null context" global +variable, so this should not be used in a multi-threaded environment +without proper synchronization ; +- the context returned by talloc_autofree_context() is also global so +shouldn't be used by several threads simultaneously without +synchronization. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc(const void *context, type); + +The talloc() macro is the core of the talloc library. It takes a +memory context and a type, and returns a pointer to a new area of +memory of the given type. + +The returned pointer is itself a talloc context, so you can use it as +the context argument to more calls to talloc if you wish. + +The returned pointer is a "child" of the supplied context. This means +that if you talloc_free() the context then the new child disappears as +well. Alternatively you can free just the child. + +The context argument to talloc() can be NULL, in which case a new top +level context is created. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_size(const void *context, size_t size); + +The function talloc_size() should be used when you don't have a +convenient type to pass to talloc(). Unlike talloc(), it is not type +safe (as it returns a void *), so you are on your own for type checking. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr); + +The talloc_ptrtype() macro should be used when you have a pointer and +want to allocate memory to point at with this pointer. When compiling +with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size() +and talloc_get_name() will return the current location in the source file. +and not the type. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +int talloc_free(void *ptr); + +The talloc_free() function frees a piece of talloc memory, and all its +children. You can call talloc_free() on any pointer returned by +talloc(). + +The return value of talloc_free() indicates success or failure, with 0 +returned for success and -1 for failure. The only possible failure +condition is if the pointer had a destructor attached to it and the +destructor returned -1. See talloc_set_destructor() for details on +destructors. + +If this pointer has an additional parent when talloc_free() is called +then the memory is not actually released, but instead the most +recently established parent is destroyed. See talloc_reference() for +details on establishing additional parents. + +For more control on which parent is removed, see talloc_unlink() + +talloc_free() operates recursively on its children. + +From the 2.0 version of talloc, as a special case, talloc_free() is +refused on pointers that have more than one parent, as talloc would +have no way of knowing which parent should be removed. To free a +pointer that has more than one parent please use talloc_unlink(). + +To help you find problems in your code caused by this behaviour, if +you do try and free a pointer with more than one parent then the +talloc logging function will be called to give output like this: + + ERROR: talloc_free with references at some_dir/source/foo.c:123 + reference at some_dir/source/other.c:325 + reference at some_dir/source/third.c:121 + +Please see the documentation for talloc_set_log_fn() and +talloc_set_log_stderr() for more information on talloc logging +functions. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +int talloc_free_children(void *ptr); + +The talloc_free_children() walks along the list of all children of a +talloc context and talloc_free()s only the children, not the context +itself. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_reference(const void *context, const void *ptr); + +The talloc_reference() function makes "context" an additional parent +of "ptr". + +The return value of talloc_reference() is always the original pointer +"ptr", unless talloc ran out of memory in creating the reference in +which case it will return NULL (each additional reference consumes +around 48 bytes of memory on intel x86 platforms). + +If "ptr" is NULL, then the function is a no-op, and simply returns NULL. + +After creating a reference you can free it in one of the following +ways: + + - you can talloc_free() any parent of the original pointer. That + will reduce the number of parents of this pointer by 1, and will + cause this pointer to be freed if it runs out of parents. + + - you can talloc_free() the pointer itself. That will destroy the + most recently established parent to the pointer and leave the + pointer as a child of its current parent. + +For more control on which parent to remove, see talloc_unlink() + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +int talloc_unlink(const void *context, const void *ptr); + +The talloc_unlink() function removes a specific parent from ptr. The +context passed must either be a context used in talloc_reference() +with this pointer, or must be a direct parent of ptr. + +Note that if the parent has already been removed using talloc_free() +then this function will fail and will return -1. Likewise, if "ptr" +is NULL, then the function will make no modifications and return -1. + +Usually you can just use talloc_free() instead of talloc_unlink(), but +sometimes it is useful to have the additional control on which parent +is removed. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_destructor(const void *ptr, int (*destructor)(void *)); + +The function talloc_set_destructor() sets the "destructor" for the +pointer "ptr". A destructor is a function that is called when the +memory used by a pointer is about to be released. The destructor +receives the pointer as an argument, and should return 0 for success +and -1 for failure. + +The destructor can do anything it wants to, including freeing other +pieces of memory. A common use for destructors is to clean up +operating system resources (such as open file descriptors) contained +in the structure the destructor is placed on. + +You can only place one destructor on a pointer. If you need more than +one destructor then you can create a zero-length child of the pointer +and place an additional destructor on that. + +To remove a destructor call talloc_set_destructor() with NULL for the +destructor. + +If your destructor attempts to talloc_free() the pointer that it is +the destructor for then talloc_free() will return -1 and the free will +be ignored. This would be a pointless operation anyway, as the +destructor is only called when the memory is just about to go away. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +int talloc_increase_ref_count(const void *ptr); + +The talloc_increase_ref_count(ptr) function is exactly equivalent to: + + talloc_reference(NULL, ptr); + +You can use either syntax, depending on which you think is clearer in +your code. + +It returns 0 on success and -1 on failure. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +size_t talloc_reference_count(const void *ptr); + +Return the number of references to the pointer. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_name(const void *ptr, const char *fmt, ...); + +Each talloc pointer has a "name". The name is used principally for +debugging purposes, although it is also possible to set and get the +name on a pointer in as a way of "marking" pointers in your code. + +The main use for names on pointer is for "talloc reports". See +talloc_report() and talloc_report_full() for details. Also see +talloc_enable_leak_report() and talloc_enable_leak_report_full(). + +The talloc_set_name() function allocates memory as a child of the +pointer. It is logically equivalent to: + talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...)); + +Note that multiple calls to talloc_set_name() will allocate more +memory without releasing the name. All of the memory is released when +the ptr is freed using talloc_free(). + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_name_const(const void *ptr, const char *name); + +The function talloc_set_name_const() is just like talloc_set_name(), +but it takes a string constant, and is much faster. It is extensively +used by the "auto naming" macros, such as talloc_p(). + +This function does not allocate any memory. It just copies the +supplied pointer into the internal representation of the talloc +ptr. This means you must not pass a name pointer to memory that will +disappear before the ptr is freed with talloc_free(). + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_named(const void *context, size_t size, const char *fmt, ...); + +The talloc_named() function creates a named talloc pointer. It is +equivalent to: + + ptr = talloc_size(context, size); + talloc_set_name(ptr, fmt, ....); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_named_const(const void *context, size_t size, const char *name); + +This is equivalent to:: + + ptr = talloc_size(context, size); + talloc_set_name_const(ptr, name); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +const char *talloc_get_name(const void *ptr); + +This returns the current name for the given talloc pointer. See +talloc_set_name() for details. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_init(const char *fmt, ...); + +This function creates a zero length named talloc context as a top +level context. It is equivalent to:: + + talloc_named(NULL, 0, fmt, ...); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_new(void *ctx); + +This is a utility macro that creates a new memory context hanging +off an exiting context, automatically naming it "talloc_new: __location__" +where __location__ is the source line it is called from. It is +particularly useful for creating a new temporary working context. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc_realloc(const void *context, void *ptr, type, count); + +The talloc_realloc() macro changes the size of a talloc +pointer. The "count" argument is the number of elements of type "type" +that you want the resulting pointer to hold. + +talloc_realloc() has the following equivalences:: + + talloc_realloc(context, NULL, type, 1) ==> talloc(context, type); + talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N); + talloc_realloc(context, ptr, type, 0) ==> talloc_free(ptr); + +The "context" argument is only used if "ptr" is NULL, otherwise it is +ignored. + +talloc_realloc() returns the new pointer, or NULL on failure. The call +will fail either due to a lack of memory, or because the pointer has +more than one parent (see talloc_reference()). + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_realloc_size(const void *context, void *ptr, size_t size); + +the talloc_realloc_size() function is useful when the type is not +known so the typesafe talloc_realloc() cannot be used. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_steal(const void *new_ctx, const void *ptr); + +The talloc_steal() function changes the parent context of a talloc +pointer. It is typically used when the context that the pointer is +currently a child of is going to be freed and you wish to keep the +memory for a longer time. + +The talloc_steal() function returns the pointer that you pass it. It +does not have any failure modes. + +NOTE: It is possible to produce loops in the parent/child relationship +if you are not careful with talloc_steal(). No guarantees are provided +as to your sanity or the safety of your data if you do this. + +talloc_steal (new_ctx, NULL) will return NULL with no sideeffects. + +Note that if you try and call talloc_steal() on a pointer that has +more than one parent then the result is ambiguous. Talloc will choose +to remove the parent that is currently indicated by talloc_parent() +and replace it with the chosen parent. You will also get a message +like this via the talloc logging functions: + + WARNING: talloc_steal with references at some_dir/source/foo.c:123 + reference at some_dir/source/other.c:325 + reference at some_dir/source/third.c:121 + +To unambiguously change the parent of a pointer please see the +function talloc_reparent(). See the talloc_set_log_fn() documentation +for more information on talloc logging. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr); + +The talloc_reparent() function changes the parent context of a talloc +pointer. It is typically used when the context that the pointer is +currently a child of is going to be freed and you wish to keep the +memory for a longer time. + +The talloc_reparent() function returns the pointer that you pass it. It +does not have any failure modes. + +The difference between talloc_reparent() and talloc_steal() is that +talloc_reparent() can specify which parent you wish to change. This is +useful when a pointer has multiple parents via references. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_parent(const void *ptr); + +The talloc_parent() function returns the current talloc parent. This +is usually the pointer under which this memory was originally created, +but it may have changed due to a talloc_steal() or talloc_reparent() + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +size_t talloc_total_size(const void *ptr); + +The talloc_total_size() function returns the total size in bytes used +by this pointer and all child pointers. Mostly useful for debugging. + +Passing NULL is allowed, but it will only give a meaningful result if +talloc_enable_leak_report() or talloc_enable_leak_report_full() has +been called. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +size_t talloc_total_blocks(const void *ptr); + +The talloc_total_blocks() function returns the total memory block +count used by this pointer and all child pointers. Mostly useful for +debugging. + +Passing NULL is allowed, but it will only give a meaningful result if +talloc_enable_leak_report() or talloc_enable_leak_report_full() has +been called. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, + void (*callback)(const void *ptr, + int depth, int max_depth, + int is_ref, + void *priv), + void *priv); + +This provides a more flexible reports than talloc_report(). It +will recursively call the callback for the entire tree of memory +referenced by the pointer. References in the tree are passed with +is_ref = 1 and the pointer that is referenced. + +You can pass NULL for the pointer, in which case a report is +printed for the top level memory context, but only if +talloc_enable_leak_report() or talloc_enable_leak_report_full() +has been called. + +The recursion is stopped when depth >= max_depth. +max_depth = -1 means only stop at leaf nodes. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f); + +This provides a more flexible reports than talloc_report(). It +will let you specify the depth and max_depth. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_report(const void *ptr, FILE *f); + +The talloc_report() function prints a summary report of all memory +used by ptr. One line of report is printed for each immediate child of +ptr, showing the total memory and number of blocks used by that child. + +You can pass NULL for the pointer, in which case a report is printed +for the top level memory context, but only if +talloc_enable_leak_report() or talloc_enable_leak_report_full() has +been called. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_report_full(const void *ptr, FILE *f); + +This provides a more detailed report than talloc_report(). It will +recursively print the ensire tree of memory referenced by the +pointer. References in the tree are shown by giving the name of the +pointer that is referenced. + +You can pass NULL for the pointer, in which case a report is printed +for the top level memory context, but only if +talloc_enable_leak_report() or talloc_enable_leak_report_full() has +been called. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_enable_leak_report(void); + +This enables calling of talloc_report(NULL, stderr) when the program +exits. In Samba4 this is enabled by using the --leak-report command +line option. + +For it to be useful, this function must be called before any other +talloc function as it establishes a "null context" that acts as the +top of the tree. If you don't call this function first then passing +NULL to talloc_report() or talloc_report_full() won't give you the +full tree printout. + +Here is a typical talloc report: + +talloc report on 'null_context' (total 267 bytes in 15 blocks) + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks + iconv(UTF8,CP850) contains 42 bytes in 2 blocks + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks + iconv(CP850,UTF8) contains 42 bytes in 2 blocks + iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks + iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_enable_leak_report_full(void); + +This enables calling of talloc_report_full(NULL, stderr) when the +program exits. In Samba4 this is enabled by using the +--leak-report-full command line option. + +For it to be useful, this function must be called before any other +talloc function as it establishes a "null context" that acts as the +top of the tree. If you don't call this function first then passing +NULL to talloc_report() or talloc_report_full() won't give you the +full tree printout. + +Here is a typical full report: + +full talloc report on 'root' (total 18 bytes in 8 blocks) + p1 contains 18 bytes in 7 blocks (ref 0) + r1 contains 13 bytes in 2 blocks (ref 0) + reference to: p2 + p2 contains 1 bytes in 1 blocks (ref 1) + x3 contains 1 bytes in 1 blocks (ref 0) + x2 contains 1 bytes in 1 blocks (ref 0) + x1 contains 1 bytes in 1 blocks (ref 0) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_enable_null_tracking(void); + +This enables tracking of the NULL memory context without enabling leak +reporting on exit. Useful for when you want to do your own leak +reporting call via talloc_report_null_full(); + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_disable_null_tracking(void); + +This disables tracking of the NULL memory context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc_zero(const void *ctx, type); + +The talloc_zero() macro is equivalent to:: + + ptr = talloc(ctx, type); + if (ptr) memset(ptr, 0, sizeof(type)); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_zero_size(const void *ctx, size_t size) + +The talloc_zero_size() function is useful when you don't have a known type + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_memdup(const void *ctx, const void *p, size_t size); + +The talloc_memdup() function is equivalent to:: + + ptr = talloc_size(ctx, size); + if (ptr) memcpy(ptr, p, size); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_strdup(const void *ctx, const char *p); + +The talloc_strdup() function is equivalent to:: + + ptr = talloc_size(ctx, strlen(p)+1); + if (ptr) memcpy(ptr, p, strlen(p)+1); + +This functions sets the name of the new pointer to the passed +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_strndup(const void *t, const char *p, size_t n); + +The talloc_strndup() function is the talloc equivalent of the C +library function strndup() + +This functions sets the name of the new pointer to the passed +string. This is equivalent to: + talloc_set_name_const(ptr, ptr) + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_append_string(const void *t, char *orig, const char *append); + +The talloc_append_string() function appends the given formatted +string to the given string. + +This function sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap); + +The talloc_vasprintf() function is the talloc equivalent of the C +library function vasprintf() + +This functions sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_asprintf(const void *t, const char *fmt, ...); + +The talloc_asprintf() function is the talloc equivalent of the C +library function asprintf() + +This functions sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_asprintf_append(char *s, const char *fmt, ...); + +The talloc_asprintf_append() function appends the given formatted +string to the given string. +Use this varient when the string in the current talloc buffer may +have been truncated in length. + +This functions sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...); + +The talloc_asprintf_append() function appends the given formatted +string to the end of the currently allocated talloc buffer. +Use this varient when the string in the current talloc buffer has +not been changed. + +This functions sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +((type *)talloc_array(const void *ctx, type, uint_t count); + +The talloc_array() macro is equivalent to:: + + (type *)talloc_size(ctx, sizeof(type) * count); + +except that it provides integer overflow protection for the multiply, +returning NULL if the multiply overflows. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_array_size(const void *ctx, size_t size, uint_t count); + +The talloc_array_size() function is useful when the type is not +known. It operates in the same way as talloc_array(), but takes a size +instead of a type. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, uint_t count); + +The talloc_ptrtype() macro should be used when you have a pointer to an array +and want to allocate memory of an array to point at with this pointer. When compiling +with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size() +and talloc_get_name() will return the current location in the source file. +and not the type. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size); + +This is a non-macro version of talloc_realloc(), which is useful +as libraries sometimes want a ralloc function pointer. A realloc() +implementation encapsulates the functionality of malloc(), free() and +realloc() in one call, which is why it is useful to be able to pass +around a single function pointer. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_autofree_context(void); + +This is a handy utility function that returns a talloc context +which will be automatically freed on program exit. This can be used +to reduce the noise in memory leak reports. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_check_name(const void *ptr, const char *name); + +This function checks if a pointer has the specified name. If it does +then the pointer is returned. It it doesn't then NULL is returned. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc_get_type(const void *ptr, type); + +This macro allows you to do type checking on talloc pointers. It is +particularly useful for void* private pointers. It is equivalent to +this:: + + (type *)talloc_check_name(ptr, #type) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +talloc_set_type(const void *ptr, type); + +This macro allows you to force the name of a pointer to be a +particular type. This can be used in conjunction with +talloc_get_type() to do type checking on void* pointers. + +It is equivalent to this:: + + talloc_set_name_const(ptr, #type) + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +talloc_get_size(const void *ctx); + +This function lets you know the amount of memory alloced so far by +this context. It does NOT account for subcontext memory. +This can be used to calculate the size of an array. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_find_parent_byname(const void *ctx, const char *name); + +Find a parent memory context of the current context that has the given +name. This can be very useful in complex programs where it may be +difficult to pass all information down to the level you need, but you +know the structure you want is a parent of another context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc_find_parent_bytype(ctx, type); + +Like talloc_find_parent_byname() but takes a type, making it typesafe. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_log_fn(void (*log_fn)(const char *message)); + +This function sets a logging function that talloc will use for +warnings and errors. By default talloc will not print any warnings or +errors. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_log_stderr(void) + +This sets the talloc log function to write log messages to stderr |