Merge branch 'master' of ssh://git.freedesktop.org/git/mesa/mesa into pipe-video

Conflicts:
	src/gallium/include/pipe/p_format.h
This commit is contained in:
Christian König 2010-10-28 20:24:56 +02:00
commit 41ed47d6b8
1126 changed files with 34370 additions and 29084 deletions

View file

@ -53,7 +53,7 @@ MKDEP_OPTIONS = @MKDEP_OPTIONS@
INSTALL = @INSTALL@ INSTALL = @INSTALL@
# Python and flags (generally only needed by the developers) # Python and flags (generally only needed by the developers)
PYTHON2 = python PYTHON2 = @PYTHON2@
PYTHON_FLAGS = -t -O -O PYTHON_FLAGS = -t -O -O
# Library names (base name) # Library names (base name)

View file

@ -30,6 +30,7 @@ AC_PROG_CPP
AC_PROG_CC AC_PROG_CC
AC_PROG_CXX AC_PROG_CXX
AC_CHECK_PROGS([MAKE], [gmake make]) AC_CHECK_PROGS([MAKE], [gmake make])
AC_CHECK_PROGS([PYTHON2], [python2 python])
AC_PATH_PROG([MKDEP], [makedepend]) AC_PATH_PROG([MKDEP], [makedepend])
AC_PATH_PROG([SED], [sed]) AC_PATH_PROG([SED], [sed])
@ -1720,6 +1721,8 @@ echo ""
echo " CFLAGS: $cflags" echo " CFLAGS: $cflags"
echo " CXXFLAGS: $cxxflags" echo " CXXFLAGS: $cxxflags"
echo " Macros: $defines" echo " Macros: $defines"
echo ""
echo " PYTHON2: $PYTHON2"
echo "" echo ""
echo " Run '${MAKE-make}' to build Mesa" echo " Run '${MAKE-make}' to build Mesa"

View file

@ -25,7 +25,7 @@ Non-normalized Integer texture/framebuffer formats not started
Packed depth/stencil formats DONE Packed depth/stencil formats DONE
Per-buffer blend and masks (GL_EXT_draw_buffers2) DONE Per-buffer blend and masks (GL_EXT_draw_buffers2) DONE
GL_EXT_texture_compression_rgtc not started GL_EXT_texture_compression_rgtc not started
Red and red/green texture formats DONE (swrast, i965) Red and red/green texture formats DONE (swrast, i965, gallium)
Transform feedback (GL_EXT_transform_feedback) ~50% done Transform feedback (GL_EXT_transform_feedback) ~50% done
glBindFragDataLocation, glGetFragDataLocation, glBindFragDataLocation, glGetFragDataLocation,
glBindBufferRange, glBindBufferBase commands glBindBufferRange, glBindBufferBase commands
@ -42,7 +42,7 @@ GL 3.1:
GLSL 1.30 and 1.40 not started GLSL 1.30 and 1.40 not started
Instanced drawing (GL_ARB_draw_instanced) ~50% done Instanced drawing (GL_ARB_draw_instanced) ~50% done
Buffer copying (GL_ARB_copy_buffer) DONE Buffer copying (GL_ARB_copy_buffer) DONE
Primitive restart (GL_NV_primitive_restart) not started Primitive restart (GL_NV_primitive_restart) DONE (gallium)
16 vertex texture image units not started 16 vertex texture image units not started
Texture buffer objs (GL_ARB_texture_buffer_object) not started Texture buffer objs (GL_ARB_texture_buffer_object) not started
Rectangular textures (GL_ARB_texture_rectangle) DONE Rectangular textures (GL_ARB_texture_rectangle) DONE

View file

@ -35,6 +35,9 @@ tbd
<h2>New features</h2> <h2>New features</h2>
<ul> <ul>
<li>GL_ARB_explicit_attrib_location extension (Intel and software drivers). <li>GL_ARB_explicit_attrib_location extension (Intel and software drivers).
<li>GL_ARB_texture_rg (Intel, software drivers, gallium drivers).
<li>GL_EXT_separate_shader_objects extension (Intel and software drivers).
<li>GL_NV_primitive_restart extension (Gallium softpipe, llvmpipe).
</ul> </ul>

View file

@ -24,8 +24,8 @@ $(EGL_DRIVER_PATH): $(EGL_DRIVER)
$(EGL_DRIVER): $(EGL_OBJECTS) Makefile $(TOP)/src/egl/drivers/Makefile.template $(EGL_DRIVER): $(EGL_OBJECTS) Makefile $(TOP)/src/egl/drivers/Makefile.template
@$(MKLIB) -o $(EGL_DRIVER) -noprefix \ @$(MKLIB) -o $(EGL_DRIVER) -noprefix \
-linker '$(CC)' -ldflags '$(LDFLAGS)' \ -linker '$(CC)' -ldflags '-L$(TOP)/$(LIB_DIR) $(LDFLAGS)' \
-L$(TOP)/$(LIB_DIR) $(MKLIB_OPTIONS) \ $(MKLIB_OPTIONS) \
$(EGL_OBJECTS) $(EGL_LIBS) -l$(EGL_LIB) $(EGL_OBJECTS) $(EGL_LIBS) -l$(EGL_LIB)
.c.o: .c.o:

View file

@ -248,21 +248,20 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
if (double_buffer) if (double_buffer)
return NULL; return NULL;
if (depth > 0 && depth != _eglGetConfigKey(&base, EGL_BUFFER_SIZE)) if (depth > 0 && depth != base.BufferSize)
return NULL; return NULL;
_eglSetConfigKey(&base, EGL_NATIVE_RENDERABLE, EGL_TRUE); base.NativeRenderable = EGL_TRUE;
_eglSetConfigKey(&base, EGL_SURFACE_TYPE, surface_type); base.SurfaceType = surface_type;
if (surface_type & (EGL_PIXMAP_BIT | EGL_PBUFFER_BIT)) { if (surface_type & (EGL_PIXMAP_BIT | EGL_PBUFFER_BIT)) {
_eglSetConfigKey(&base, EGL_BIND_TO_TEXTURE_RGB, bind_to_texture_rgb); base.BindToTextureRGB = bind_to_texture_rgb;
if (_eglGetConfigKey(&base, EGL_ALPHA_SIZE) > 0) if (base.AlphaSize > 0)
_eglSetConfigKey(&base, base.BindToTextureRGBA = bind_to_texture_rgba;
EGL_BIND_TO_TEXTURE_RGBA, bind_to_texture_rgba);
} }
_eglSetConfigKey(&base, EGL_RENDERABLE_TYPE, disp->ClientAPIsMask); base.RenderableType = disp->ClientAPIsMask;
_eglSetConfigKey(&base, EGL_CONFORMANT, disp->ClientAPIsMask); base.Conformant = disp->ClientAPIsMask;
if (!_eglValidateConfig(&base, EGL_FALSE)) { if (!_eglValidateConfig(&base, EGL_FALSE)) {
_eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id); _eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
@ -273,7 +272,7 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
if (conf != NULL) { if (conf != NULL) {
memcpy(&conf->base, &base, sizeof base); memcpy(&conf->base, &base, sizeof base);
conf->dri_config = dri_config; conf->dri_config = dri_config;
_eglAddConfig(disp, &conf->base); _eglLinkConfig(&conf->base);
} }
return conf; return conf;
@ -1161,7 +1160,7 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
(void) drv; (void) drv;
if (_eglIsSurfaceBound(surf)) if (!_eglPutSurface(surf))
return EGL_TRUE; return EGL_TRUE;
(*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
@ -1188,15 +1187,17 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf); struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf); struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
_EGLContext *old_ctx;
_EGLSurface *old_dsurf, *old_rsurf;
__DRIdrawable *ddraw, *rdraw; __DRIdrawable *ddraw, *rdraw;
__DRIcontext *cctx; __DRIcontext *cctx;
/* bind the new context and return the "orphaned" one */ /* make new bindings */
if (!_eglBindContext(&ctx, &dsurf, &rsurf)) if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
return EGL_FALSE; return EGL_FALSE;
/* flush before context switch */ /* flush before context switch */
if (ctx && dri2_drv->glFlush) if (old_ctx && dri2_drv->glFlush)
dri2_drv->glFlush(); dri2_drv->glFlush();
ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL; ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
@ -1205,16 +1206,29 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
if ((cctx == NULL && ddraw == NULL && rdraw == NULL) || if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) { dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
if (dsurf && !_eglIsSurfaceLinked(dsurf)) dri2_destroy_surface(drv, disp, old_dsurf);
dri2_destroy_surface(drv, disp, dsurf); dri2_destroy_surface(drv, disp, old_rsurf);
if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(dsurf)) if (old_ctx) {
dri2_destroy_surface(drv, disp, rsurf); dri2_dpy->core->unbindContext(dri2_egl_context(old_ctx)->dri_context);
if (ctx != NULL && !_eglIsContextLinked(ctx)) /* no destroy? */
dri2_dpy->core->unbindContext(dri2_egl_context(ctx)->dri_context); _eglPutContext(old_ctx);
}
return EGL_TRUE; return EGL_TRUE;
} else { } else {
_eglBindContext(&ctx, &dsurf, &rsurf); /* undo the previous _eglBindContext */
_eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
assert(&dri2_ctx->base == ctx &&
&dri2_dsurf->base == dsurf &&
&dri2_rsurf->base == rsurf);
_eglPutSurface(dsurf);
_eglPutSurface(rsurf);
_eglPutContext(ctx);
_eglPutSurface(old_dsurf);
_eglPutSurface(old_rsurf);
_eglPutContext(old_ctx);
return EGL_FALSE; return EGL_FALSE;
} }
@ -1251,8 +1265,7 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
if (type == EGL_PBUFFER_BIT) { if (type == EGL_PBUFFER_BIT) {
dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn); dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
xcb_create_pixmap(dri2_dpy->conn, xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
_eglGetConfigKey(conf, EGL_BUFFER_SIZE),
dri2_surf->drawable, s.data->root, dri2_surf->drawable, s.data->root,
dri2_surf->base.Width, dri2_surf->base.Height); dri2_surf->base.Width, dri2_surf->base.Height);
} else { } else {
@ -1601,7 +1614,7 @@ dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
return EGL_NO_IMAGE_KHR; return EGL_NO_IMAGE_KHR;
} }
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) { if (!_eglInitImage(&dri2_img->base, disp)) {
free(buffers_reply); free(buffers_reply);
free(geometry_reply); free(geometry_reply);
return EGL_NO_IMAGE_KHR; return EGL_NO_IMAGE_KHR;
@ -1644,7 +1657,7 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
return EGL_NO_IMAGE_KHR; return EGL_NO_IMAGE_KHR;
} }
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) if (!_eglInitImage(&dri2_img->base, disp))
return EGL_NO_IMAGE_KHR; return EGL_NO_IMAGE_KHR;
dri2_img->dri_image = dri2_img->dri_image =
@ -1661,56 +1674,28 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
{ {
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_image *dri2_img; struct dri2_egl_image *dri2_img;
EGLint width, height, format, name, stride, pitch, i, err; EGLint format, name, pitch, err;
_EGLImageAttribs attrs;
(void) ctx; (void) ctx;
name = (EGLint) buffer; name = (EGLint) buffer;
err = EGL_SUCCESS; err = _eglParseImageAttribList(&attrs, disp, attr_list);
width = 0; if (err != EGL_SUCCESS)
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; return NULL;
}
}
if (width <= 0 || height <= 0 || stride <= 0) { if (attrs.Width <= 0 || attrs.Height <= 0 ||
attrs.DRMBufferStrideMESA <= 0) {
_eglError(EGL_BAD_PARAMETER, _eglError(EGL_BAD_PARAMETER,
"bad width, height or stride"); "bad width, height or stride");
return NULL; return NULL;
} }
switch (format) { switch (attrs.DRMBufferFormatMESA) {
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
format = __DRI_IMAGE_FORMAT_ARGB8888; format = __DRI_IMAGE_FORMAT_ARGB8888;
pitch = stride; pitch = attrs.DRMBufferStrideMESA;
break; break;
default: default:
_eglError(EGL_BAD_PARAMETER, _eglError(EGL_BAD_PARAMETER,
@ -1724,15 +1709,15 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
return NULL; return NULL;
} }
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) { if (!_eglInitImage(&dri2_img->base, disp)) {
free(dri2_img); free(dri2_img);
return NULL; return NULL;
} }
dri2_img->dri_image = dri2_img->dri_image =
dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
width, attrs.Width,
height, attrs.Height,
format, format,
name, name,
pitch, pitch,
@ -1786,8 +1771,9 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
{ {
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_image *dri2_img; struct dri2_egl_image *dri2_img;
int width, height, format, i; _EGLImageAttribs attrs;
unsigned int use, dri_use, valid_mask; unsigned int dri_use, valid_mask;
int format;
EGLint err = EGL_SUCCESS; EGLint err = EGL_SUCCESS;
(void) drv; (void) drv;
@ -1803,74 +1789,50 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
goto cleanup_img; goto cleanup_img;
} }
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) { if (!_eglInitImage(&dri2_img->base, disp)) {
err = EGL_BAD_PARAMETER; err = EGL_BAD_PARAMETER;
goto cleanup_img; goto cleanup_img;
} }
width = 0; err = _eglParseImageAttribList(&attrs, disp, attr_list);
height = 0; if (err != EGL_SUCCESS)
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; goto cleanup_img;
}
}
if (width <= 0 || height <= 0) { if (attrs.Width <= 0 || attrs.Height <= 0) {
_eglLog(_EGL_WARNING, "bad width or height (%dx%d)", width, height); _eglLog(_EGL_WARNING, "bad width or height (%dx%d)",
attrs.Width, attrs.Height);
goto cleanup_img; goto cleanup_img;
} }
switch (format) { switch (attrs.DRMBufferFormatMESA) {
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
format = __DRI_IMAGE_FORMAT_ARGB8888; format = __DRI_IMAGE_FORMAT_ARGB8888;
break; break;
default: default:
_eglLog(_EGL_WARNING, "bad image format value 0x%04x", format); _eglLog(_EGL_WARNING, "bad image format value 0x%04x",
attrs.DRMBufferFormatMESA);
goto cleanup_img; goto cleanup_img;
} }
valid_mask = valid_mask =
EGL_DRM_BUFFER_USE_SCANOUT_MESA | EGL_DRM_BUFFER_USE_SCANOUT_MESA |
EGL_DRM_BUFFER_USE_SHARE_MESA; EGL_DRM_BUFFER_USE_SHARE_MESA;
if (use & ~valid_mask) { if (attrs.DRMBufferUseMESA & ~valid_mask) {
_eglLog(_EGL_WARNING, "bad image use bit 0x%04x", use & ~valid_mask); _eglLog(_EGL_WARNING, "bad image use bit 0x%04x",
attrs.DRMBufferUseMESA & ~valid_mask);
goto cleanup_img; goto cleanup_img;
} }
dri_use = 0; dri_use = 0;
if (use & EGL_DRM_BUFFER_USE_SHARE_MESA) if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SHARE_MESA)
dri_use |= __DRI_IMAGE_USE_SHARE; dri_use |= __DRI_IMAGE_USE_SHARE;
if (use & EGL_DRM_BUFFER_USE_SCANOUT_MESA) if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
dri_use |= __DRI_IMAGE_USE_SCANOUT; dri_use |= __DRI_IMAGE_USE_SCANOUT;
dri2_img->dri_image = dri2_img->dri_image =
dri2_dpy->image->createImage(dri2_dpy->dri_screen, dri2_dpy->image->createImage(dri2_dpy->dri_screen,
width, height, format, dri_use, dri2_img); attrs.Width, attrs.Height,
format, dri_use, dri2_img);
if (dri2_img->dri_image == NULL) { if (dri2_img->dri_image == NULL) {
err = EGL_BAD_ALLOC; err = EGL_BAD_ALLOC;
goto cleanup_img; goto cleanup_img;

View file

@ -132,29 +132,38 @@ static const struct {
int egl_attr; int egl_attr;
} fbconfig_attributes[] = { } fbconfig_attributes[] = {
/* table 3.1 of GLX 1.4 */ /* table 3.1 of GLX 1.4 */
{ GLX_FBCONFIG_ID, 0 },
{ GLX_BUFFER_SIZE, EGL_BUFFER_SIZE }, { GLX_BUFFER_SIZE, EGL_BUFFER_SIZE },
{ GLX_LEVEL, EGL_LEVEL }, { GLX_LEVEL, EGL_LEVEL },
{ GLX_DOUBLEBUFFER, 0 },
{ GLX_STEREO, 0 },
{ GLX_AUX_BUFFERS, 0 },
{ GLX_RED_SIZE, EGL_RED_SIZE }, { GLX_RED_SIZE, EGL_RED_SIZE },
{ GLX_GREEN_SIZE, EGL_GREEN_SIZE }, { GLX_GREEN_SIZE, EGL_GREEN_SIZE },
{ GLX_BLUE_SIZE, EGL_BLUE_SIZE }, { GLX_BLUE_SIZE, EGL_BLUE_SIZE },
{ GLX_ALPHA_SIZE, EGL_ALPHA_SIZE }, { GLX_ALPHA_SIZE, EGL_ALPHA_SIZE },
{ GLX_DEPTH_SIZE, EGL_DEPTH_SIZE }, { GLX_DEPTH_SIZE, EGL_DEPTH_SIZE },
{ GLX_STENCIL_SIZE, EGL_STENCIL_SIZE }, { GLX_STENCIL_SIZE, EGL_STENCIL_SIZE },
{ GLX_ACCUM_RED_SIZE, 0 },
{ GLX_ACCUM_GREEN_SIZE, 0 },
{ GLX_ACCUM_BLUE_SIZE, 0 },
{ GLX_ACCUM_ALPHA_SIZE, 0 },
{ GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS }, { GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS },
{ GLX_SAMPLES, EGL_SAMPLES }, { GLX_SAMPLES, EGL_SAMPLES },
{ GLX_RENDER_TYPE, EGL_RENDERABLE_TYPE }, { GLX_RENDER_TYPE, 0 },
{ GLX_DRAWABLE_TYPE, EGL_SURFACE_TYPE },
{ GLX_X_RENDERABLE, EGL_NATIVE_RENDERABLE }, { GLX_X_RENDERABLE, EGL_NATIVE_RENDERABLE },
{ GLX_X_VISUAL_TYPE, EGL_NATIVE_VISUAL_TYPE }, { GLX_X_VISUAL_TYPE, EGL_NATIVE_VISUAL_TYPE },
{ GLX_CONFIG_CAVEAT, EGL_CONFIG_CAVEAT }, { GLX_CONFIG_CAVEAT, EGL_CONFIG_CAVEAT },
{ GLX_TRANSPARENT_TYPE, EGL_TRANSPARENT_TYPE }, { GLX_TRANSPARENT_TYPE, EGL_TRANSPARENT_TYPE },
{ GLX_TRANSPARENT_INDEX_VALUE, 0 },
{ GLX_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_RED_VALUE }, { GLX_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_RED_VALUE },
{ GLX_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_GREEN_VALUE }, { GLX_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_GREEN_VALUE },
{ GLX_TRANSPARENT_BLUE_VALUE, EGL_TRANSPARENT_BLUE_VALUE }, { GLX_TRANSPARENT_BLUE_VALUE, EGL_TRANSPARENT_BLUE_VALUE },
{ GLX_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_WIDTH }, { GLX_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_WIDTH },
{ GLX_MAX_PBUFFER_HEIGHT, EGL_MAX_PBUFFER_HEIGHT }, { GLX_MAX_PBUFFER_HEIGHT, EGL_MAX_PBUFFER_HEIGHT },
{ GLX_MAX_PBUFFER_PIXELS, EGL_MAX_PBUFFER_PIXELS }, { GLX_MAX_PBUFFER_PIXELS, EGL_MAX_PBUFFER_PIXELS },
{ GLX_VISUAL_ID, EGL_NATIVE_VISUAL_ID }, { GLX_VISUAL_ID, EGL_NATIVE_VISUAL_ID }
{ GLX_X_VISUAL_TYPE, EGL_NATIVE_VISUAL_TYPE },
}; };
@ -162,13 +171,31 @@ static EGLBoolean
convert_fbconfig(Display *dpy, GLXFBConfig fbconfig, convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
struct GLX_egl_config *GLX_conf) struct GLX_egl_config *GLX_conf)
{ {
int err = 0, attr, egl_attr, val; int err, attr, val;
unsigned i; unsigned i;
EGLint conformant, config_caveat, surface_type;
/* must have rgba bit */
err = glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &val);
if (err || !(val & GLX_RGBA_BIT))
return EGL_FALSE;
/* must know whether it is double-buffered */
err = glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &val);
if (err)
return EGL_FALSE;
GLX_conf->double_buffered = val;
GLX_conf->Base.RenderableType = EGL_OPENGL_BIT;
GLX_conf->Base.Conformant = EGL_OPENGL_BIT;
for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) { for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) {
EGLint egl_attr, egl_val;
attr = fbconfig_attributes[i].attr; attr = fbconfig_attributes[i].attr;
egl_attr = fbconfig_attributes[i].egl_attr; egl_attr = fbconfig_attributes[i].egl_attr;
if (!egl_attr)
continue;
err = glXGetFBConfigAttrib(dpy, fbconfig, attr, &val); err = glXGetFBConfigAttrib(dpy, fbconfig, attr, &val);
if (err) { if (err) {
if (err == GLX_BAD_ATTRIBUTE) { if (err == GLX_BAD_ATTRIBUTE) {
@ -178,47 +205,71 @@ convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
break; break;
} }
_eglSetConfigKey(&GLX_conf->Base, egl_attr, val); switch (egl_attr) {
case EGL_SURFACE_TYPE:
egl_val = 0;
if (val & GLX_WINDOW_BIT)
egl_val |= EGL_WINDOW_BIT;
/* pixmap and pbuffer surfaces must be single-buffered in EGL */
if (!GLX_conf->double_buffered) {
if (val & GLX_PIXMAP_BIT)
egl_val |= EGL_PIXMAP_BIT;
if (val & GLX_PBUFFER_BIT)
egl_val |= EGL_PBUFFER_BIT;
}
break;
case EGL_NATIVE_VISUAL_TYPE:
switch (val) {
case GLX_TRUE_COLOR:
egl_val = TrueColor;
break;
case GLX_DIRECT_COLOR:
egl_val = DirectColor;
break;
case GLX_PSEUDO_COLOR:
egl_val = PseudoColor;
break;
case GLX_STATIC_COLOR:
egl_val = StaticColor;
break;
case GLX_GRAY_SCALE:
egl_val = GrayScale;
break;
case GLX_STATIC_GRAY:
egl_val = StaticGray;
break;
default:
egl_val = EGL_NONE;
break;
}
break;
case EGL_CONFIG_CAVEAT:
egl_val = EGL_NONE;
if (val == GLX_SLOW_CONFIG) {
egl_val = EGL_SLOW_CONFIG;
}
else if (val == GLX_NON_CONFORMANT_CONFIG) {
GLX_conf->Base.Conformant &= ~EGL_OPENGL_BIT;
egl_val = EGL_NONE;
}
break;
case EGL_TRANSPARENT_TYPE:
egl_val = (val == GLX_TRANSPARENT_RGB) ?
EGL_TRANSPARENT_RGB : EGL_NONE;
break;
default:
egl_val = val;
break;
}
_eglSetConfigKey(&GLX_conf->Base, egl_attr, egl_val);
} }
if (err) if (err)
return EGL_FALSE; return EGL_FALSE;
/* must have rgba bit */ if (!GLX_conf->Base.SurfaceType)
glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &val);
if (!(val & GLX_RGBA_BIT))
return EGL_FALSE; return EGL_FALSE;
conformant = EGL_OPENGL_BIT;
glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &val);
if (val == GLX_SLOW_CONFIG)
config_caveat = EGL_SLOW_CONFIG;
if (val == GLX_NON_CONFORMANT_CONFIG)
conformant &= ~EGL_OPENGL_BIT;
if (!(conformant & EGL_OPENGL_ES_BIT))
config_caveat = EGL_NON_CONFORMANT_CONFIG;
_eglSetConfigKey(&GLX_conf->Base, EGL_CONFIG_CAVEAT, config_caveat);
surface_type = 0;
glXGetFBConfigAttrib(dpy, fbconfig, GLX_DRAWABLE_TYPE, &val);
if (val & GLX_WINDOW_BIT)
surface_type |= EGL_WINDOW_BIT;
if (val & GLX_PIXMAP_BIT)
surface_type |= EGL_PIXMAP_BIT;
if (val & GLX_PBUFFER_BIT)
surface_type |= EGL_PBUFFER_BIT;
/* pixmap and pbuffer surfaces must be single-buffered in EGL */
glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &val);
GLX_conf->double_buffered = val;
if (GLX_conf->double_buffered) {
surface_type &= ~(EGL_PIXMAP_BIT | EGL_PBUFFER_BIT);
if (!surface_type)
return EGL_FALSE;
}
_eglSetConfigKey(&GLX_conf->Base, EGL_SURFACE_TYPE, surface_type);
return EGL_TRUE; return EGL_TRUE;
} }
@ -227,35 +278,69 @@ static const struct {
int egl_attr; int egl_attr;
} visual_attributes[] = { } visual_attributes[] = {
/* table 3.7 of GLX 1.4 */ /* table 3.7 of GLX 1.4 */
/* no GLX_USE_GL */ { GLX_USE_GL, 0 },
{ GLX_BUFFER_SIZE, EGL_BUFFER_SIZE }, { GLX_BUFFER_SIZE, EGL_BUFFER_SIZE },
{ GLX_LEVEL, EGL_LEVEL }, { GLX_LEVEL, EGL_LEVEL },
{ GLX_RGBA, 0 },
{ GLX_DOUBLEBUFFER, 0 },
{ GLX_STEREO, 0 },
{ GLX_AUX_BUFFERS, 0 },
{ GLX_RED_SIZE, EGL_RED_SIZE }, { GLX_RED_SIZE, EGL_RED_SIZE },
{ GLX_GREEN_SIZE, EGL_GREEN_SIZE }, { GLX_GREEN_SIZE, EGL_GREEN_SIZE },
{ GLX_BLUE_SIZE, EGL_BLUE_SIZE }, { GLX_BLUE_SIZE, EGL_BLUE_SIZE },
{ GLX_ALPHA_SIZE, EGL_ALPHA_SIZE }, { GLX_ALPHA_SIZE, EGL_ALPHA_SIZE },
{ GLX_DEPTH_SIZE, EGL_DEPTH_SIZE }, { GLX_DEPTH_SIZE, EGL_DEPTH_SIZE },
{ GLX_STENCIL_SIZE, EGL_STENCIL_SIZE }, { GLX_STENCIL_SIZE, EGL_STENCIL_SIZE },
{ GLX_ACCUM_RED_SIZE, 0 },
{ GLX_ACCUM_GREEN_SIZE, 0 },
{ GLX_ACCUM_BLUE_SIZE, 0 },
{ GLX_ACCUM_ALPHA_SIZE, 0 },
{ GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS }, { GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS },
{ GLX_SAMPLES, EGL_SAMPLES }, { GLX_SAMPLES, EGL_SAMPLES },
{ GLX_FBCONFIG_ID, 0 },
/* GLX_EXT_visual_rating */
{ GLX_VISUAL_CAVEAT_EXT, EGL_CONFIG_CAVEAT }
}; };
static EGLBoolean static EGLBoolean
convert_visual(Display *dpy, XVisualInfo *vinfo, convert_visual(Display *dpy, XVisualInfo *vinfo,
struct GLX_egl_config *GLX_conf) struct GLX_egl_config *GLX_conf)
{ {
int err, attr, egl_attr, val; int err, attr, val;
unsigned i; unsigned i;
EGLint conformant, config_caveat, surface_type;
/* the visual must support OpenGL */ /* the visual must support OpenGL and RGBA buffer */
err = glXGetConfig(dpy, vinfo, GLX_USE_GL, &val); err = glXGetConfig(dpy, vinfo, GLX_USE_GL, &val);
if (!err && val)
err = glXGetConfig(dpy, vinfo, GLX_RGBA, &val);
if (err || !val) if (err || !val)
return EGL_FALSE; return EGL_FALSE;
/* must know whether it is double-buffered */
err = glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &val);
if (err)
return EGL_FALSE;
GLX_conf->double_buffered = val;
GLX_conf->Base.RenderableType = EGL_OPENGL_BIT;
GLX_conf->Base.Conformant = EGL_OPENGL_BIT;
GLX_conf->Base.SurfaceType = EGL_WINDOW_BIT;
/* pixmap surfaces must be single-buffered in EGL */
if (!GLX_conf->double_buffered)
GLX_conf->Base.SurfaceType |= EGL_PIXMAP_BIT;
GLX_conf->Base.NativeVisualID = vinfo->visualid;
GLX_conf->Base.NativeVisualType = vinfo->class;
GLX_conf->Base.NativeRenderable = EGL_TRUE;
for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) { for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) {
EGLint egl_attr, egl_val;
attr = visual_attributes[i].attr; attr = visual_attributes[i].attr;
egl_attr = fbconfig_attributes[i].egl_attr; egl_attr = visual_attributes[i].egl_attr;
if (!egl_attr)
continue;
err = glXGetConfig(dpy, vinfo, attr, &val); err = glXGetConfig(dpy, vinfo, attr, &val);
if (err) { if (err) {
if (err == GLX_BAD_ATTRIBUTE) { if (err == GLX_BAD_ATTRIBUTE) {
@ -265,41 +350,26 @@ convert_visual(Display *dpy, XVisualInfo *vinfo,
break; break;
} }
_eglSetConfigKey(&GLX_conf->Base, egl_attr, val); switch (egl_attr) {
case EGL_CONFIG_CAVEAT:
egl_val = EGL_NONE;
if (val == GLX_SLOW_VISUAL_EXT) {
egl_val = EGL_SLOW_CONFIG;
}
else if (val == GLX_NON_CONFORMANT_VISUAL_EXT) {
GLX_conf->Base.Conformant &= ~EGL_OPENGL_BIT;
egl_val = EGL_NONE;
}
break;
break;
default:
egl_val = val;
break;
}
_eglSetConfigKey(&GLX_conf->Base, egl_attr, egl_val);
} }
if (err)
return EGL_FALSE;
glXGetConfig(dpy, vinfo, GLX_RGBA, &val); return (err) ? EGL_FALSE : EGL_TRUE;
if (!val)
return EGL_FALSE;
conformant = EGL_OPENGL_BIT;
glXGetConfig(dpy, vinfo, GLX_VISUAL_CAVEAT_EXT, &val);
if (val == GLX_SLOW_CONFIG)
config_caveat = EGL_SLOW_CONFIG;
if (val == GLX_NON_CONFORMANT_CONFIG)
conformant &= ~EGL_OPENGL_BIT;
if (!(conformant & EGL_OPENGL_ES_BIT))
config_caveat = EGL_NON_CONFORMANT_CONFIG;
_eglSetConfigKey(&GLX_conf->Base, EGL_CONFIG_CAVEAT, config_caveat);
_eglSetConfigKey(&GLX_conf->Base, EGL_NATIVE_VISUAL_ID, vinfo->visualid);
_eglSetConfigKey(&GLX_conf->Base, EGL_NATIVE_VISUAL_TYPE, vinfo->class);
/* pixmap and pbuffer surfaces must be single-buffered in EGL */
glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &val);
GLX_conf->double_buffered = val;
surface_type = EGL_WINDOW_BIT;
/* pixmap surfaces must be single-buffered in EGL */
if (!GLX_conf->double_buffered)
surface_type |= EGL_PIXMAP_BIT;
_eglSetConfigKey(&GLX_conf->Base, EGL_SURFACE_TYPE, surface_type);
_eglSetConfigKey(&GLX_conf->Base, EGL_NATIVE_RENDERABLE, EGL_TRUE);
return EGL_TRUE;
} }
@ -307,30 +377,31 @@ static void
fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf) fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf)
{ {
_EGLConfig *conf = &GLX_conf->Base; _EGLConfig *conf = &GLX_conf->Base;
EGLint surface_type, r, g, b, a;
surface_type = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) { if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) {
/* some GLX impls do not like single-buffered window surface */ /* some GLX impls do not like single-buffered window surface */
surface_type &= ~EGL_WINDOW_BIT; conf->SurfaceType &= ~EGL_WINDOW_BIT;
/* pbuffer bit is usually not set */ /* pbuffer bit is usually not set */
if (GLX_dpy->have_pbuffer) if (GLX_dpy->have_pbuffer)
surface_type |= EGL_PBUFFER_BIT; conf->SurfaceType |= EGL_PBUFFER_BIT;
SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type);
} }
/* no visual attribs unless window bit is set */ /* no visual attribs unless window bit is set */
if (!(surface_type & EGL_WINDOW_BIT)) { if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, 0); conf->NativeVisualID = 0;
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_NONE); conf->NativeVisualType = EGL_NONE;
}
if (conf->TransparentType != EGL_TRANSPARENT_RGB) {
/* some impls set them to -1 (GLX_DONT_CARE) */
conf->TransparentRedValue = 0;
conf->TransparentGreenValue = 0;
conf->TransparentBlueValue = 0;
} }
/* make sure buffer size is set correctly */ /* make sure buffer size is set correctly */
r = GET_CONFIG_ATTRIB(conf, EGL_RED_SIZE); conf->BufferSize =
g = GET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE); conf->RedSize + conf->GreenSize + conf->BlueSize + conf->AlphaSize;
b = GET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE);
a = GET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE);
SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, r + g + b + a);
} }
@ -381,7 +452,7 @@ create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy,
memcpy(GLX_conf, &template, sizeof(template)); memcpy(GLX_conf, &template, sizeof(template));
GLX_conf->index = i; GLX_conf->index = i;
_eglAddConfig(dpy, &GLX_conf->Base); _eglLinkConfig(&GLX_conf->Base);
id++; id++;
} }
} }
@ -606,14 +677,16 @@ GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf); struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf); struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx); struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
_EGLContext *old_ctx;
_EGLSurface *old_dsurf, *old_rsurf;
GLXDrawable ddraw, rdraw; GLXDrawable ddraw, rdraw;
GLXContext cctx; GLXContext cctx;
EGLBoolean ret = EGL_FALSE; EGLBoolean ret = EGL_FALSE;
(void) drv; (void) drv;
/* bind the new context and return the "orphaned" one */ /* make new bindings */
if (!_eglBindContext(&ctx, &dsurf, &rsurf)) if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
return EGL_FALSE; return EGL_FALSE;
ddraw = (GLX_dsurf) ? GLX_dsurf->glx_drawable : None; ddraw = (GLX_dsurf) ? GLX_dsurf->glx_drawable : None;
@ -626,13 +699,27 @@ GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
ret = glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx); ret = glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx);
if (ret) { if (ret) {
if (dsurf && !_eglIsSurfaceLinked(dsurf)) if (_eglPutSurface(old_dsurf))
destroy_surface(disp, dsurf); destroy_surface(disp, old_dsurf);
if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(rsurf)) if (_eglPutSurface(old_rsurf))
destroy_surface(disp, rsurf); destroy_surface(disp, old_rsurf);
/* no destroy? */
_eglPutContext(old_ctx);
} }
else { else {
_eglBindContext(&ctx, &dsurf, &rsurf); /* undo the previous _eglBindContext */
_eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
assert(&GLX_ctx->Base == ctx &&
&GLX_dsurf->Base == dsurf &&
&GLX_rsurf->Base == rsurf);
_eglPutSurface(dsurf);
_eglPutSurface(rsurf);
_eglPutContext(ctx);
_eglPutSurface(old_dsurf);
_eglPutSurface(old_rsurf);
_eglPutContext(old_ctx);
} }
return ret; return ret;
@ -836,7 +923,7 @@ GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
{ {
(void) drv; (void) drv;
if (!_eglIsSurfaceBound(surf)) if (_eglPutSurface(surf))
destroy_surface(disp, surf); destroy_surface(disp, surf);
return EGL_TRUE; return EGL_TRUE;

View file

@ -36,6 +36,7 @@ SOURCES = \
eglcurrent.c \ eglcurrent.c \
egldisplay.c \ egldisplay.c \
egldriver.c \ egldriver.c \
eglfallbacks.c \
eglglobals.c \ eglglobals.c \
eglimage.c \ eglimage.c \
egllog.c \ egllog.c \

View file

@ -28,6 +28,7 @@ if env['platform'] != 'winddk':
'eglcurrent.c', 'eglcurrent.c',
'egldisplay.c', 'egldisplay.c',
'egldriver.c', 'egldriver.c',
'eglfallbacks.c',
'eglglobals.c', 'eglglobals.c',
'eglimage.c', 'eglimage.c',
'egllog.c', 'egllog.c',

View file

@ -416,7 +416,7 @@ eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list,
RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_NO_CONTEXT); RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
context = drv->API.CreateContext(drv, disp, conf, share, attrib_list); context = drv->API.CreateContext(drv, disp, conf, share, attrib_list);
ret = (context) ? _eglLinkContext(context, disp) : EGL_NO_CONTEXT; ret = (context) ? _eglLinkContext(context) : EGL_NO_CONTEXT;
RETURN_EGL_EVAL(disp, ret); RETURN_EGL_EVAL(disp, ret);
} }
@ -515,7 +515,7 @@ eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
surf = drv->API.CreateWindowSurface(drv, disp, conf, window, attrib_list); surf = drv->API.CreateWindowSurface(drv, disp, conf, window, attrib_list);
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE; ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
RETURN_EGL_EVAL(disp, ret); RETURN_EGL_EVAL(disp, ret);
} }
@ -536,7 +536,7 @@ eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE); RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
surf = drv->API.CreatePixmapSurface(drv, disp, conf, pixmap, attrib_list); surf = drv->API.CreatePixmapSurface(drv, disp, conf, pixmap, attrib_list);
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE; ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
RETURN_EGL_EVAL(disp, ret); RETURN_EGL_EVAL(disp, ret);
} }
@ -555,7 +555,7 @@ eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
_EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv); _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
surf = drv->API.CreatePbufferSurface(drv, disp, conf, attrib_list); surf = drv->API.CreatePbufferSurface(drv, disp, conf, attrib_list);
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE; ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
RETURN_EGL_EVAL(disp, ret); RETURN_EGL_EVAL(disp, ret);
} }
@ -648,11 +648,12 @@ eglSwapInterval(EGLDisplay dpy, EGLint interval)
_EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
if (!ctx || !_eglIsContextLinked(ctx) || ctx->Resource.Display != disp) if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
ctx->Resource.Display != disp)
RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_FALSE); RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_FALSE);
surf = ctx->DrawSurface; surf = ctx->DrawSurface;
if (!_eglIsSurfaceLinked(surf)) if (_eglGetSurfaceHandle(surf) == EGL_NO_SURFACE)
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE); RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
ret = drv->API.SwapInterval(drv, disp, surf, interval); ret = drv->API.SwapInterval(drv, disp, surf, interval);
@ -673,7 +674,8 @@ eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
_EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv);
/* surface must be bound to current context in EGL 1.4 */ /* surface must be bound to current context in EGL 1.4 */
if (!ctx || !_eglIsContextLinked(ctx) || surf != ctx->DrawSurface) if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
surf != ctx->DrawSurface)
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE); RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
ret = drv->API.SwapBuffers(drv, disp, surf); ret = drv->API.SwapBuffers(drv, disp, surf);
@ -714,7 +716,8 @@ eglWaitClient(void)
_eglLockMutex(&disp->Mutex); _eglLockMutex(&disp->Mutex);
/* let bad current context imply bad current surface */ /* let bad current context imply bad current surface */
if (!_eglIsContextLinked(ctx) || !_eglIsSurfaceLinked(ctx->DrawSurface)) if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
_eglGetSurfaceHandle(ctx->DrawSurface) == EGL_NO_SURFACE)
RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE); RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
/* a valid current context implies an initialized current display */ /* a valid current context implies an initialized current display */
@ -763,7 +766,8 @@ eglWaitNative(EGLint engine)
_eglLockMutex(&disp->Mutex); _eglLockMutex(&disp->Mutex);
/* let bad current context imply bad current surface */ /* let bad current context imply bad current surface */
if (!_eglIsContextLinked(ctx) || !_eglIsSurfaceLinked(ctx->DrawSurface)) if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
_eglGetSurfaceHandle(ctx->DrawSurface) == EGL_NO_SURFACE)
RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE); RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
/* a valid current context implies an initialized current display */ /* a valid current context implies an initialized current display */
@ -1043,7 +1047,7 @@ eglCreateScreenSurfaceMESA(EGLDisplay dpy, EGLConfig config,
_EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv); _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
surf = drv->API.CreateScreenSurfaceMESA(drv, disp, conf, attrib_list); surf = drv->API.CreateScreenSurfaceMESA(drv, disp, conf, attrib_list);
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE; ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
RETURN_EGL_EVAL(disp, ret); RETURN_EGL_EVAL(disp, ret);
} }
@ -1235,7 +1239,7 @@ eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype,
surf = drv->API.CreatePbufferFromClientBuffer(drv, disp, buftype, buffer, surf = drv->API.CreatePbufferFromClientBuffer(drv, disp, buftype, buffer,
conf, attrib_list); conf, attrib_list);
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE; ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
RETURN_EGL_EVAL(disp, ret); RETURN_EGL_EVAL(disp, ret);
} }
@ -1298,7 +1302,7 @@ eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
img = drv->API.CreateImageKHR(drv, img = drv->API.CreateImageKHR(drv,
disp, context, target, buffer, attr_list); disp, context, target, buffer, attr_list);
ret = (img) ? _eglLinkImage(img, disp) : EGL_NO_IMAGE_KHR; ret = (img) ? _eglLinkImage(img) : EGL_NO_IMAGE_KHR;
RETURN_EGL_EVAL(disp, ret); RETURN_EGL_EVAL(disp, ret);
} }
@ -1344,7 +1348,7 @@ eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
RETURN_EGL_EVAL(disp, EGL_NO_SYNC_KHR); RETURN_EGL_EVAL(disp, EGL_NO_SYNC_KHR);
sync = drv->API.CreateSyncKHR(drv, disp, type, attrib_list); sync = drv->API.CreateSyncKHR(drv, disp, type, attrib_list);
ret = (sync) ? _eglLinkSync(sync, disp) : EGL_NO_SYNC_KHR; ret = (sync) ? _eglLinkSync(sync) : EGL_NO_SYNC_KHR;
RETURN_EGL_EVAL(disp, ret); RETURN_EGL_EVAL(disp, ret);
} }
@ -1437,7 +1441,8 @@ eglSwapBuffersRegionNOK(EGLDisplay dpy, EGLSurface surface,
RETURN_EGL_EVAL(disp, EGL_FALSE); RETURN_EGL_EVAL(disp, EGL_FALSE);
/* surface must be bound to current context in EGL 1.4 */ /* surface must be bound to current context in EGL 1.4 */
if (!ctx || !_eglIsContextLinked(ctx) || surf != ctx->DrawSurface) if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
surf != ctx->DrawSurface)
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE); RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
ret = drv->API.SwapBuffersRegionNOK(drv, disp, surf, numRects, rects); ret = drv->API.SwapBuffersRegionNOK(drv, disp, surf, numRects, rects);
@ -1463,7 +1468,7 @@ eglCreateDRMImageMESA(EGLDisplay dpy, const EGLint *attr_list)
RETURN_EGL_EVAL(disp, EGL_NO_IMAGE_KHR); RETURN_EGL_EVAL(disp, EGL_NO_IMAGE_KHR);
img = drv->API.CreateDRMImageMESA(drv, disp, attr_list); img = drv->API.CreateDRMImageMESA(drv, disp, attr_list);
ret = (img) ? _eglLinkImage(img, disp) : EGL_NO_IMAGE_KHR; ret = (img) ? _eglLinkImage(img) : EGL_NO_IMAGE_KHR;
RETURN_EGL_EVAL(disp, ret); RETURN_EGL_EVAL(disp, ret);
} }

View file

@ -24,34 +24,34 @@
* IDs are from 1 to N respectively. * IDs are from 1 to N respectively.
*/ */
void void
_eglInitConfig(_EGLConfig *config, _EGLDisplay *dpy, EGLint id) _eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id)
{ {
memset(config, 0, sizeof(*config)); memset(conf, 0, sizeof(*conf));
config->Display = dpy; conf->Display = dpy;
/* some attributes take non-zero default values */ /* some attributes take non-zero default values */
SET_CONFIG_ATTRIB(config, EGL_CONFIG_ID, id); conf->ConfigID = id;
SET_CONFIG_ATTRIB(config, EGL_CONFIG_CAVEAT, EGL_NONE); conf->ConfigCaveat = EGL_NONE;
SET_CONFIG_ATTRIB(config, EGL_TRANSPARENT_TYPE, EGL_NONE); conf->TransparentType = EGL_NONE;
SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, EGL_NONE); conf->NativeVisualType = EGL_NONE;
#ifdef EGL_VERSION_1_2 conf->ColorBufferType = EGL_RGB_BUFFER;
SET_CONFIG_ATTRIB(config, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
#endif /* EGL_VERSION_1_2 */
} }
/** /**
* Link a config to a display and return the handle of the link. * Link a config to its display and return the handle of the link.
* The handle can be passed to client directly. * The handle can be passed to client directly.
* *
* Note that we just save the ptr to the config (we don't copy the config). * Note that we just save the ptr to the config (we don't copy the config).
*/ */
EGLConfig PUBLIC EGLConfig
_eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf) _eglLinkConfig(_EGLConfig *conf)
{ {
_EGLDisplay *dpy = conf->Display;
/* sanity check */ /* sanity check */
assert(GET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID) > 0); assert(dpy && conf->ConfigID > 0);
if (!dpy->Configs) { if (!dpy->Configs) {
dpy->Configs = _eglCreateArray("Config", 16); dpy->Configs = _eglCreateArray("Config", 16);
@ -59,23 +59,29 @@ _eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf)
return (EGLConfig) NULL; return (EGLConfig) NULL;
} }
conf->Display = dpy;
_eglAppendArray(dpy->Configs, (void *) conf); _eglAppendArray(dpy->Configs, (void *) conf);
return (EGLConfig) conf; return (EGLConfig) conf;
} }
EGLBoolean /**
_eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy) * Lookup a handle to find the linked config.
* Return NULL if the handle has no corresponding linked config.
*/
_EGLConfig *
_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy)
{ {
_EGLConfig *conf; _EGLConfig *conf;
if (!dpy)
return NULL;
conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config); conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config);
if (conf) if (conf)
assert(conf->Display == dpy); assert(conf->Display == dpy);
return (conf != NULL); return conf;
} }
@ -104,6 +110,7 @@ static const struct {
EGLint default_value; EGLint default_value;
} _eglValidationTable[] = } _eglValidationTable[] =
{ {
/* core */
{ EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER, { EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST, ATTRIB_CRITERION_ATLEAST,
0 }, 0 },
@ -200,22 +207,13 @@ static const struct {
{ EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER, { EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT, ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE }, EGL_DONT_CARE },
/* these are not real attributes */
{ EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO, { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO,
ATTRIB_CRITERION_SPECIAL, ATTRIB_CRITERION_SPECIAL,
EGL_NONE }, EGL_NONE },
/* there is a gap before EGL_SAMPLES */ /* extensions */
{ 0x3030, ATTRIB_TYPE_PSEUDO,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_NONE, ATTRIB_TYPE_PSEUDO,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN, { EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT, ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE }, EGL_DONT_CARE }
}; };
@ -232,18 +230,13 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
{ {
EGLint i, attr, val; EGLint i, attr, val;
EGLBoolean valid = EGL_TRUE; EGLBoolean valid = EGL_TRUE;
EGLint red_size = 0, green_size = 0, blue_size = 0, luminance_size = 0;
EGLint alpha_size = 0, buffer_size = 0;
/* all attributes should have been listed */
assert(ARRAY_SIZE(_eglValidationTable) == _EGL_CONFIG_NUM_ATTRIBS);
/* check attributes by their types */ /* check attributes by their types */
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
EGLint mask; EGLint mask;
attr = _eglValidationTable[i].attr; attr = _eglValidationTable[i].attr;
val = GET_CONFIG_ATTRIB(conf, attr); val = _eglGetConfigKey(conf, attr);
switch (_eglValidationTable[i].type) { switch (_eglValidationTable[i].type) {
case ATTRIB_TYPE_INTEGER: case ATTRIB_TYPE_INTEGER:
@ -255,31 +248,15 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
break; break;
case EGL_SAMPLE_BUFFERS: case EGL_SAMPLE_BUFFERS:
/* there can be at most 1 sample buffer */ /* there can be at most 1 sample buffer */
if (val > 1) if (val > 1 || val < 0)
valid = EGL_FALSE; valid = EGL_FALSE;
break; break;
case EGL_RED_SIZE: default:
red_size = val;
break;
case EGL_GREEN_SIZE:
green_size = val;
break;
case EGL_BLUE_SIZE:
blue_size = val;
break;
case EGL_LUMINANCE_SIZE:
luminance_size = val;
break;
case EGL_ALPHA_SIZE:
alpha_size = val;
break;
case EGL_BUFFER_SIZE:
buffer_size = val;
break;
}
if (val < 0) if (val < 0)
valid = EGL_FALSE; valid = EGL_FALSE;
break; break;
}
break;
case ATTRIB_TYPE_BOOLEAN: case ATTRIB_TYPE_BOOLEAN:
if (val != EGL_TRUE && val != EGL_FALSE) if (val != EGL_TRUE && val != EGL_FALSE)
valid = EGL_FALSE; valid = EGL_FALSE;
@ -366,17 +343,18 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
/* now check for conflicting attribute values */ /* now check for conflicting attribute values */
switch (GET_CONFIG_ATTRIB(conf, EGL_COLOR_BUFFER_TYPE)) { switch (conf->ColorBufferType) {
case EGL_RGB_BUFFER: case EGL_RGB_BUFFER:
if (luminance_size) if (conf->LuminanceSize)
valid = EGL_FALSE; valid = EGL_FALSE;
if (red_size + green_size + blue_size + alpha_size != buffer_size) if (conf->RedSize + conf->GreenSize +
conf->BlueSize + conf->AlphaSize != conf->BufferSize)
valid = EGL_FALSE; valid = EGL_FALSE;
break; break;
case EGL_LUMINANCE_BUFFER: case EGL_LUMINANCE_BUFFER:
if (red_size || green_size || blue_size) if (conf->RedSize || conf->GreenSize || conf->BlueSize)
valid = EGL_FALSE; valid = EGL_FALSE;
if (luminance_size + alpha_size != buffer_size) if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
valid = EGL_FALSE; valid = EGL_FALSE;
break; break;
} }
@ -385,23 +363,19 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
return EGL_FALSE; return EGL_FALSE;
} }
val = GET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS); if (!conf->SampleBuffers && conf->Samples)
if (!val && GET_CONFIG_ATTRIB(conf, EGL_SAMPLES))
valid = EGL_FALSE; valid = EGL_FALSE;
if (!valid) { if (!valid) {
_eglLog(_EGL_DEBUG, "conflicting samples and sample buffers"); _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
return EGL_FALSE; return EGL_FALSE;
} }
val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE); if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
if (!(val & EGL_WINDOW_BIT)) { if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
if (GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID) != 0 ||
GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE) != EGL_NONE)
valid = EGL_FALSE; valid = EGL_FALSE;
} }
if (!(val & EGL_PBUFFER_BIT)) { if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
if (GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB) || if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA))
valid = EGL_FALSE; valid = EGL_FALSE;
} }
if (!valid) { if (!valid) {
@ -433,11 +407,11 @@ _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
continue; continue;
attr = _eglValidationTable[i].attr; attr = _eglValidationTable[i].attr;
cmp = GET_CONFIG_ATTRIB(criteria, attr); cmp = _eglGetConfigKey(criteria, attr);
if (cmp == EGL_DONT_CARE) if (cmp == EGL_DONT_CARE)
continue; continue;
val = GET_CONFIG_ATTRIB(conf, attr); val = _eglGetConfigKey(conf, attr);
switch (_eglValidationTable[i].criterion) { switch (_eglValidationTable[i].criterion) {
case ATTRIB_CRITERION_EXACT: case ATTRIB_CRITERION_EXACT:
if (val != cmp) if (val != cmp)
@ -478,16 +452,11 @@ _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
static INLINE EGLBoolean static INLINE EGLBoolean
_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
{ {
if (_eglIndexConfig(conf, attr) < 0) if (_eglOffsetOfConfig(attr) < 0)
return EGL_FALSE; return EGL_FALSE;
/* there are some holes in the range */
switch (attr) { switch (attr) {
case 0x3030 /* a gap before EGL_SAMPLES */:
case EGL_NONE:
#ifdef EGL_VERSION_1_4
case EGL_MATCH_NATIVE_PIXMAP: case EGL_MATCH_NATIVE_PIXMAP:
#endif
return EGL_FALSE; return EGL_FALSE;
case EGL_Y_INVERTED_NOK: case EGL_Y_INVERTED_NOK:
return conf->Display->Extensions.NOK_texture_from_pixmap; return conf->Display->Extensions.NOK_texture_from_pixmap;
@ -503,18 +472,18 @@ _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
* Return EGL_FALSE if any of the attribute is invalid. * Return EGL_FALSE if any of the attribute is invalid.
*/ */
EGLBoolean EGLBoolean
_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list) _eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
const EGLint *attrib_list)
{ {
EGLint attr, val, i; EGLint attr, val, i;
EGLint config_id = 0, level = 0;
EGLBoolean has_native_visual_type = EGL_FALSE; _eglInitConfig(conf, dpy, EGL_DONT_CARE);
EGLBoolean has_transparent_color = EGL_FALSE;
/* reset to default values */ /* reset to default values */
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
attr = _eglValidationTable[i].attr; attr = _eglValidationTable[i].attr;
val = _eglValidationTable[i].default_value; val = _eglValidationTable[i].default_value;
SET_CONFIG_ATTRIB(conf, attr, val); _eglSetConfigKey(conf, attr, val);
} }
/* parse the list */ /* parse the list */
@ -525,58 +494,32 @@ _eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list)
if (!_eglIsConfigAttribValid(conf, attr)) if (!_eglIsConfigAttribValid(conf, attr))
return EGL_FALSE; return EGL_FALSE;
SET_CONFIG_ATTRIB(conf, attr, val); _eglSetConfigKey(conf, attr, val);
/* rememeber some attributes for post-processing */
switch (attr) {
case EGL_CONFIG_ID:
config_id = val;
break;
case EGL_LEVEL:
level = val;
break;
case EGL_NATIVE_VISUAL_TYPE:
has_native_visual_type = EGL_TRUE;
break;
case EGL_TRANSPARENT_RED_VALUE:
case EGL_TRANSPARENT_GREEN_VALUE:
case EGL_TRANSPARENT_BLUE_VALUE:
has_transparent_color = EGL_TRUE;
break;
default:
break;
}
} }
if (!_eglValidateConfig(conf, EGL_TRUE)) if (!_eglValidateConfig(conf, EGL_TRUE))
return EGL_FALSE; return EGL_FALSE;
/* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */ /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */
if (level == EGL_DONT_CARE) if (conf->Level == EGL_DONT_CARE)
return EGL_FALSE; return EGL_FALSE;
/* ignore other attributes when EGL_CONFIG_ID is given */ /* ignore other attributes when EGL_CONFIG_ID is given */
if (config_id > 0) { if (conf->ConfigID != EGL_DONT_CARE) {
_eglResetConfigKeys(conf, EGL_DONT_CARE); for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
SET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID, config_id); attr = _eglValidationTable[i].attr;
if (attr != EGL_CONFIG_ID)
_eglSetConfigKey(conf, attr, EGL_DONT_CARE);
}
} }
else { else {
if (has_native_visual_type) { if (!(conf->SurfaceType & EGL_WINDOW_BIT))
val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE); conf->NativeVisualType = EGL_DONT_CARE;
if (!(val & EGL_WINDOW_BIT))
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE);
}
if (has_transparent_color) { if (conf->TransparentType == EGL_NONE) {
val = GET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE); conf->TransparentRedValue = EGL_DONT_CARE;
if (val == EGL_NONE) { conf->TransparentGreenValue = EGL_DONT_CARE;
SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE, conf->TransparentBlueValue = EGL_DONT_CARE;
EGL_DONT_CARE);
SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE,
EGL_DONT_CARE);
SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE,
EGL_DONT_CARE);
}
} }
} }
@ -610,7 +553,6 @@ _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
EGL_ALPHA_MASK_SIZE, EGL_ALPHA_MASK_SIZE,
}; };
EGLint val1, val2; EGLint val1, val2;
EGLBoolean rgb_buffer;
EGLint i; EGLint i;
if (conf1 == conf2) if (conf1 == conf2)
@ -619,44 +561,41 @@ _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
/* the enum values have the desired ordering */ /* the enum values have the desired ordering */
assert(EGL_NONE < EGL_SLOW_CONFIG); assert(EGL_NONE < EGL_SLOW_CONFIG);
assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_CAVEAT); val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_CAVEAT); if (val1)
if (val1 != val2) return val1;
return (val1 - val2);
/* the enum values have the desired ordering */ /* the enum values have the desired ordering */
assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
val1 = GET_CONFIG_ATTRIB(conf1, EGL_COLOR_BUFFER_TYPE); val1 = conf1->ColorBufferType - conf2->ColorBufferType;
val2 = GET_CONFIG_ATTRIB(conf2, EGL_COLOR_BUFFER_TYPE); if (val1)
if (val1 != val2) return val1;
return (val1 - val2);
rgb_buffer = (val1 == EGL_RGB_BUFFER);
if (criteria) { if (criteria) {
val1 = val2 = 0; val1 = val2 = 0;
if (rgb_buffer) { if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
if (GET_CONFIG_ATTRIB(criteria, EGL_RED_SIZE) > 0) { if (criteria->RedSize > 0) {
val1 += GET_CONFIG_ATTRIB(conf1, EGL_RED_SIZE); val1 += conf1->RedSize;
val2 += GET_CONFIG_ATTRIB(conf2, EGL_RED_SIZE); val2 += conf2->RedSize;
} }
if (GET_CONFIG_ATTRIB(criteria, EGL_GREEN_SIZE) > 0) { if (criteria->GreenSize > 0) {
val1 += GET_CONFIG_ATTRIB(conf1, EGL_GREEN_SIZE); val1 += conf1->GreenSize;
val2 += GET_CONFIG_ATTRIB(conf2, EGL_GREEN_SIZE); val2 += conf2->GreenSize;
} }
if (GET_CONFIG_ATTRIB(criteria, EGL_BLUE_SIZE) > 0) { if (criteria->BlueSize > 0) {
val1 += GET_CONFIG_ATTRIB(conf1, EGL_BLUE_SIZE); val1 += conf1->BlueSize;
val2 += GET_CONFIG_ATTRIB(conf2, EGL_BLUE_SIZE); val2 += conf2->BlueSize;
} }
} }
else { else {
if (GET_CONFIG_ATTRIB(criteria, EGL_LUMINANCE_SIZE) > 0) { if (criteria->LuminanceSize > 0) {
val1 += GET_CONFIG_ATTRIB(conf1, EGL_LUMINANCE_SIZE); val1 += conf1->LuminanceSize;
val2 += GET_CONFIG_ATTRIB(conf2, EGL_LUMINANCE_SIZE); val2 += conf2->LuminanceSize;
} }
} }
if (GET_CONFIG_ATTRIB(criteria, EGL_ALPHA_SIZE) > 0) { if (criteria->AlphaSize > 0) {
val1 += GET_CONFIG_ATTRIB(conf1, EGL_ALPHA_SIZE); val1 += conf1->AlphaSize;
val2 += GET_CONFIG_ATTRIB(conf2, EGL_ALPHA_SIZE); val2 += conf2->AlphaSize;
} }
} }
else { else {
@ -669,24 +608,15 @@ _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
return (val2 - val1); return (val2 - val1);
for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
val1 = GET_CONFIG_ATTRIB(conf1, compare_attribs[i]); val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
val2 = GET_CONFIG_ATTRIB(conf2, compare_attribs[i]); val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
if (val1 != val2) if (val1 != val2)
return (val1 - val2); return (val1 - val2);
} }
/* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
if (compare_id) { return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_ID);
val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_ID);
assert(val1 != val2);
}
else {
val1 = val2 = 0;
}
return (val1 - val2);
} }
@ -764,8 +694,7 @@ _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
if (!num_configs) if (!num_configs)
return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
_eglInitConfig(&criteria, disp, 0); if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
if (!_eglParseConfigAttribList(&criteria, attrib_list))
return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
configList = (_EGLConfig **) _eglFilterArray(disp->Configs, &count, configList = (_EGLConfig **) _eglFilterArray(disp->Configs, &count,
@ -802,7 +731,7 @@ _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
if (!value) if (!value)
return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
*value = GET_CONFIG_ATTRIB(conf, attribute); *value = _eglGetConfigKey(conf, attribute);
return EGL_TRUE; return EGL_TRUE;
} }

View file

@ -6,69 +6,103 @@
#include "egltypedefs.h" #include "egltypedefs.h"
#define _EGL_CONFIG_FIRST_ATTRIB EGL_BUFFER_SIZE /* update _eglValidationTable and _eglOffsetOfConfig before updating this
#define _EGL_CONFIG_LAST_ATTRIB EGL_CONFORMANT * struct */
#define _EGL_CONFIG_NUM_CONTIGUOUS_ATTRIBS \
(_EGL_CONFIG_LAST_ATTRIB - _EGL_CONFIG_FIRST_ATTRIB + 1)
/* Attributes outside the contiguous block:
*
* EGL_Y_INVERTED_NOK
*/
#define _EGL_CONFIG_FIRST_EXTRA_ATTRIB _EGL_CONFIG_NUM_CONTIGUOUS_ATTRIBS
#define _EGL_CONFIG_NUM_EXTRA_ATTRIBS 1
#define _EGL_CONFIG_NUM_ATTRIBS \
_EGL_CONFIG_NUM_CONTIGUOUS_ATTRIBS + _EGL_CONFIG_NUM_EXTRA_ATTRIBS
struct _egl_config struct _egl_config
{ {
_EGLDisplay *Display; _EGLDisplay *Display;
EGLint Storage[_EGL_CONFIG_NUM_ATTRIBS];
/* core */
EGLint BufferSize;
EGLint AlphaSize;
EGLint BlueSize;
EGLint GreenSize;
EGLint RedSize;
EGLint DepthSize;
EGLint StencilSize;
EGLint ConfigCaveat;
EGLint ConfigID;
EGLint Level;
EGLint MaxPbufferHeight;
EGLint MaxPbufferPixels;
EGLint MaxPbufferWidth;
EGLint NativeRenderable;
EGLint NativeVisualID;
EGLint NativeVisualType;
EGLint Samples;
EGLint SampleBuffers;
EGLint SurfaceType;
EGLint TransparentType;
EGLint TransparentBlueValue;
EGLint TransparentGreenValue;
EGLint TransparentRedValue;
EGLint BindToTextureRGB;
EGLint BindToTextureRGBA;
EGLint MinSwapInterval;
EGLint MaxSwapInterval;
EGLint LuminanceSize;
EGLint AlphaMaskSize;
EGLint ColorBufferType;
EGLint RenderableType;
EGLint MatchNativePixmap;
EGLint Conformant;
/* extensions */
EGLint YInvertedNOK;
}; };
/** /**
* Macros for source level compatibility. * Map an EGL attribute enum to the offset of the member in _EGLConfig.
*/
#define SET_CONFIG_ATTRIB(CONF, ATTR, VAL) _eglSetConfigKey(CONF, ATTR, VAL)
#define GET_CONFIG_ATTRIB(CONF, ATTR) _eglGetConfigKey(CONF, ATTR)
/**
* Given a key, return an index into the storage of the config.
* Return -1 if the key is invalid.
*/ */
static INLINE EGLint static INLINE EGLint
_eglIndexConfig(const _EGLConfig *conf, EGLint key) _eglOffsetOfConfig(EGLint attr)
{ {
(void) conf; switch (attr) {
if (key >= _EGL_CONFIG_FIRST_ATTRIB && #define ATTRIB_MAP(attr, memb) case attr: return offsetof(_EGLConfig, memb)
key < _EGL_CONFIG_FIRST_ATTRIB + _EGL_CONFIG_NUM_CONTIGUOUS_ATTRIBS) /* core */
return key - _EGL_CONFIG_FIRST_ATTRIB; ATTRIB_MAP(EGL_BUFFER_SIZE, BufferSize);
ATTRIB_MAP(EGL_ALPHA_SIZE, AlphaSize);
switch (key) { ATTRIB_MAP(EGL_BLUE_SIZE, BlueSize);
case EGL_Y_INVERTED_NOK: ATTRIB_MAP(EGL_GREEN_SIZE, GreenSize);
return _EGL_CONFIG_FIRST_EXTRA_ATTRIB; ATTRIB_MAP(EGL_RED_SIZE, RedSize);
ATTRIB_MAP(EGL_DEPTH_SIZE, DepthSize);
ATTRIB_MAP(EGL_STENCIL_SIZE, StencilSize);
ATTRIB_MAP(EGL_CONFIG_CAVEAT, ConfigCaveat);
ATTRIB_MAP(EGL_CONFIG_ID, ConfigID);
ATTRIB_MAP(EGL_LEVEL, Level);
ATTRIB_MAP(EGL_MAX_PBUFFER_HEIGHT, MaxPbufferHeight);
ATTRIB_MAP(EGL_MAX_PBUFFER_PIXELS, MaxPbufferPixels);
ATTRIB_MAP(EGL_MAX_PBUFFER_WIDTH, MaxPbufferWidth);
ATTRIB_MAP(EGL_NATIVE_RENDERABLE, NativeRenderable);
ATTRIB_MAP(EGL_NATIVE_VISUAL_ID, NativeVisualID);
ATTRIB_MAP(EGL_NATIVE_VISUAL_TYPE, NativeVisualType);
ATTRIB_MAP(EGL_SAMPLES, Samples);
ATTRIB_MAP(EGL_SAMPLE_BUFFERS, SampleBuffers);
ATTRIB_MAP(EGL_SURFACE_TYPE, SurfaceType);
ATTRIB_MAP(EGL_TRANSPARENT_TYPE, TransparentType);
ATTRIB_MAP(EGL_TRANSPARENT_BLUE_VALUE, TransparentBlueValue);
ATTRIB_MAP(EGL_TRANSPARENT_GREEN_VALUE, TransparentGreenValue);
ATTRIB_MAP(EGL_TRANSPARENT_RED_VALUE, TransparentRedValue);
ATTRIB_MAP(EGL_BIND_TO_TEXTURE_RGB, BindToTextureRGB);
ATTRIB_MAP(EGL_BIND_TO_TEXTURE_RGBA, BindToTextureRGBA);
ATTRIB_MAP(EGL_MIN_SWAP_INTERVAL, MinSwapInterval);
ATTRIB_MAP(EGL_MAX_SWAP_INTERVAL, MaxSwapInterval);
ATTRIB_MAP(EGL_LUMINANCE_SIZE, LuminanceSize);
ATTRIB_MAP(EGL_ALPHA_MASK_SIZE, AlphaMaskSize);
ATTRIB_MAP(EGL_COLOR_BUFFER_TYPE, ColorBufferType);
ATTRIB_MAP(EGL_RENDERABLE_TYPE, RenderableType);
ATTRIB_MAP(EGL_MATCH_NATIVE_PIXMAP, MatchNativePixmap);
ATTRIB_MAP(EGL_CONFORMANT, Conformant);
/* extensions */
ATTRIB_MAP(EGL_Y_INVERTED_NOK, YInvertedNOK);
#undef ATTRIB_MAP
default: default:
return -1; return -1;
} }
} }
/**
* Reset all keys in the config to a given value.
*/
static INLINE void
_eglResetConfigKeys(_EGLConfig *conf, EGLint val)
{
EGLint i;
for (i = 0; i < _EGL_CONFIG_NUM_ATTRIBS; i++)
conf->Storage[i] = val;
}
/** /**
* Update a config for a given key. * Update a config for a given key.
* *
@ -79,9 +113,9 @@ _eglResetConfigKeys(_EGLConfig *conf, EGLint val)
static INLINE void static INLINE void
_eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val) _eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val)
{ {
EGLint idx = _eglIndexConfig(conf, key); EGLint offset = _eglOffsetOfConfig(key);
assert(idx >= 0); assert(offset >= 0);
conf->Storage[idx] = val; *((EGLint *) ((char *) conf + offset)) = val;
} }
@ -91,9 +125,9 @@ _eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val)
static INLINE EGLint static INLINE EGLint
_eglGetConfigKey(const _EGLConfig *conf, EGLint key) _eglGetConfigKey(const _EGLConfig *conf, EGLint key)
{ {
EGLint idx = _eglIndexConfig(conf, key); EGLint offset = _eglOffsetOfConfig(key);
assert(idx >= 0); assert(offset >= 0);
return conf->Storage[idx]; return *((EGLint *) ((char *) conf + offset));
} }
@ -102,34 +136,20 @@ _eglInitConfig(_EGLConfig *config, _EGLDisplay *dpy, EGLint id);
PUBLIC EGLConfig PUBLIC EGLConfig
_eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf); _eglLinkConfig(_EGLConfig *conf);
extern EGLBoolean extern _EGLConfig *
_eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy); _eglLookupConfig(EGLConfig config, _EGLDisplay *dpy);
/** /**
* Lookup a handle to find the linked config. * Return the handle of a linked config.
* Return NULL if the handle has no corresponding linked config.
*/
static INLINE _EGLConfig *
_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy)
{
_EGLConfig *conf = (_EGLConfig *) config;
if (!dpy || !_eglCheckConfigHandle(config, dpy))
conf = NULL;
return conf;
}
/**
* Return the handle of a linked config, or NULL.
*/ */
static INLINE EGLConfig static INLINE EGLConfig
_eglGetConfigHandle(_EGLConfig *conf) _eglGetConfigHandle(_EGLConfig *conf)
{ {
return (EGLConfig) ((conf && conf->Display) ? conf : NULL); return (EGLConfig) conf;
} }
@ -142,7 +162,8 @@ _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria);
PUBLIC EGLBoolean PUBLIC EGLBoolean
_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list); _eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
const EGLint *attrib_list);
PUBLIC EGLint PUBLIC EGLint

View file

@ -103,8 +103,7 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
return EGL_FALSE; return EGL_FALSE;
} }
memset(ctx, 0, sizeof(_EGLContext)); _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
ctx->Resource.Display = dpy;
ctx->ClientAPI = api; ctx->ClientAPI = api;
ctx->Config = conf; ctx->Config = conf;
ctx->WindowRenderBuffer = EGL_NONE; ctx->WindowRenderBuffer = EGL_NONE;
@ -113,13 +112,12 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
err = _eglParseContextAttribList(ctx, attrib_list); err = _eglParseContextAttribList(ctx, attrib_list);
if (err == EGL_SUCCESS && ctx->Config) { if (err == EGL_SUCCESS && ctx->Config) {
EGLint renderable_type, api_bit; EGLint api_bit;
renderable_type = GET_CONFIG_ATTRIB(ctx->Config, EGL_RENDERABLE_TYPE);
api_bit = _eglGetContextAPIBit(ctx); api_bit = _eglGetContextAPIBit(ctx);
if (!(renderable_type & api_bit)) { if (!(ctx->Config->RenderableType & api_bit)) {
_eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x", _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
api_bit, renderable_type); api_bit, ctx->Config->RenderableType);
err = EGL_BAD_CONFIG; err = EGL_BAD_CONFIG;
} }
} }
@ -130,29 +128,6 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
} }
/**
* Just a placeholder/demo function. Real driver will never use this!
*/
_EGLContext *
_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
_EGLContext *share_list, const EGLint *attrib_list)
{
return NULL;
}
/**
* Default fallback routine - drivers should usually override this.
*/
EGLBoolean
_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
{
if (!_eglIsContextBound(ctx))
free(ctx);
return EGL_TRUE;
}
#ifdef EGL_VERSION_1_2 #ifdef EGL_VERSION_1_2
static EGLint static EGLint
_eglQueryContextRenderBuffer(_EGLContext *ctx) _eglQueryContextRenderBuffer(_EGLContext *ctx)
@ -183,7 +158,9 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
switch (attribute) { switch (attribute) {
case EGL_CONFIG_ID: case EGL_CONFIG_ID:
*value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID); if (!c->Config)
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
*value = c->Config->ConfigID;
break; break;
case EGL_CONTEXT_CLIENT_VERSION: case EGL_CONTEXT_CLIENT_VERSION:
*value = c->ClientVersion; *value = c->ClientVersion;
@ -272,10 +249,6 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
if (!surfaceless && (draw == NULL || read == NULL)) if (!surfaceless && (draw == NULL || read == NULL))
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
/* context stealing from another thread is not allowed */
if (ctx->Binding && ctx->Binding != t)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
/* /*
* The spec says * The spec says
* *
@ -283,16 +256,23 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
* bound to contexts in another thread, an EGL_BAD_ACCESS error is * bound to contexts in another thread, an EGL_BAD_ACCESS error is
* generated." * generated."
* *
* But it also says * and
* *
* "at most one context may be bound to a particular surface at a given * "at most one context may be bound to a particular surface at a given
* time" * time"
*
* The latter is more restrictive so we can check only the latter case.
*/ */
if ((draw && draw->CurrentContext && draw->CurrentContext != ctx) || if (ctx->Binding && ctx->Binding != t)
(read && read->CurrentContext && read->CurrentContext != ctx))
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
if (draw->CurrentContext->Binding != t ||
draw->CurrentContext->ClientAPI != ctx->ClientAPI)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
}
if (read && read->CurrentContext && read->CurrentContext != ctx) {
if (read->CurrentContext->Binding != t ||
read->CurrentContext->ClientAPI != ctx->ClientAPI)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
}
/* simply require the configs to be equal */ /* simply require the configs to be equal */
if ((draw && draw->Config != ctx->Config) || if ((draw && draw->Config != ctx->Config) ||
@ -323,79 +303,65 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
/** /**
* Bind the context to the current thread and given surfaces. Return the * Bind the context to the current thread and given surfaces. Return the
* "orphaned" context and surfaces. Each argument is both input and output. * previous bound context and surfaces. The caller should unreference the
* returned context and surfaces.
*
* Making a second call with the resources returned by the first call
* unsurprisingly undoes the first call, except for the resouce reference
* counts.
*/ */
EGLBoolean EGLBoolean
_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read) _eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
_EGLContext **old_ctx,
_EGLSurface **old_draw, _EGLSurface **old_read)
{ {
_EGLThreadInfo *t = _eglGetCurrentThread(); _EGLThreadInfo *t = _eglGetCurrentThread();
_EGLContext *newCtx = *ctx, *oldCtx; _EGLContext *prev_ctx;
_EGLSurface *newDraw = *draw, *newRead = *read; _EGLSurface *prev_draw, *prev_read;
if (!_eglCheckMakeCurrent(newCtx, newDraw, newRead)) if (!_eglCheckMakeCurrent(ctx, draw, read))
return EGL_FALSE; return EGL_FALSE;
/* increment refcounts before binding */
_eglGetContext(ctx);
_eglGetSurface(draw);
_eglGetSurface(read);
/* bind the new context */ /* bind the new context */
oldCtx = _eglBindContextToThread(newCtx, t); prev_ctx = _eglBindContextToThread(ctx, t);
/* break old bindings */ /* break previous bindings */
if (oldCtx) { if (prev_ctx) {
*ctx = oldCtx; prev_draw = prev_ctx->DrawSurface;
*draw = oldCtx->DrawSurface; prev_read = prev_ctx->ReadSurface;
*read = oldCtx->ReadSurface;
if (*draw) if (prev_draw)
(*draw)->CurrentContext = NULL; prev_draw->CurrentContext = NULL;
if (*read) if (prev_read)
(*read)->CurrentContext = NULL; prev_read->CurrentContext = NULL;
oldCtx->DrawSurface = NULL; prev_ctx->DrawSurface = NULL;
oldCtx->ReadSurface = NULL; prev_ctx->ReadSurface = NULL;
}
else {
prev_draw = prev_read = NULL;
} }
/* establish new bindings */ /* establish new bindings */
if (newCtx) { if (ctx) {
if (newDraw) if (draw)
newDraw->CurrentContext = newCtx; draw->CurrentContext = ctx;
if (newRead) if (read)
newRead->CurrentContext = newCtx; read->CurrentContext = ctx;
newCtx->DrawSurface = newDraw; ctx->DrawSurface = draw;
newCtx->ReadSurface = newRead; ctx->ReadSurface = read;
} }
/* an old context or surface is not orphaned if it is still bound */ assert(old_ctx && old_draw && old_read);
if (*ctx == newCtx) *old_ctx = prev_ctx;
*ctx = NULL; *old_draw = prev_draw;
if (*draw == newDraw || *draw == newRead) *old_read = prev_read;
*draw = NULL;
if (*read == newDraw || *read == newRead)
*read = NULL;
return EGL_TRUE; return EGL_TRUE;
} }
/**
* Just a placeholder/demo function. Drivers should override this.
*/
EGLBoolean
_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
_EGLSurface *read, _EGLContext *ctx)
{
return EGL_FALSE;
}
/**
* This is defined by the EGL_MESA_copy_context extension.
*/
EGLBoolean
_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
EGLContext dest, EGLint mask)
{
/* This function will always have to be overridden/implemented in the
* device driver. If the driver is based on Mesa, use _mesa_copy_context().
*/
return EGL_FALSE;
}

View file

@ -34,51 +34,46 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy,
_EGLConfig *config, const EGLint *attrib_list); _EGLConfig *config, const EGLint *attrib_list);
extern _EGLContext *
_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, _EGLContext *share_list, const EGLint *attrib_list);
extern EGLBoolean
_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx);
extern EGLBoolean extern EGLBoolean
_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLint attribute, EGLint *value); _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLint attribute, EGLint *value);
PUBLIC EGLBoolean PUBLIC EGLBoolean
_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read); _eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
_EGLContext **old_ctx,
_EGLSurface **old_draw, _EGLSurface **old_read);
extern EGLBoolean
_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx);
extern EGLBoolean
_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source, EGLContext dest, EGLint mask);
/** /**
* Return true if the context is bound to a thread. * Increment reference count for the context.
*
* The binding is considered a reference to the context. Drivers should not
* destroy a context when it is bound.
*/ */
static INLINE EGLBoolean static INLINE _EGLContext *
_eglIsContextBound(_EGLContext *ctx) _eglGetContext(_EGLContext *ctx)
{ {
return (ctx->Binding != NULL); if (ctx)
_eglGetResource(&ctx->Resource);
return ctx;
} }
/** /**
* Link a context to a display and return the handle of the link. * Decrement reference count for the context.
*/
static INLINE EGLBoolean
_eglPutContext(_EGLContext *ctx)
{
return (ctx) ? _eglPutResource(&ctx->Resource) : EGL_FALSE;
}
/**
* Link a context to its display and return the handle of the link.
* The handle can be passed to client directly. * The handle can be passed to client directly.
*/ */
static INLINE EGLContext static INLINE EGLContext
_eglLinkContext(_EGLContext *ctx, _EGLDisplay *dpy) _eglLinkContext(_EGLContext *ctx)
{ {
_eglLinkResource(&ctx->Resource, _EGL_RESOURCE_CONTEXT, dpy); _eglLinkResource(&ctx->Resource, _EGL_RESOURCE_CONTEXT);
return (EGLContext) ctx; return (EGLContext) ctx;
} }
@ -120,18 +115,4 @@ _eglGetContextHandle(_EGLContext *ctx)
} }
/**
* Return true if the context is linked to a display.
*
* The link is considered a reference to the context (the display is owning the
* context). Drivers should not destroy a context when it is linked.
*/
static INLINE EGLBoolean
_eglIsContextLinked(_EGLContext *ctx)
{
_EGLResource *res = (_EGLResource *) ctx;
return (res && _eglIsResourceLinked(res));
}
#endif /* EGLCONTEXT_INCLUDED */ #endif /* EGLCONTEXT_INCLUDED */

View file

@ -233,17 +233,53 @@ _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
/** /**
* Link a resource to a display. * Initialize a display resource.
*/ */
void void
_eglLinkResource(_EGLResource *res, _EGLResourceType type, _EGLDisplay *dpy) _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
{ {
assert(!res->Display || res->Display == dpy); memset(res, 0, size);
res->Display = dpy; res->Display = dpy;
res->RefCount = 1;
}
/**
* Increment reference count for the resource.
*/
void
_eglGetResource(_EGLResource *res)
{
assert(res && res->RefCount > 0);
/* hopefully a resource is always manipulated with its display locked */
res->RefCount++;
}
/**
* Decrement reference count for the resource.
*/
EGLBoolean
_eglPutResource(_EGLResource *res)
{
assert(res && res->RefCount > 0);
res->RefCount--;
return (!res->RefCount);
}
/**
* Link a resource to its display.
*/
void
_eglLinkResource(_EGLResource *res, _EGLResourceType type)
{
assert(res->Display);
res->IsLinked = EGL_TRUE; res->IsLinked = EGL_TRUE;
res->Next = dpy->ResourceLists[type]; res->Next = res->Display->ResourceLists[type];
dpy->ResourceLists[type] = res; res->Display->ResourceLists[type] = res;
_eglGetResource(res);
} }
@ -270,6 +306,9 @@ _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
} }
res->Next = NULL; res->Next = NULL;
/* do not reset res->Display */
res->IsLinked = EGL_FALSE; res->IsLinked = EGL_FALSE;
_eglPutResource(res);
/* We always unlink before destroy. The driver still owns a reference */
assert(res->RefCount);
} }

View file

@ -40,6 +40,7 @@ struct _egl_resource
/* which display the resource belongs to */ /* which display the resource belongs to */
_EGLDisplay *Display; _EGLDisplay *Display;
EGLBoolean IsLinked; EGLBoolean IsLinked;
EGLint RefCount;
/* used to link resources of the same type */ /* used to link resources of the same type */
_EGLResource *Next; _EGLResource *Next;
@ -162,7 +163,19 @@ _eglGetDisplayHandle(_EGLDisplay *dpy)
extern void extern void
_eglLinkResource(_EGLResource *res, _EGLResourceType type, _EGLDisplay *dpy); _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy);
PUBLIC void
_eglGetResource(_EGLResource *res);
PUBLIC EGLBoolean
_eglPutResource(_EGLResource *res);
extern void
_eglLinkResource(_EGLResource *res, _EGLResourceType type);
extern void extern void

View file

@ -9,18 +9,10 @@
#include <stdlib.h> #include <stdlib.h>
#include "eglstring.h" #include "eglstring.h"
#include "eglconfig.h"
#include "eglcontext.h"
#include "egldefines.h" #include "egldefines.h"
#include "egldisplay.h" #include "egldisplay.h"
#include "egldriver.h" #include "egldriver.h"
#include "egllog.h" #include "egllog.h"
#include "eglmisc.h"
#include "eglmode.h"
#include "eglscreen.h"
#include "eglsurface.h"
#include "eglimage.h"
#include "eglsync.h"
#include "eglmutex.h" #include "eglmutex.h"
#if defined(_EGL_OS_UNIX) #if defined(_EGL_OS_UNIX)
@ -662,77 +654,6 @@ _eglUnloadDrivers(void)
} }
/**
* Plug all the available fallback routines into the given driver's
* dispatch table.
*/
void
_eglInitDriverFallbacks(_EGLDriver *drv)
{
/* If a pointer is set to NULL, then the device driver _really_ has
* to implement it.
*/
drv->API.Initialize = NULL;
drv->API.Terminate = NULL;
drv->API.GetConfigs = _eglGetConfigs;
drv->API.ChooseConfig = _eglChooseConfig;
drv->API.GetConfigAttrib = _eglGetConfigAttrib;
drv->API.CreateContext = _eglCreateContext;
drv->API.DestroyContext = _eglDestroyContext;
drv->API.MakeCurrent = _eglMakeCurrent;
drv->API.QueryContext = _eglQueryContext;
drv->API.CreateWindowSurface = _eglCreateWindowSurface;
drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
drv->API.DestroySurface = _eglDestroySurface;
drv->API.QuerySurface = _eglQuerySurface;
drv->API.SurfaceAttrib = _eglSurfaceAttrib;
drv->API.BindTexImage = _eglBindTexImage;
drv->API.ReleaseTexImage = _eglReleaseTexImage;
drv->API.SwapInterval = _eglSwapInterval;
drv->API.SwapBuffers = _eglSwapBuffers;
drv->API.CopyBuffers = _eglCopyBuffers;
drv->API.QueryString = _eglQueryString;
drv->API.WaitClient = _eglWaitClient;
drv->API.WaitNative = _eglWaitNative;
#ifdef EGL_MESA_screen_surface
drv->API.ChooseModeMESA = _eglChooseModeMESA;
drv->API.GetModesMESA = _eglGetModesMESA;
drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
drv->API.GetScreensMESA = _eglGetScreensMESA;
drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
drv->API.QueryScreenMESA = _eglQueryScreenMESA;
drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
#endif /* EGL_MESA_screen_surface */
#ifdef EGL_VERSION_1_2
drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
#endif /* EGL_VERSION_1_2 */
#ifdef EGL_KHR_image_base
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 */
}
/** /**
* Invoke a callback function on each EGL search path. * Invoke a callback function on each EGL search path.
* *

View file

@ -80,6 +80,7 @@ extern void
_eglUnloadDrivers(void); _eglUnloadDrivers(void);
/* defined in eglfallbacks.c */
PUBLIC void PUBLIC void
_eglInitDriverFallbacks(_EGLDriver *drv); _eglInitDriverFallbacks(_EGLDriver *drv);

View file

@ -0,0 +1,99 @@
#include <string.h>
#include "egltypedefs.h"
#include "egldriver.h"
#include "eglconfig.h"
#include "eglcontext.h"
#include "eglsurface.h"
#include "eglmisc.h"
#include "eglscreen.h"
#include "eglmode.h"
#include "eglsync.h"
static EGLBoolean
_eglReturnFalse(void)
{
return EGL_FALSE;
}
/**
* Plug all the available fallback routines into the given driver's
* dispatch table.
*/
void
_eglInitDriverFallbacks(_EGLDriver *drv)
{
memset(&drv->API, 0, sizeof(drv->API));
/* the driver has to implement these */
drv->API.Initialize = NULL;
drv->API.Terminate = NULL;
drv->API.GetConfigs = _eglGetConfigs;
drv->API.ChooseConfig = _eglChooseConfig;
drv->API.GetConfigAttrib = _eglGetConfigAttrib;
drv->API.CreateContext = (CreateContext_t) _eglReturnFalse;
drv->API.DestroyContext = (DestroyContext_t) _eglReturnFalse;
drv->API.MakeCurrent = (MakeCurrent_t) _eglReturnFalse;
drv->API.QueryContext = _eglQueryContext;
drv->API.CreateWindowSurface = (CreateWindowSurface_t) _eglReturnFalse;
drv->API.CreatePixmapSurface = (CreatePixmapSurface_t) _eglReturnFalse;
drv->API.CreatePbufferSurface = (CreatePbufferSurface_t) _eglReturnFalse;
drv->API.CreatePbufferFromClientBuffer =
(CreatePbufferFromClientBuffer_t) _eglReturnFalse;
drv->API.DestroySurface = (DestroySurface_t) _eglReturnFalse;
drv->API.QuerySurface = _eglQuerySurface;
drv->API.SurfaceAttrib = _eglSurfaceAttrib;
drv->API.BindTexImage = (BindTexImage_t) _eglReturnFalse;
drv->API.ReleaseTexImage = (ReleaseTexImage_t) _eglReturnFalse;
drv->API.CopyBuffers = (CopyBuffers_t) _eglReturnFalse;
drv->API.SwapBuffers = (SwapBuffers_t) _eglReturnFalse;
drv->API.SwapInterval = _eglSwapInterval;
drv->API.WaitClient = (WaitClient_t) _eglReturnFalse;
drv->API.WaitNative = (WaitNative_t) _eglReturnFalse;
drv->API.GetProcAddress = (GetProcAddress_t) _eglReturnFalse;
drv->API.QueryString = _eglQueryString;
#ifdef EGL_MESA_screen_surface
drv->API.CopyContextMESA = (CopyContextMESA_t) _eglReturnFalse;
drv->API.CreateScreenSurfaceMESA =
(CreateScreenSurfaceMESA_t) _eglReturnFalse;
drv->API.ShowScreenSurfaceMESA = (ShowScreenSurfaceMESA_t) _eglReturnFalse;
drv->API.ChooseModeMESA = _eglChooseModeMESA;
drv->API.GetModesMESA = _eglGetModesMESA;
drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
drv->API.GetScreensMESA = _eglGetScreensMESA;
drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
drv->API.QueryScreenMESA = _eglQueryScreenMESA;
drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
#endif /* EGL_MESA_screen_surface */
#ifdef EGL_KHR_image_base
drv->API.CreateImageKHR = NULL;
drv->API.DestroyImageKHR = NULL;
#endif /* EGL_KHR_image_base */
#ifdef EGL_KHR_reusable_sync
drv->API.CreateSyncKHR = NULL;
drv->API.DestroySyncKHR = NULL;
drv->API.ClientWaitSyncKHR = NULL;
drv->API.SignalSyncKHR = NULL;
drv->API.GetSyncAttribKHR = _eglGetSyncAttribKHR;
#endif /* EGL_KHR_reusable_sync */
#ifdef EGL_MESA_drm_image
drv->API.CreateDRMImageMESA = NULL;
drv->API.ExportDRMImageMESA = NULL;
#endif
#ifdef EGL_NOK_swap_region
drv->API.SwapBuffersRegionNOK = NULL;
#endif
}

View file

@ -2,7 +2,6 @@
#include <string.h> #include <string.h>
#include "eglimage.h" #include "eglimage.h"
#include "eglcurrent.h"
#include "egllog.h" #include "egllog.h"
@ -12,28 +11,57 @@
/** /**
* Parse the list of image attributes and return the proper error code. * Parse the list of image attributes and return the proper error code.
*/ */
static EGLint EGLint
_eglParseImageAttribList(_EGLImage *img, const EGLint *attrib_list) _eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *dpy,
const EGLint *attrib_list)
{ {
EGLint i, err = EGL_SUCCESS; EGLint i, err = EGL_SUCCESS;
(void) dpy;
memset(attrs, 0, sizeof(attrs));
attrs->ImagePreserved = EGL_FALSE;
attrs->GLTextureLevel = 0;
attrs->GLTextureZOffset = 0;
if (!attrib_list) if (!attrib_list)
return EGL_SUCCESS; return err;
for (i = 0; attrib_list[i] != EGL_NONE; i++) { for (i = 0; attrib_list[i] != EGL_NONE; i++) {
EGLint attr = attrib_list[i++]; EGLint attr = attrib_list[i++];
EGLint val = attrib_list[i]; EGLint val = attrib_list[i];
switch (attr) { switch (attr) {
/* EGL_KHR_image_base */
case EGL_IMAGE_PRESERVED_KHR: case EGL_IMAGE_PRESERVED_KHR:
img->Preserved = val; attrs->ImagePreserved = val;
break; break;
/* EGL_KHR_gl_image */
case EGL_GL_TEXTURE_LEVEL_KHR: case EGL_GL_TEXTURE_LEVEL_KHR:
img->GLTextureLevel = val; attrs->GLTextureLevel = val;
break; break;
case EGL_GL_TEXTURE_ZOFFSET_KHR: case EGL_GL_TEXTURE_ZOFFSET_KHR:
img->GLTextureZOffset = val; attrs->GLTextureZOffset = val;
break; break;
/* EGL_MESA_drm_image */
case EGL_WIDTH:
attrs->Width = val;
break;
case EGL_HEIGHT:
attrs->Height = val;
break;
case EGL_DRM_BUFFER_FORMAT_MESA:
attrs->DRMBufferFormatMESA = val;
break;
case EGL_DRM_BUFFER_USE_MESA:
attrs->DRMBufferUseMESA = val;
break;
case EGL_DRM_BUFFER_STRIDE_MESA:
attrs->DRMBufferStrideMESA = val;
break;
default: default:
/* unknown attrs are ignored */ /* unknown attrs are ignored */
break; break;
@ -50,41 +78,12 @@ _eglParseImageAttribList(_EGLImage *img, const EGLint *attrib_list)
EGLBoolean EGLBoolean
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy, const EGLint *attrib_list) _eglInitImage(_EGLImage *img, _EGLDisplay *dpy)
{ {
EGLint err; _eglInitResource(&img->Resource, sizeof(*img), dpy);
memset(img, 0, sizeof(_EGLImage));
img->Resource.Display = dpy;
img->Preserved = EGL_FALSE;
img->GLTextureLevel = 0;
img->GLTextureZOffset = 0;
err = _eglParseImageAttribList(img, attrib_list);
if (err != EGL_SUCCESS)
return _eglError(err, "eglCreateImageKHR");
return EGL_TRUE; return EGL_TRUE;
} }
_EGLImage *
_eglCreateImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx,
EGLenum target, EGLClientBuffer buffer,
const EGLint *attr_list)
{
/* driver should override this function */
return NULL;
}
EGLBoolean
_eglDestroyImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *image)
{
/* driver should override this function */
return EGL_FALSE;
}
#endif /* EGL_KHR_image_base */ #endif /* EGL_KHR_image_base */

View file

@ -6,6 +6,23 @@
#include "egldisplay.h" #include "egldisplay.h"
struct _egl_image_attribs
{
/* EGL_KHR_image_base */
EGLBoolean ImagePreserved;
/* EGL_KHR_gl_image */
EGLint GLTextureLevel;
EGLint GLTextureZOffset;
/* EGL_MESA_drm_image */
EGLint Width;
EGLint Height;
EGLint DRMBufferFormatMESA;
EGLint DRMBufferUseMESA;
EGLint DRMBufferStrideMESA;
};
/** /**
* "Base" class for device driver images. * "Base" class for device driver images.
*/ */
@ -13,34 +30,48 @@ struct _egl_image
{ {
/* An image is a display resource */ /* An image is a display resource */
_EGLResource Resource; _EGLResource Resource;
EGLBoolean Preserved;
EGLint GLTextureLevel;
EGLint GLTextureZOffset;
}; };
PUBLIC EGLint
_eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *dpy,
const EGLint *attrib_list);
PUBLIC EGLBoolean PUBLIC EGLBoolean
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy, const EGLint *attrib_list); _eglInitImage(_EGLImage *img, _EGLDisplay *dpy);
extern _EGLImage *
_eglCreateImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx,
EGLenum target, EGLClientBuffer buffer, const EGLint *attr_list);
extern EGLBoolean
_eglDestroyImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *image);
/** /**
* Link an image to a display and return the handle of the link. * Increment reference count for the image.
*/
static INLINE _EGLImage *
_eglGetImage(_EGLImage *img)
{
if (img)
_eglGetResource(&img->Resource);
return img;
}
/**
* Decrement reference count for the image.
*/
static INLINE EGLBoolean
_eglPutImage(_EGLImage *img)
{
return (img) ? _eglPutResource(&img->Resource) : EGL_FALSE;
}
/**
* Link an image to its display and return the handle of the link.
* The handle can be passed to client directly. * The handle can be passed to client directly.
*/ */
static INLINE EGLImageKHR static INLINE EGLImageKHR
_eglLinkImage(_EGLImage *img, _EGLDisplay *dpy) _eglLinkImage(_EGLImage *img)
{ {
_eglLinkResource(&img->Resource, _EGL_RESOURCE_IMAGE, dpy); _eglLinkResource(&img->Resource, _EGL_RESOURCE_IMAGE);
return (EGLImageKHR) img; return (EGLImageKHR) img;
} }
@ -82,15 +113,4 @@ _eglGetImageHandle(_EGLImage *img)
} }
/**
* Return true if the image is linked to a display.
*/
static INLINE EGLBoolean
_eglIsImageLinked(_EGLImage *img)
{
_EGLResource *res = (_EGLResource *) img;
return (res && _eglIsResourceLinked(res));
}
#endif /* EGLIMAGE_INCLUDED */ #endif /* EGLIMAGE_INCLUDED */

View file

@ -158,32 +158,3 @@ _eglQueryString(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name)
return NULL; return NULL;
} }
} }
EGLBoolean
_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
{
/* just a placeholder */
(void) drv;
(void) dpy;
(void) ctx;
return EGL_TRUE;
}
EGLBoolean
_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
{
/* just a placeholder */
(void) drv;
(void) dpy;
switch (engine) {
case EGL_CORE_NATIVE_ENGINE:
break;
default:
_eglError(EGL_BAD_PARAMETER, "eglWaitNative(engine)");
return EGL_FALSE;
}
return EGL_TRUE;
}

View file

@ -37,12 +37,4 @@ extern const char *
_eglQueryString(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name); _eglQueryString(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name);
extern EGLBoolean
_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx);
extern EGLBoolean
_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine);
#endif /* EGLMISC_INCLUDED */ #endif /* EGLMISC_INCLUDED */

View file

@ -3,11 +3,9 @@
#include <string.h> #include <string.h>
#include "egldisplay.h" #include "egldisplay.h"
#include "egldriver.h"
#include "eglmode.h" #include "eglmode.h"
#include "eglcurrent.h" #include "eglcurrent.h"
#include "eglscreen.h" #include "eglscreen.h"
#include "eglstring.h"
#ifdef EGL_MESA_screen_surface #ifdef EGL_MESA_screen_surface
@ -31,56 +29,24 @@ _eglLookupMode(EGLModeMESA mode, _EGLDisplay *disp)
/* loop over all screens on the display */ /* loop over all screens on the display */
for (scrnum = 0; scrnum < disp->Screens->Size; scrnum++) { for (scrnum = 0; scrnum < disp->Screens->Size; scrnum++) {
const _EGLScreen *scrn = disp->Screens->Elements[scrnum]; const _EGLScreen *scrn = disp->Screens->Elements[scrnum];
EGLint i; EGLint idx;
/* search list of modes for handle */
for (i = 0; i < scrn->NumModes; i++) {
if (scrn->Modes[i].Handle == mode) {
return scrn->Modes + i;
}
}
}
return NULL; /*
} * the mode ids of a screen ranges from scrn->Handle to scrn->Handle +
* scrn->NumModes
/**
* Add a new mode with the given attributes (width, height, depth, refreshRate)
* to the given screen.
* Assign a new mode ID/handle to the mode as well.
* \return pointer to the new _EGLMode
*/ */
_EGLMode * if (mode >= scrn->Handle &&
_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height, mode < scrn->Handle + _EGL_SCREEN_MAX_MODES) {
EGLint refreshRate, const char *name) idx = mode - scrn->Handle;
{
EGLint n;
_EGLMode *newModes;
assert(screen); assert(idx < scrn->NumModes && scrn->Modes[idx].Handle == mode);
assert(width > 0);
assert(height > 0);
assert(refreshRate > 0);
n = screen->NumModes; return &scrn->Modes[idx];
newModes = (_EGLMode *) realloc(screen->Modes, (n+1) * sizeof(_EGLMode));
if (newModes) {
screen->Modes = newModes;
screen->Modes[n].Handle = n + 1;
screen->Modes[n].Width = width;
screen->Modes[n].Height = height;
screen->Modes[n].RefreshRate = refreshRate;
screen->Modes[n].Optimal = EGL_FALSE;
screen->Modes[n].Interlaced = EGL_FALSE;
screen->Modes[n].Name = _eglstrdup(name);
screen->NumModes++;
return screen->Modes + n;
} }
else { }
return NULL; return NULL;
} }
}
/** /**

View file

@ -32,11 +32,6 @@ extern _EGLMode *
_eglLookupMode(EGLModeMESA mode, _EGLDisplay *dpy); _eglLookupMode(EGLModeMESA mode, _EGLDisplay *dpy);
PUBLIC _EGLMode *
_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height,
EGLint refreshRate, const char *name);
extern EGLBoolean extern EGLBoolean
_eglChooseModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, _eglChooseModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
const EGLint *attrib_list, EGLModeMESA *modes, const EGLint *attrib_list, EGLModeMESA *modes,

View file

@ -18,7 +18,6 @@
#include "egldisplay.h" #include "egldisplay.h"
#include "eglcurrent.h" #include "eglcurrent.h"
#include "eglmode.h" #include "eglmode.h"
#include "eglconfig.h"
#include "eglsurface.h" #include "eglsurface.h"
#include "eglscreen.h" #include "eglscreen.h"
#include "eglmutex.h" #include "eglmutex.h"
@ -42,7 +41,8 @@ _eglAllocScreenHandle(void)
EGLScreenMESA s; EGLScreenMESA s;
_eglLockMutex(&_eglNextScreenHandleMutex); _eglLockMutex(&_eglNextScreenHandleMutex);
s = _eglNextScreenHandle++; s = _eglNextScreenHandle;
_eglNextScreenHandle += _EGL_SCREEN_MAX_MODES;
_eglUnlockMutex(&_eglNextScreenHandleMutex); _eglUnlockMutex(&_eglNextScreenHandleMutex);
return s; return s;
@ -53,16 +53,54 @@ _eglAllocScreenHandle(void)
* Initialize an _EGLScreen object to default values. * Initialize an _EGLScreen object to default values.
*/ */
void void
_eglInitScreen(_EGLScreen *screen) _eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes)
{ {
memset(screen, 0, sizeof(_EGLScreen)); memset(screen, 0, sizeof(_EGLScreen));
screen->Display = dpy;
screen->NumModes = num_modes;
screen->StepX = 1; screen->StepX = 1;
screen->StepY = 1; screen->StepY = 1;
if (num_modes > _EGL_SCREEN_MAX_MODES)
num_modes = _EGL_SCREEN_MAX_MODES;
screen->Modes = (_EGLMode *) calloc(num_modes, sizeof(*screen->Modes));
screen->NumModes = (screen->Modes) ? num_modes : 0;
} }
/** /**
* Given a public screen handle, return the internal _EGLScreen object. * Link a screen to its display and return the handle of the link.
* The handle can be passed to client directly.
*/
EGLScreenMESA
_eglLinkScreen(_EGLScreen *screen)
{
_EGLDisplay *display;
EGLint i;
assert(screen && screen->Display);
display = screen->Display;
if (!display->Screens) {
display->Screens = _eglCreateArray("Screen", 4);
if (!display->Screens)
return (EGLScreenMESA) 0;
}
screen->Handle = _eglAllocScreenHandle();
for (i = 0; i < screen->NumModes; i++)
screen->Modes[i].Handle = screen->Handle + i;
_eglAppendArray(display->Screens, (void *) screen);
return screen->Handle;
}
/**
* Lookup a handle to find the linked config.
* Return NULL if the handle has no corresponding linked config.
*/ */
_EGLScreen * _EGLScreen *
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display) _eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
@ -74,39 +112,21 @@ _eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
for (i = 0; i < display->Screens->Size; i++) { for (i = 0; i < display->Screens->Size; i++) {
_EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i]; _EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i];
if (scr->Handle == screen) if (scr->Handle == screen) {
assert(scr->Display == display);
return scr; return scr;
} }
}
return NULL; return NULL;
} }
/**
* Add the given _EGLScreen to the display's list of screens.
*/
void
_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen)
{
assert(display);
assert(screen);
if (!display->Screens) {
display->Screens = _eglCreateArray("Screen", 4);
if (!display->Screens)
return;
}
screen->Handle = _eglAllocScreenHandle();
_eglAppendArray(display->Screens, (void *) screen);
}
static EGLBoolean static EGLBoolean
_eglFlattenScreen(void *elem, void *buffer) _eglFlattenScreen(void *elem, void *buffer)
{ {
_EGLScreen *scr = (_EGLScreen *) elem; _EGLScreen *scr = (_EGLScreen *) elem;
EGLScreenMESA *handle = (EGLScreenMESA *) buffer; EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
*handle = scr->Handle; *handle = _eglGetScreenHandle(scr);
return EGL_TRUE; return EGL_TRUE;
} }
@ -122,66 +142,6 @@ _eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *display, EGLScreenMESA *screens
} }
/**
* Drivers should do a proper implementation.
*/
_EGLSurface *
_eglCreateScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
const EGLint *attrib_list)
{
return NULL;
}
/**
* Show the given surface on the named screen.
* If surface is EGL_NO_SURFACE, disable the screen's output.
*
* This is just a placeholder function; drivers will always override
* this with code that _really_ shows the surface.
*/
EGLBoolean
_eglShowScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
_EGLScreen *scrn, _EGLSurface *surf,
_EGLMode *mode)
{
if (!surf) {
scrn->CurrentSurface = NULL;
}
else {
if (surf->Type != EGL_SCREEN_BIT_MESA) {
_eglError(EGL_BAD_SURFACE, "eglShowSurfaceMESA");
return EGL_FALSE;
}
if (surf->Width < mode->Width || surf->Height < mode->Height) {
_eglError(EGL_BAD_SURFACE,
"eglShowSurfaceMESA(surface smaller than screen size)");
return EGL_FALSE;
}
scrn->CurrentSurface = surf;
scrn->CurrentMode = mode;
}
return EGL_TRUE;
}
/**
* Set a screen's current display mode.
* Note: mode = EGL_NO_MODE is valid (turns off the screen)
*
* This is just a placeholder function; drivers will always override
* this with code that _really_ sets the mode.
*/
EGLBoolean
_eglScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
_EGLMode *m)
{
scrn->CurrentMode = m;
return EGL_TRUE;
}
/** /**
* Set a screen's surface origin. * Set a screen's surface origin.
*/ */
@ -242,33 +202,4 @@ _eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
} }
/**
* Delete the modes associated with given screen.
*/
void
_eglDestroyScreenModes(_EGLScreen *scrn)
{
EGLint i;
for (i = 0; i < scrn->NumModes; i++) {
if (scrn->Modes[i].Name)
free((char *) scrn->Modes[i].Name); /* cast away const */
}
if (scrn->Modes)
free(scrn->Modes);
scrn->Modes = NULL;
scrn->NumModes = 0;
}
/**
* Default fallback routine - drivers should usually override this.
*/
void
_eglDestroyScreen(_EGLScreen *scrn)
{
_eglDestroyScreenModes(scrn);
free(scrn);
}
#endif /* EGL_MESA_screen_surface */ #endif /* EGL_MESA_screen_surface */

View file

@ -8,6 +8,9 @@
#ifdef EGL_MESA_screen_surface #ifdef EGL_MESA_screen_surface
#define _EGL_SCREEN_MAX_MODES 16
/** /**
* Per-screen information. * Per-screen information.
* Note that an EGL screen doesn't have a size. A screen may be set to * Note that an EGL screen doesn't have a size. A screen may be set to
@ -19,6 +22,8 @@
*/ */
struct _egl_screen struct _egl_screen
{ {
_EGLDisplay *Display;
EGLScreenMESA Handle; /* The public/opaque handle which names this object */ EGLScreenMESA Handle; /* The public/opaque handle which names this object */
_EGLMode *CurrentMode; _EGLMode *CurrentMode;
@ -33,41 +38,35 @@ struct _egl_screen
PUBLIC void PUBLIC void
_eglInitScreen(_EGLScreen *screen); _eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes);
PUBLIC EGLScreenMESA
_eglLinkScreen(_EGLScreen *screen);
extern _EGLScreen * extern _EGLScreen *
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *dpy); _eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *dpy);
PUBLIC void /**
_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen); * Return the handle of a linked screen.
*/
static INLINE EGLScreenMESA
_eglGetScreenHandle(_EGLScreen *screen)
{
return (screen) ? screen->Handle : (EGLScreenMESA) 0;
}
extern EGLBoolean extern EGLBoolean
_eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *dpy, EGLScreenMESA *screens, EGLint max_screens, EGLint *num_screens); _eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *dpy, EGLScreenMESA *screens, EGLint max_screens, EGLint *num_screens);
extern _EGLSurface *
_eglCreateScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, const EGLint *attrib_list);
extern EGLBoolean
_eglShowScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, _EGLSurface *surf, _EGLMode *m);
extern EGLBoolean
_eglScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, _EGLMode *m);
extern EGLBoolean extern EGLBoolean
_eglScreenPositionMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, EGLint x, EGLint y); _eglScreenPositionMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, EGLint x, EGLint y);
extern EGLBoolean
_eglQueryDisplayMESA(_EGLDriver *drv, _EGLDisplay *dpy, EGLint attribute, EGLint *value);
extern EGLBoolean extern EGLBoolean
_eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy, _eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
_EGLScreen *scrn, _EGLSurface **surface); _EGLScreen *scrn, _EGLSurface **surface);
@ -81,14 +80,6 @@ extern EGLBoolean
_eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, EGLint attribute, EGLint *value); _eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, EGLint attribute, EGLint *value);
extern void
_eglDestroyScreenModes(_EGLScreen *scrn);
PUBLIC void
_eglDestroyScreen(_EGLScreen *scrn);
#endif /* EGL_MESA_screen_surface */ #endif /* EGL_MESA_screen_surface */

View file

@ -17,12 +17,12 @@
static void static void
_eglClampSwapInterval(_EGLSurface *surf, EGLint interval) _eglClampSwapInterval(_EGLSurface *surf, EGLint interval)
{ {
EGLint bound = GET_CONFIG_ATTRIB(surf->Config, EGL_MAX_SWAP_INTERVAL); EGLint bound = surf->Config->MaxSwapInterval;
if (interval >= bound) { if (interval >= bound) {
interval = bound; interval = bound;
} }
else { else {
bound = GET_CONFIG_ATTRIB(surf->Config, EGL_MIN_SWAP_INTERVAL); bound = surf->Config->MinSwapInterval;
if (interval < bound) if (interval < bound)
interval = bound; interval = bound;
} }
@ -263,14 +263,13 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
return EGL_FALSE; return EGL_FALSE;
} }
if ((GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE) & type) == 0) { if ((conf->SurfaceType & type) == 0) {
/* The config can't be used to create a surface of this type */ /* The config can't be used to create a surface of this type */
_eglError(EGL_BAD_CONFIG, func); _eglError(EGL_BAD_CONFIG, func);
return EGL_FALSE; return EGL_FALSE;
} }
memset(surf, 0, sizeof(_EGLSurface)); _eglInitResource(&surf->Resource, sizeof(*surf), dpy);
surf->Resource.Display = dpy;
surf->Type = type; surf->Type = type;
surf->Config = conf; surf->Config = conf;
@ -303,24 +302,6 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
} }
EGLBoolean
_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
{
/* Drivers have to do the actual buffer swap. */
return EGL_TRUE;
}
EGLBoolean
_eglCopyBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
EGLNativePixmapType target)
{
/* copy surface to native pixmap */
/* All implementation burdon for this is in the device driver */
return EGL_FALSE;
}
EGLBoolean EGLBoolean
_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
EGLint attribute, EGLint *value) EGLint attribute, EGLint *value)
@ -333,7 +314,7 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
*value = surface->Height; *value = surface->Height;
break; break;
case EGL_CONFIG_ID: case EGL_CONFIG_ID:
*value = GET_CONFIG_ATTRIB(surface->Config, EGL_CONFIG_ID); *value = surface->Config->ConfigID;
break; break;
case EGL_LARGEST_PBUFFER: case EGL_LARGEST_PBUFFER:
*value = surface->LargestPbuffer; *value = surface->LargestPbuffer;
@ -388,51 +369,6 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
} }
/**
* Drivers should do a proper implementation.
*/
_EGLSurface *
_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
EGLNativeWindowType window, const EGLint *attrib_list)
{
return NULL;
}
/**
* Drivers should do a proper implementation.
*/
_EGLSurface *
_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
EGLNativePixmapType pixmap, const EGLint *attrib_list)
{
return NULL;
}
/**
* Drivers should do a proper implementation.
*/
_EGLSurface *
_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
const EGLint *attrib_list)
{
return NULL;
}
/**
* Default fallback routine - drivers should usually override this.
*/
EGLBoolean
_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
{
if (!_eglIsSurfaceBound(surf))
free(surf);
return EGL_TRUE;
}
/** /**
* Default fallback routine - drivers might override this. * Default fallback routine - drivers might override this.
*/ */
@ -445,7 +381,7 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
switch (attribute) { switch (attribute) {
case EGL_MIPMAP_LEVEL: case EGL_MIPMAP_LEVEL:
confval = GET_CONFIG_ATTRIB(surface->Config, EGL_RENDERABLE_TYPE); confval = surface->Config->RenderableType;
if (!(confval & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT))) { if (!(confval & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT))) {
err = EGL_BAD_PARAMETER; err = EGL_BAD_PARAMETER;
break; break;
@ -457,7 +393,7 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
case EGL_MULTISAMPLE_RESOLVE_DEFAULT: case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
break; break;
case EGL_MULTISAMPLE_RESOLVE_BOX: case EGL_MULTISAMPLE_RESOLVE_BOX:
confval = GET_CONFIG_ATTRIB(surface->Config, EGL_SURFACE_TYPE); confval = surface->Config->SurfaceType;
if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT)) if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
err = EGL_BAD_MATCH; err = EGL_BAD_MATCH;
break; break;
@ -474,7 +410,7 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
case EGL_BUFFER_DESTROYED: case EGL_BUFFER_DESTROYED:
break; break;
case EGL_BUFFER_PRESERVED: case EGL_BUFFER_PRESERVED:
confval = GET_CONFIG_ATTRIB(surface->Config, EGL_SURFACE_TYPE); confval = surface->Config->SurfaceType;
if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)) if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
err = EGL_BAD_MATCH; err = EGL_BAD_MATCH;
break; break;
@ -536,40 +472,6 @@ _eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
} }
EGLBoolean
_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
EGLint buffer)
{
/* Just do basic error checking and return success/fail.
* Drivers must implement the real stuff.
*/
if (surface->Type != EGL_PBUFFER_BIT) {
_eglError(EGL_BAD_SURFACE, "eglBindTexImage");
return EGL_FALSE;
}
if (surface->TextureFormat == EGL_NO_TEXTURE) {
_eglError(EGL_BAD_MATCH, "eglBindTexImage");
return EGL_FALSE;
}
if (buffer != EGL_BACK_BUFFER) {
_eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
return EGL_FALSE;
}
if (!surface->BoundToTexture) {
_eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
return EGL_FALSE;
}
surface->BoundToTexture = EGL_FALSE;
return EGL_TRUE;
}
EGLBoolean EGLBoolean
_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
EGLint interval) EGLint interval)
@ -577,24 +479,3 @@ _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
_eglClampSwapInterval(surf, interval); _eglClampSwapInterval(surf, interval);
return EGL_TRUE; return EGL_TRUE;
} }
#ifdef EGL_VERSION_1_2
/**
* Example function - drivers should do a proper implementation.
*/
_EGLSurface *
_eglCreatePbufferFromClientBuffer(_EGLDriver *drv, _EGLDisplay *dpy,
EGLenum buftype, EGLClientBuffer buffer,
_EGLConfig *conf, const EGLint *attrib_list)
{
if (buftype != EGL_OPENVG_IMAGE) {
_eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer");
return NULL;
}
return NULL;
}
#endif /* EGL_VERSION_1_2 */

View file

@ -51,34 +51,10 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
_EGLConfig *config, const EGLint *attrib_list); _EGLConfig *config, const EGLint *attrib_list);
extern EGLBoolean
_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf);
extern EGLBoolean
_eglCopyBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLNativePixmapType target);
extern EGLBoolean extern EGLBoolean
_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint *value); _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint *value);
extern _EGLSurface *
_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, EGLNativeWindowType window, const EGLint *attrib_list);
extern _EGLSurface *
_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, EGLNativePixmapType pixmap, const EGLint *attrib_list);
extern _EGLSurface *
_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, const EGLint *attrib_list);
extern EGLBoolean
_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf);
extern EGLBoolean extern EGLBoolean
_eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint value); _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint value);
@ -87,45 +63,40 @@ PUBLIC extern EGLBoolean
_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint buffer); _eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint buffer);
extern EGLBoolean
_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint buffer);
extern EGLBoolean extern EGLBoolean
_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval); _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval);
#ifdef EGL_VERSION_1_2
extern _EGLSurface *
_eglCreatePbufferFromClientBuffer(_EGLDriver *drv, _EGLDisplay *dpy,
EGLenum buftype, EGLClientBuffer buffer,
_EGLConfig *conf, const EGLint *attrib_list);
#endif /* EGL_VERSION_1_2 */
/** /**
* Return true if there is a context bound to the surface. * Increment reference count for the surface.
*
* The binding is considered a reference to the surface. Drivers should not
* destroy a surface when it is bound.
*/ */
static INLINE EGLBoolean static INLINE _EGLSurface *
_eglIsSurfaceBound(_EGLSurface *surf) _eglGetSurface(_EGLSurface *surf)
{ {
return (surf->CurrentContext != NULL); if (surf)
_eglGetResource(&surf->Resource);
return surf;
} }
/** /**
* Link a surface to a display and return the handle of the link. * Decrement reference count for the surface.
*/
static INLINE EGLBoolean
_eglPutSurface(_EGLSurface *surf)
{
return (surf) ? _eglPutResource(&surf->Resource) : EGL_FALSE;
}
/**
* Link a surface to its display and return the handle of the link.
* The handle can be passed to client directly. * The handle can be passed to client directly.
*/ */
static INLINE EGLSurface static INLINE EGLSurface
_eglLinkSurface(_EGLSurface *surf, _EGLDisplay *dpy) _eglLinkSurface(_EGLSurface *surf)
{ {
_eglLinkResource(&surf->Resource, _EGL_RESOURCE_SURFACE, dpy); _eglLinkResource(&surf->Resource, _EGL_RESOURCE_SURFACE);
return (EGLSurface) surf; return (EGLSurface) surf;
} }
@ -167,18 +138,4 @@ _eglGetSurfaceHandle(_EGLSurface *surf)
} }
/**
* Return true if the surface is linked to a display.
*
* The link is considered a reference to the surface (the display is owning the
* surface). Drivers should not destroy a surface when it is linked.
*/
static INLINE EGLBoolean
_eglIsSurfaceLinked(_EGLSurface *surf)
{
_EGLResource *res = (_EGLResource *) surf;
return (res && _eglIsResourceLinked(res));
}
#endif /* EGLSURFACE_INCLUDED */ #endif /* EGLSURFACE_INCLUDED */

View file

@ -50,10 +50,7 @@ _eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type,
!(type == EGL_SYNC_FENCE_KHR && dpy->Extensions.KHR_fence_sync)) !(type == EGL_SYNC_FENCE_KHR && dpy->Extensions.KHR_fence_sync))
return _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR"); return _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
memset(sync, 0, sizeof(*sync)); _eglInitResource(&sync->Resource, sizeof(*sync), dpy);
sync->Resource.Display = dpy;
sync->Type = type; sync->Type = type;
sync->SyncStatus = EGL_UNSIGNALED_KHR; sync->SyncStatus = EGL_UNSIGNALED_KHR;
sync->SyncCondition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; sync->SyncCondition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
@ -66,37 +63,6 @@ _eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type,
} }
_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 EGLBoolean
_eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, _eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
EGLint attribute, EGLint *value) EGLint attribute, EGLint *value)

View file

@ -28,38 +28,41 @@ _eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type,
const EGLint *attrib_list); 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 extern EGLBoolean
_eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, _eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
EGLint attribute, EGLint *value); EGLint attribute, EGLint *value);
/** /**
* Link a sync to a display and return the handle of the link. * Increment reference count for the sync.
*/
static INLINE _EGLSync *
_eglGetSync(_EGLSync *sync)
{
if (sync)
_eglGetResource(&sync->Resource);
return sync;
}
/**
* Decrement reference count for the sync.
*/
static INLINE EGLBoolean
_eglPutSync(_EGLSync *sync)
{
return (sync) ? _eglPutResource(&sync->Resource) : EGL_FALSE;
}
/**
* Link a sync to its display and return the handle of the link.
* The handle can be passed to client directly. * The handle can be passed to client directly.
*/ */
static INLINE EGLSyncKHR static INLINE EGLSyncKHR
_eglLinkSync(_EGLSync *sync, _EGLDisplay *dpy) _eglLinkSync(_EGLSync *sync)
{ {
_eglLinkResource(&sync->Resource, _EGL_RESOURCE_SYNC, dpy); _eglLinkResource(&sync->Resource, _EGL_RESOURCE_SYNC);
return (EGLSyncKHR) sync; return (EGLSyncKHR) sync;
} }
@ -100,20 +103,6 @@ _eglGetSyncHandle(_EGLSync *sync)
} }
/**
* 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 /* EGL_KHR_reusable_sync */

View file

@ -24,6 +24,8 @@ typedef struct _egl_extensions _EGLExtensions;
typedef struct _egl_image _EGLImage; typedef struct _egl_image _EGLImage;
typedef struct _egl_image_attribs _EGLImageAttribs;
typedef struct _egl_mode _EGLMode; typedef struct _egl_mode _EGLMode;
typedef struct _egl_resource _EGLResource; typedef struct _egl_resource _EGLResource;

View file

@ -173,6 +173,7 @@ GALLIVM_SOURCES = \
gallivm/lp_bld_struct.c \ gallivm/lp_bld_struct.c \
gallivm/lp_bld_swizzle.c \ gallivm/lp_bld_swizzle.c \
gallivm/lp_bld_tgsi_aos.c \ gallivm/lp_bld_tgsi_aos.c \
gallivm/lp_bld_tgsi_info.c \
gallivm/lp_bld_tgsi_soa.c \ gallivm/lp_bld_tgsi_soa.c \
gallivm/lp_bld_type.c \ gallivm/lp_bld_type.c \
draw/draw_llvm.c \ draw/draw_llvm.c \
@ -207,16 +208,16 @@ include ../Makefile.template
indices/u_indices_gen.c: indices/u_indices_gen.py indices/u_indices_gen.c: indices/u_indices_gen.py
python $< > $@ $(PYTHON2) $< > $@
indices/u_unfilled_gen.c: indices/u_unfilled_gen.py indices/u_unfilled_gen.c: indices/u_unfilled_gen.py
python $< > $@ $(PYTHON2) $< > $@
util/u_format_srgb.c: util/u_format_srgb.py util/u_format_srgb.c: util/u_format_srgb.py
python $< > $@ $(PYTHON2) $< > $@
util/u_format_table.c: util/u_format_table.py util/u_format_pack.py util/u_format_parse.py util/u_format.csv util/u_format_table.c: util/u_format_table.py util/u_format_pack.py util/u_format_parse.py util/u_format.csv
python util/u_format_table.py util/u_format.csv > $@ $(PYTHON2) util/u_format_table.py util/u_format.csv > $@
util/u_half.c: util/u_half.py util/u_half.c: util/u_half.py
python util/u_half.py > $@ $(PYTHON2) util/u_half.py > $@

View file

@ -225,6 +225,7 @@ if env['llvm']:
'gallivm/lp_bld_struct.c', 'gallivm/lp_bld_struct.c',
'gallivm/lp_bld_swizzle.c', 'gallivm/lp_bld_swizzle.c',
'gallivm/lp_bld_tgsi_aos.c', 'gallivm/lp_bld_tgsi_aos.c',
'gallivm/lp_bld_tgsi_info.c',
'gallivm/lp_bld_tgsi_soa.c', 'gallivm/lp_bld_tgsi_soa.c',
'gallivm/lp_bld_type.c', 'gallivm/lp_bld_type.c',
'draw/draw_llvm.c', 'draw/draw_llvm.c',

View file

@ -335,6 +335,7 @@ draw_set_mapped_constant_buffer(struct draw_context *draw,
case PIPE_SHADER_VERTEX: case PIPE_SHADER_VERTEX:
draw->pt.user.vs_constants[slot] = buffer; draw->pt.user.vs_constants[slot] = buffer;
draw->pt.user.vs_constants_size[slot] = size; draw->pt.user.vs_constants_size[slot] = size;
draw->pt.user.planes = (float (*) [12][4]) &(draw->plane[0]);
draw_vs_set_constants(draw, slot, buffer, size); draw_vs_set_constants(draw, slot, buffer, size);
break; break;
case PIPE_SHADER_GEOMETRY: case PIPE_SHADER_GEOMETRY:
@ -721,9 +722,9 @@ draw_set_mapped_texture(struct draw_context *draw,
unsigned sampler_idx, unsigned sampler_idx,
uint32_t width, uint32_t height, uint32_t depth, uint32_t width, uint32_t height, uint32_t depth,
uint32_t last_level, uint32_t last_level,
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS], uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS], uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
const void *data[DRAW_MAX_TEXTURE_LEVELS]) const void *data[PIPE_MAX_TEXTURE_LEVELS])
{ {
#ifdef HAVE_LLVM #ifdef HAVE_LLVM
if(draw->llvm) if(draw->llvm)

View file

@ -49,7 +49,6 @@ struct draw_geometry_shader;
struct draw_fragment_shader; struct draw_fragment_shader;
struct tgsi_sampler; struct tgsi_sampler;
#define DRAW_MAX_TEXTURE_LEVELS 13 /* 4K x 4K for now */
struct draw_context *draw_create( struct pipe_context *pipe ); struct draw_context *draw_create( struct pipe_context *pipe );
@ -120,9 +119,9 @@ draw_set_mapped_texture(struct draw_context *draw,
unsigned sampler_idx, unsigned sampler_idx,
uint32_t width, uint32_t height, uint32_t depth, uint32_t width, uint32_t height, uint32_t depth,
uint32_t last_level, uint32_t last_level,
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS], uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS], uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
const void *data[DRAW_MAX_TEXTURE_LEVELS]); const void *data[PIPE_MAX_TEXTURE_LEVELS]);
/* /*

View file

@ -31,6 +31,9 @@
#include "draw_vs.h" #include "draw_vs.h"
#include "gallivm/lp_bld_arit.h" #include "gallivm/lp_bld_arit.h"
#include "gallivm/lp_bld_logic.h"
#include "gallivm/lp_bld_const.h"
#include "gallivm/lp_bld_swizzle.h"
#include "gallivm/lp_bld_struct.h" #include "gallivm/lp_bld_struct.h"
#include "gallivm/lp_bld_type.h" #include "gallivm/lp_bld_type.h"
#include "gallivm/lp_bld_flow.h" #include "gallivm/lp_bld_flow.h"
@ -43,7 +46,6 @@
#include "tgsi/tgsi_exec.h" #include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_dump.h" #include "tgsi/tgsi_dump.h"
#include "util/u_cpu_detect.h"
#include "util/u_math.h" #include "util/u_math.h"
#include "util/u_pointer.h" #include "util/u_pointer.h"
#include "util/u_string.h" #include "util/u_string.h"
@ -72,12 +74,12 @@ init_globals(struct draw_llvm *llvm)
elem_types[DRAW_JIT_TEXTURE_DEPTH] = LLVMInt32Type(); elem_types[DRAW_JIT_TEXTURE_DEPTH] = LLVMInt32Type();
elem_types[DRAW_JIT_TEXTURE_LAST_LEVEL] = LLVMInt32Type(); elem_types[DRAW_JIT_TEXTURE_LAST_LEVEL] = LLVMInt32Type();
elem_types[DRAW_JIT_TEXTURE_ROW_STRIDE] = elem_types[DRAW_JIT_TEXTURE_ROW_STRIDE] =
LLVMArrayType(LLVMInt32Type(), DRAW_MAX_TEXTURE_LEVELS); LLVMArrayType(LLVMInt32Type(), PIPE_MAX_TEXTURE_LEVELS);
elem_types[DRAW_JIT_TEXTURE_IMG_STRIDE] = elem_types[DRAW_JIT_TEXTURE_IMG_STRIDE] =
LLVMArrayType(LLVMInt32Type(), DRAW_MAX_TEXTURE_LEVELS); LLVMArrayType(LLVMInt32Type(), PIPE_MAX_TEXTURE_LEVELS);
elem_types[DRAW_JIT_TEXTURE_DATA] = elem_types[DRAW_JIT_TEXTURE_DATA] =
LLVMArrayType(LLVMPointerType(LLVMInt8Type(), 0), LLVMArrayType(LLVMPointerType(LLVMInt8Type(), 0),
DRAW_MAX_TEXTURE_LEVELS); PIPE_MAX_TEXTURE_LEVELS);
elem_types[DRAW_JIT_TEXTURE_MIN_LOD] = LLVMFloatType(); elem_types[DRAW_JIT_TEXTURE_MIN_LOD] = LLVMFloatType();
elem_types[DRAW_JIT_TEXTURE_MAX_LOD] = LLVMFloatType(); elem_types[DRAW_JIT_TEXTURE_MAX_LOD] = LLVMFloatType();
elem_types[DRAW_JIT_TEXTURE_LOD_BIAS] = LLVMFloatType(); elem_types[DRAW_JIT_TEXTURE_LOD_BIAS] = LLVMFloatType();
@ -128,12 +130,14 @@ init_globals(struct draw_llvm *llvm)
/* struct draw_jit_context */ /* struct draw_jit_context */
{ {
LLVMTypeRef elem_types[3]; LLVMTypeRef elem_types[5];
LLVMTypeRef context_type; LLVMTypeRef context_type;
elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */ elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */
elem_types[1] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */ elem_types[1] = LLVMPointerType(LLVMFloatType(), 0); /* gs_constants */
elem_types[2] = LLVMArrayType(texture_type, elem_types[2] = LLVMPointerType(LLVMArrayType(LLVMArrayType(LLVMFloatType(), 4), 12), 0); /* planes */
elem_types[3] = LLVMPointerType(LLVMFloatType(), 0); /* viewport */
elem_types[4] = LLVMArrayType(texture_type,
PIPE_MAX_VERTEX_SAMPLERS); /* textures */ PIPE_MAX_VERTEX_SAMPLERS); /* textures */
context_type = LLVMStructType(elem_types, Elements(elem_types), 0); context_type = LLVMStructType(elem_types, Elements(elem_types), 0);
@ -142,6 +146,8 @@ init_globals(struct draw_llvm *llvm)
llvm->target, context_type, 0); llvm->target, context_type, 0);
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, gs_constants, LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, gs_constants,
llvm->target, context_type, 1); llvm->target, context_type, 1);
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, planes,
llvm->target, context_type, 2);
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, textures, LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, textures,
llvm->target, context_type, llvm->target, context_type,
DRAW_JIT_CTX_TEXTURES); DRAW_JIT_CTX_TEXTURES);
@ -267,13 +273,7 @@ draw_llvm_create(struct draw_context *draw)
LLVMAddConstantPropagationPass(llvm->pass); LLVMAddConstantPropagationPass(llvm->pass);
} }
if(util_cpu_caps.has_sse4_1) {
/* FIXME: There is a bug in this pass, whereby the combination of fptosi
* and sitofp (necessary for trunc/floor/ceil/round implementation)
* somehow becomes invalid code.
*/
LLVMAddInstructionCombiningPass(llvm->pass); LLVMAddInstructionCombiningPass(llvm->pass);
}
LLVMAddGVNPass(llvm->pass); LLVMAddGVNPass(llvm->pass);
} else { } else {
/* We need at least this pass to prevent the backends to fail in /* We need at least this pass to prevent the backends to fail in
@ -421,7 +421,7 @@ generate_fetch(LLVMBuilderRef builder,
"instance_divisor"); "instance_divisor");
} }
/* limit index to min(inex, vb_max_index) */ /* limit index to min(index, vb_max_index) */
cond = LLVMBuildICmp(builder, LLVMIntULE, index, vb_max_index, ""); cond = LLVMBuildICmp(builder, LLVMIntULE, index, vb_max_index, "");
index = LLVMBuildSelect(builder, cond, index, vb_max_index, ""); index = LLVMBuildSelect(builder, cond, index, vb_max_index, "");
@ -550,19 +550,28 @@ static void
store_aos(LLVMBuilderRef builder, store_aos(LLVMBuilderRef builder,
LLVMValueRef io_ptr, LLVMValueRef io_ptr,
LLVMValueRef index, LLVMValueRef index,
LLVMValueRef value) LLVMValueRef value,
LLVMValueRef clipmask)
{ {
LLVMValueRef id_ptr = draw_jit_header_id(builder, io_ptr); LLVMValueRef id_ptr = draw_jit_header_id(builder, io_ptr);
LLVMValueRef data_ptr = draw_jit_header_data(builder, io_ptr); LLVMValueRef data_ptr = draw_jit_header_data(builder, io_ptr);
LLVMValueRef indices[3]; LLVMValueRef indices[3];
LLVMValueRef val, shift;
indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0); indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
indices[1] = index; indices[1] = index;
indices[2] = LLVMConstInt(LLVMInt32Type(), 0, 0); indices[2] = LLVMConstInt(LLVMInt32Type(), 0, 0);
/* undefined vertex */ /* initialize vertex id:16 = 0xffff, pad:3 = 0, edgeflag:1 = 1 */
LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), val = LLVMConstInt(LLVMInt32Type(), 0xffff1, 0);
0xffff, 0), id_ptr); shift = LLVMConstInt(LLVMInt32Type(), 12, 0);
val = LLVMBuildShl(builder, val, shift, "");
/* add clipmask:12 */
val = LLVMBuildOr(builder, val, clipmask, "");
/* store vertex header */
LLVMBuildStore(builder, val, id_ptr);
#if DEBUG_STORE #if DEBUG_STORE
lp_build_printf(builder, " ---- %p storing attribute %d (io = %p)\n", data_ptr, index, io_ptr); lp_build_printf(builder, " ---- %p storing attribute %d (io = %p)\n", data_ptr, index, io_ptr);
@ -617,7 +626,8 @@ store_aos_array(LLVMBuilderRef builder,
LLVMValueRef io_ptr, LLVMValueRef io_ptr,
LLVMValueRef aos[NUM_CHANNELS], LLVMValueRef aos[NUM_CHANNELS],
int attrib, int attrib,
int num_outputs) int num_outputs,
LLVMValueRef clipmask)
{ {
LLVMValueRef attr_index = LLVMConstInt(LLVMInt32Type(), attrib, 0); LLVMValueRef attr_index = LLVMConstInt(LLVMInt32Type(), attrib, 0);
LLVMValueRef ind0 = LLVMConstInt(LLVMInt32Type(), 0, 0); LLVMValueRef ind0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
@ -625,6 +635,7 @@ store_aos_array(LLVMBuilderRef builder,
LLVMValueRef ind2 = LLVMConstInt(LLVMInt32Type(), 2, 0); LLVMValueRef ind2 = LLVMConstInt(LLVMInt32Type(), 2, 0);
LLVMValueRef ind3 = LLVMConstInt(LLVMInt32Type(), 3, 0); LLVMValueRef ind3 = LLVMConstInt(LLVMInt32Type(), 3, 0);
LLVMValueRef io0_ptr, io1_ptr, io2_ptr, io3_ptr; LLVMValueRef io0_ptr, io1_ptr, io2_ptr, io3_ptr;
LLVMValueRef clipmask0, clipmask1, clipmask2, clipmask3;
debug_assert(NUM_CHANNELS == 4); debug_assert(NUM_CHANNELS == 4);
@ -637,21 +648,31 @@ store_aos_array(LLVMBuilderRef builder,
io3_ptr = LLVMBuildGEP(builder, io_ptr, io3_ptr = LLVMBuildGEP(builder, io_ptr,
&ind3, 1, ""); &ind3, 1, "");
#if DEBUG_STORE clipmask0 = LLVMBuildExtractElement(builder, clipmask,
lp_build_printf(builder, " io = %p, indexes[%d, %d, %d, %d]\n", ind0, "");
io_ptr, ind0, ind1, ind2, ind3); clipmask1 = LLVMBuildExtractElement(builder, clipmask,
#endif ind1, "");
clipmask2 = LLVMBuildExtractElement(builder, clipmask,
ind2, "");
clipmask3 = LLVMBuildExtractElement(builder, clipmask,
ind3, "");
store_aos(builder, io0_ptr, attr_index, aos[0]); #if DEBUG_STORE
store_aos(builder, io1_ptr, attr_index, aos[1]); lp_build_printf(builder, "io = %p, indexes[%d, %d, %d, %d]\n, clipmask0 = %x, clipmask1 = %x, clipmask2 = %x, clipmask3 = %x\n",
store_aos(builder, io2_ptr, attr_index, aos[2]); io_ptr, ind0, ind1, ind2, ind3, clipmask0, clipmask1, clipmask2, clipmask3);
store_aos(builder, io3_ptr, attr_index, aos[3]); #endif
/* store for each of the 4 vertices */
store_aos(builder, io0_ptr, attr_index, aos[0], clipmask0);
store_aos(builder, io1_ptr, attr_index, aos[1], clipmask1);
store_aos(builder, io2_ptr, attr_index, aos[2], clipmask2);
store_aos(builder, io3_ptr, attr_index, aos[3], clipmask3);
} }
static void static void
convert_to_aos(LLVMBuilderRef builder, convert_to_aos(LLVMBuilderRef builder,
LLVMValueRef io, LLVMValueRef io,
LLVMValueRef (*outputs)[NUM_CHANNELS], LLVMValueRef (*outputs)[NUM_CHANNELS],
LLVMValueRef clipmask,
int num_outputs, int num_outputs,
int max_vertices) int max_vertices)
{ {
@ -680,13 +701,305 @@ convert_to_aos(LLVMBuilderRef builder,
io, io,
aos, aos,
attrib, attrib,
num_outputs); num_outputs,
clipmask);
} }
#if DEBUG_STORE #if DEBUG_STORE
lp_build_printf(builder, " # storing end\n"); lp_build_printf(builder, " # storing end\n");
#endif #endif
} }
/*
* Stores original vertex positions in clip coordinates
* There is probably a more efficient way to do this, 4 floats at once
* rather than extracting each element one by one.
*/
static void
store_clip(LLVMBuilderRef builder,
LLVMValueRef io_ptr,
LLVMValueRef (*outputs)[NUM_CHANNELS])
{
LLVMValueRef out[4];
LLVMValueRef indices[2];
LLVMValueRef io0_ptr, io1_ptr, io2_ptr, io3_ptr;
LLVMValueRef clip_ptr0, clip_ptr1, clip_ptr2, clip_ptr3;
LLVMValueRef clip0_ptr, clip1_ptr, clip2_ptr, clip3_ptr;
LLVMValueRef out0elem, out1elem, out2elem, out3elem;
int i;
LLVMValueRef ind0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
LLVMValueRef ind1 = LLVMConstInt(LLVMInt32Type(), 1, 0);
LLVMValueRef ind2 = LLVMConstInt(LLVMInt32Type(), 2, 0);
LLVMValueRef ind3 = LLVMConstInt(LLVMInt32Type(), 3, 0);
indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
indices[1] = LLVMConstInt(LLVMInt32Type(), 0, 0);
out[0] = LLVMBuildLoad(builder, outputs[0][0], ""); /*x0 x1 x2 x3*/
out[1] = LLVMBuildLoad(builder, outputs[0][1], ""); /*y0 y1 y2 y3*/
out[2] = LLVMBuildLoad(builder, outputs[0][2], ""); /*z0 z1 z2 z3*/
out[3] = LLVMBuildLoad(builder, outputs[0][3], ""); /*w0 w1 w2 w3*/
io0_ptr = LLVMBuildGEP(builder, io_ptr, &ind0, 1, "");
io1_ptr = LLVMBuildGEP(builder, io_ptr, &ind1, 1, "");
io2_ptr = LLVMBuildGEP(builder, io_ptr, &ind2, 1, "");
io3_ptr = LLVMBuildGEP(builder, io_ptr, &ind3, 1, "");
clip_ptr0 = draw_jit_header_clip(builder, io0_ptr);
clip_ptr1 = draw_jit_header_clip(builder, io1_ptr);
clip_ptr2 = draw_jit_header_clip(builder, io2_ptr);
clip_ptr3 = draw_jit_header_clip(builder, io3_ptr);
for (i = 0; i<4; i++){
clip0_ptr = LLVMBuildGEP(builder, clip_ptr0,
indices, 2, ""); //x0
clip1_ptr = LLVMBuildGEP(builder, clip_ptr1,
indices, 2, ""); //x1
clip2_ptr = LLVMBuildGEP(builder, clip_ptr2,
indices, 2, ""); //x2
clip3_ptr = LLVMBuildGEP(builder, clip_ptr3,
indices, 2, ""); //x3
out0elem = LLVMBuildExtractElement(builder, out[i],
ind0, ""); //x0
out1elem = LLVMBuildExtractElement(builder, out[i],
ind1, ""); //x1
out2elem = LLVMBuildExtractElement(builder, out[i],
ind2, ""); //x2
out3elem = LLVMBuildExtractElement(builder, out[i],
ind3, ""); //x3
LLVMBuildStore(builder, out0elem, clip0_ptr);
LLVMBuildStore(builder, out1elem, clip1_ptr);
LLVMBuildStore(builder, out2elem, clip2_ptr);
LLVMBuildStore(builder, out3elem, clip3_ptr);
indices[1]= LLVMBuildAdd(builder, indices[1], ind1, "");
}
}
/* Equivalent of _mm_set1_ps(a)
*/
static LLVMValueRef vec4f_from_scalar(LLVMBuilderRef bld,
LLVMValueRef a,
const char *name)
{
LLVMValueRef res = LLVMGetUndef(LLVMVectorType(LLVMFloatType(), 4));
int i;
for(i = 0; i < 4; ++i) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
res = LLVMBuildInsertElement(bld, res, a, index, i == 3 ? name : "");
}
return res;
}
/*
* Transforms the outputs for viewport mapping
*/
static void
generate_viewport(struct draw_llvm *llvm,
LLVMBuilderRef builder,
LLVMValueRef (*outputs)[NUM_CHANNELS],
LLVMValueRef context_ptr)
{
int i;
struct lp_type f32_type = lp_type_float_vec(32);
LLVMValueRef out3 = LLVMBuildLoad(builder, outputs[0][3], ""); /*w0 w1 w2 w3*/
LLVMValueRef const1 = lp_build_const_vec(f32_type, 1.0); /*1.0 1.0 1.0 1.0*/
LLVMValueRef vp_ptr = draw_jit_context_viewport(builder, context_ptr);
/* for 1/w convention*/
out3 = LLVMBuildFDiv(builder, const1, out3, "");
LLVMBuildStore(builder, out3, outputs[0][3]);
/* Viewport Mapping */
for (i=0; i<3; i++){
LLVMValueRef out = LLVMBuildLoad(builder, outputs[0][i], ""); /*x0 x1 x2 x3*/
LLVMValueRef scale;
LLVMValueRef trans;
LLVMValueRef scale_i;
LLVMValueRef trans_i;
LLVMValueRef index;
index = LLVMConstInt(LLVMInt32Type(), i, 0);
scale_i = LLVMBuildGEP(builder, vp_ptr, &index, 1, "");
index = LLVMConstInt(LLVMInt32Type(), i+4, 0);
trans_i = LLVMBuildGEP(builder, vp_ptr, &index, 1, "");
scale = vec4f_from_scalar(builder, LLVMBuildLoad(builder, scale_i, ""), "scale");
trans = vec4f_from_scalar(builder, LLVMBuildLoad(builder, trans_i, ""), "trans");
/* divide by w */
out = LLVMBuildFMul(builder, out, out3, "");
/* mult by scale */
out = LLVMBuildFMul(builder, out, scale, "");
/* add translation */
out = LLVMBuildFAdd(builder, out, trans, "");
/* store transformed outputs */
LLVMBuildStore(builder, out, outputs[0][i]);
}
}
/*
* Returns clipmask as 4xi32 bitmask for the 4 vertices
*/
static LLVMValueRef
generate_clipmask(LLVMBuilderRef builder,
LLVMValueRef (*outputs)[NUM_CHANNELS],
boolean clip_xy,
boolean clip_z,
boolean clip_user,
boolean clip_halfz,
unsigned nr,
LLVMValueRef context_ptr)
{
LLVMValueRef mask; /* stores the <4xi32> clipmasks */
LLVMValueRef test, temp;
LLVMValueRef zero, shift;
LLVMValueRef pos_x, pos_y, pos_z, pos_w;
LLVMValueRef plane1, planes, plane_ptr, sum;
unsigned i;
struct lp_type f32_type = lp_type_float_vec(32);
mask = lp_build_const_int_vec(lp_type_int_vec(32), 0);
temp = lp_build_const_int_vec(lp_type_int_vec(32), 0);
zero = lp_build_const_vec(f32_type, 0); /* 0.0f 0.0f 0.0f 0.0f */
shift = lp_build_const_int_vec(lp_type_int_vec(32), 1); /* 1 1 1 1 */
/* Assuming position stored at output[0] */
pos_x = LLVMBuildLoad(builder, outputs[0][0], ""); /*x0 x1 x2 x3*/
pos_y = LLVMBuildLoad(builder, outputs[0][1], ""); /*y0 y1 y2 y3*/
pos_z = LLVMBuildLoad(builder, outputs[0][2], ""); /*z0 z1 z2 z3*/
pos_w = LLVMBuildLoad(builder, outputs[0][3], ""); /*w0 w1 w2 w3*/
/* Cliptest, for hardwired planes */
if (clip_xy){
/* plane 1 */
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, pos_x , pos_w);
temp = shift;
test = LLVMBuildAnd(builder, test, temp, "");
mask = test;
/* plane 2 */
test = LLVMBuildFAdd(builder, pos_x, pos_w, "");
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, test);
temp = LLVMBuildShl(builder, temp, shift, "");
test = LLVMBuildAnd(builder, test, temp, "");
mask = LLVMBuildOr(builder, mask, test, "");
/* plane 3 */
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, pos_y, pos_w);
temp = LLVMBuildShl(builder, temp, shift, "");
test = LLVMBuildAnd(builder, test, temp, "");
mask = LLVMBuildOr(builder, mask, test, "");
/* plane 4 */
test = LLVMBuildFAdd(builder, pos_y, pos_w, "");
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, test);
temp = LLVMBuildShl(builder, temp, shift, "");
test = LLVMBuildAnd(builder, test, temp, "");
mask = LLVMBuildOr(builder, mask, test, "");
}
if (clip_z){
temp = lp_build_const_int_vec(lp_type_int_vec(32), 16);
if (clip_halfz){
/* plane 5 */
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, pos_z);
test = LLVMBuildAnd(builder, test, temp, "");
mask = LLVMBuildOr(builder, mask, test, "");
}
else{
/* plane 5 */
test = LLVMBuildFAdd(builder, pos_z, pos_w, "");
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, test);
test = LLVMBuildAnd(builder, test, temp, "");
mask = LLVMBuildOr(builder, mask, test, "");
}
/* plane 6 */
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, pos_z, pos_w);
temp = LLVMBuildShl(builder, temp, shift, "");
test = LLVMBuildAnd(builder, test, temp, "");
mask = LLVMBuildOr(builder, mask, test, "");
}
if (clip_user){
LLVMValueRef planes_ptr = draw_jit_context_planes(builder, context_ptr);
LLVMValueRef indices[3];
temp = lp_build_const_int_vec(lp_type_int_vec(32), 32);
/* userclip planes */
for (i = 6; i < nr; i++) {
indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
indices[1] = LLVMConstInt(LLVMInt32Type(), i, 0);
indices[2] = LLVMConstInt(LLVMInt32Type(), 0, 0);
plane_ptr = LLVMBuildGEP(builder, planes_ptr, indices, 3, "");
plane1 = LLVMBuildLoad(builder, plane_ptr, "plane_x");
planes = vec4f_from_scalar(builder, plane1, "plane4_x");
sum = LLVMBuildFMul(builder, planes, pos_x, "");
indices[2] = LLVMConstInt(LLVMInt32Type(), 1, 0);
plane_ptr = LLVMBuildGEP(builder, planes_ptr, indices, 3, "");
plane1 = LLVMBuildLoad(builder, plane_ptr, "plane_y");
planes = vec4f_from_scalar(builder, plane1, "plane4_y");
test = LLVMBuildFMul(builder, planes, pos_y, "");
sum = LLVMBuildFAdd(builder, sum, test, "");
indices[2] = LLVMConstInt(LLVMInt32Type(), 2, 0);
plane_ptr = LLVMBuildGEP(builder, planes_ptr, indices, 3, "");
plane1 = LLVMBuildLoad(builder, plane_ptr, "plane_z");
planes = vec4f_from_scalar(builder, plane1, "plane4_z");
test = LLVMBuildFMul(builder, planes, pos_z, "");
sum = LLVMBuildFAdd(builder, sum, test, "");
indices[2] = LLVMConstInt(LLVMInt32Type(), 3, 0);
plane_ptr = LLVMBuildGEP(builder, planes_ptr, indices, 3, "");
plane1 = LLVMBuildLoad(builder, plane_ptr, "plane_w");
planes = vec4f_from_scalar(builder, plane1, "plane4_w");
test = LLVMBuildFMul(builder, planes, pos_w, "");
sum = LLVMBuildFAdd(builder, sum, test, "");
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, sum);
temp = LLVMBuildShl(builder, temp, shift, "");
test = LLVMBuildAnd(builder, test, temp, "");
mask = LLVMBuildOr(builder, mask, test, "");
}
}
return mask;
}
/*
* Returns boolean if any clipping has occurred
* Used zero/non-zero i32 value to represent boolean
*/
static void
clipmask_bool(LLVMBuilderRef builder,
LLVMValueRef clipmask,
LLVMValueRef ret_ptr)
{
LLVMValueRef ret = LLVMBuildLoad(builder, ret_ptr, "");
LLVMValueRef temp;
int i;
for (i=0; i<4; i++){
temp = LLVMBuildExtractElement(builder, clipmask,
LLVMConstInt(LLVMInt32Type(), i, 0) , "");
ret = LLVMBuildOr(builder, ret, temp, "");
}
LLVMBuildStore(builder, ret, ret_ptr);
}
static void static void
draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant) draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
{ {
@ -706,6 +1019,11 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS]; LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS];
void *code; void *code;
struct lp_build_sampler_soa *sampler = 0; struct lp_build_sampler_soa *sampler = 0;
LLVMValueRef ret, ret_ptr;
boolean bypass_viewport = variant->key.bypass_viewport;
boolean enable_cliptest = variant->key.clip_xy ||
variant->key.clip_z ||
variant->key.clip_user;
arg_types[0] = llvm->context_ptr_type; /* context */ arg_types[0] = llvm->context_ptr_type; /* context */
arg_types[1] = llvm->vertex_header_ptr_type; /* vertex_header */ arg_types[1] = llvm->vertex_header_ptr_type; /* vertex_header */
@ -716,7 +1034,7 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */ arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */
arg_types[7] = LLVMInt32Type(); /* instance_id */ arg_types[7] = LLVMInt32Type(); /* instance_id */
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0); func_type = LLVMFunctionType(LLVMInt32Type(), arg_types, Elements(arg_types), 0);
variant->function = LLVMAddFunction(llvm->module, "draw_llvm_shader", func_type); variant->function = LLVMAddFunction(llvm->module, "draw_llvm_shader", func_type);
LLVMSetFunctionCallConv(variant->function, LLVMCCallConv); LLVMSetFunctionCallConv(variant->function, LLVMCCallConv);
@ -756,6 +1074,10 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
step = LLVMConstInt(LLVMInt32Type(), max_vertices, 0); step = LLVMConstInt(LLVMInt32Type(), max_vertices, 0);
/* function will return non-zero i32 value if any clipped vertices */
ret_ptr = lp_build_alloca(builder, LLVMInt32Type(), "");
LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), 0, 0), ret_ptr);
/* code generated texture sampling */ /* code generated texture sampling */
sampler = draw_llvm_sampler_soa_create( sampler = draw_llvm_sampler_soa_create(
draw_llvm_variant_key_samplers(&variant->key), draw_llvm_variant_key_samplers(&variant->key),
@ -770,6 +1092,7 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS]; LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
LLVMValueRef aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } }; LLVMValueRef aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } };
LLVMValueRef io; LLVMValueRef io;
LLVMValueRef clipmask; /* holds the clipmask value */
const LLVMValueRef (*ptr_aos)[NUM_CHANNELS]; const LLVMValueRef (*ptr_aos)[NUM_CHANNELS];
io_itr = LLVMBuildSub(builder, lp_loop.counter, start, ""); io_itr = LLVMBuildSub(builder, lp_loop.counter, start, "");
@ -806,10 +1129,37 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
context_ptr, context_ptr,
sampler); sampler);
convert_to_aos(builder, io, outputs, /* store original positions in clip before further manipulation */
store_clip(builder, io, outputs);
/* do cliptest */
if (enable_cliptest){
/* allocate clipmask, assign it integer type */
clipmask = generate_clipmask(builder, outputs,
variant->key.clip_xy,
variant->key.clip_z,
variant->key.clip_user,
variant->key.clip_halfz,
variant->key.nr_planes,
context_ptr);
/* return clipping boolean value for function */
clipmask_bool(builder, clipmask, ret_ptr);
}
else{
clipmask = lp_build_const_int_vec(lp_type_int_vec(32), 0);
}
/* do viewport mapping */
if (!bypass_viewport){
generate_viewport(llvm, builder, outputs, context_ptr);
}
/* store clipmask in vertex header and positions in data */
convert_to_aos(builder, io, outputs, clipmask,
draw->vs.vertex_shader->info.num_outputs, draw->vs.vertex_shader->info.num_outputs,
max_vertices); max_vertices);
} }
lp_build_loop_end_cond(builder, end, step, LLVMIntUGE, &lp_loop); lp_build_loop_end_cond(builder, end, step, LLVMIntUGE, &lp_loop);
sampler->destroy(sampler); sampler->destroy(sampler);
@ -819,7 +1169,8 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0); lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0);
#endif #endif
LLVMBuildRetVoid(builder); ret = LLVMBuildLoad(builder, ret_ptr,"");
LLVMBuildRet(builder, ret);
LLVMDisposeBuilder(builder); LLVMDisposeBuilder(builder);
@ -870,6 +1221,11 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
LLVMValueRef fetch_max; LLVMValueRef fetch_max;
void *code; void *code;
struct lp_build_sampler_soa *sampler = 0; struct lp_build_sampler_soa *sampler = 0;
LLVMValueRef ret, ret_ptr;
boolean bypass_viewport = variant->key.bypass_viewport;
boolean enable_cliptest = variant->key.clip_xy ||
variant->key.clip_z ||
variant->key.clip_user;
arg_types[0] = llvm->context_ptr_type; /* context */ arg_types[0] = llvm->context_ptr_type; /* context */
arg_types[1] = llvm->vertex_header_ptr_type; /* vertex_header */ arg_types[1] = llvm->vertex_header_ptr_type; /* vertex_header */
@ -880,10 +1236,9 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */ arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */
arg_types[7] = LLVMInt32Type(); /* instance_id */ arg_types[7] = LLVMInt32Type(); /* instance_id */
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0); func_type = LLVMFunctionType(LLVMInt32Type(), arg_types, Elements(arg_types), 0);
variant->function_elts = LLVMAddFunction(llvm->module, "draw_llvm_shader_elts", variant->function_elts = LLVMAddFunction(llvm->module, "draw_llvm_shader_elts", func_type);
func_type);
LLVMSetFunctionCallConv(variant->function_elts, LLVMCCallConv); LLVMSetFunctionCallConv(variant->function_elts, LLVMCCallConv);
for(i = 0; i < Elements(arg_types); ++i) for(i = 0; i < Elements(arg_types); ++i)
if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind) if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
@ -929,11 +1284,16 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
LLVMConstInt(LLVMInt32Type(), 1, 0), LLVMConstInt(LLVMInt32Type(), 1, 0),
"fetch_max"); "fetch_max");
/* function returns non-zero i32 value if any clipped vertices */
ret_ptr = lp_build_alloca(builder, LLVMInt32Type(), "");
LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), 0, 0), ret_ptr);
lp_build_loop_begin(builder, LLVMConstInt(LLVMInt32Type(), 0, 0), &lp_loop); lp_build_loop_begin(builder, LLVMConstInt(LLVMInt32Type(), 0, 0), &lp_loop);
{ {
LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS]; LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
LLVMValueRef aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } }; LLVMValueRef aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } };
LLVMValueRef io; LLVMValueRef io;
LLVMValueRef clipmask; /* holds the clipmask value */
const LLVMValueRef (*ptr_aos)[NUM_CHANNELS]; const LLVMValueRef (*ptr_aos)[NUM_CHANNELS];
io_itr = lp_loop.counter; io_itr = lp_loop.counter;
@ -980,10 +1340,40 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
context_ptr, context_ptr,
sampler); sampler);
convert_to_aos(builder, io, outputs, /* store original positions in clip before further manipulation */
store_clip(builder, io, outputs);
/* do cliptest */
if (enable_cliptest){
/* allocate clipmask, assign it integer type */
clipmask = generate_clipmask(builder, outputs,
variant->key.clip_xy,
variant->key.clip_z,
variant->key.clip_user,
variant->key.clip_halfz,
variant->key.nr_planes,
context_ptr);
/* return clipping boolean value for function */
clipmask_bool(builder, clipmask, ret_ptr);
}
else{
clipmask = lp_build_const_int_vec(lp_type_int_vec(32), 0);
}
/* do viewport mapping */
if (!bypass_viewport){
generate_viewport(llvm, builder, outputs, context_ptr);
}
/* store clipmask in vertex header,
* original positions in clip
* and transformed positions in data
*/
convert_to_aos(builder, io, outputs, clipmask,
draw->vs.vertex_shader->info.num_outputs, draw->vs.vertex_shader->info.num_outputs,
max_vertices); max_vertices);
} }
lp_build_loop_end_cond(builder, fetch_count, step, LLVMIntUGE, &lp_loop); lp_build_loop_end_cond(builder, fetch_count, step, LLVMIntUGE, &lp_loop);
sampler->destroy(sampler); sampler->destroy(sampler);
@ -993,7 +1383,8 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0); lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0);
#endif #endif
LLVMBuildRetVoid(builder); ret = LLVMBuildLoad(builder, ret_ptr,"");
LLVMBuildRet(builder, ret);
LLVMDisposeBuilder(builder); LLVMDisposeBuilder(builder);
@ -1038,6 +1429,16 @@ draw_llvm_make_variant_key(struct draw_llvm *llvm, char *store)
*/ */
key->nr_vertex_elements = llvm->draw->pt.nr_vertex_elements; key->nr_vertex_elements = llvm->draw->pt.nr_vertex_elements;
/* will have to rig this up properly later */
key->clip_xy = llvm->draw->clip_xy;
key->clip_z = llvm->draw->clip_z;
key->clip_user = llvm->draw->clip_user;
key->bypass_viewport = llvm->draw->identity_viewport;
key->clip_halfz = !llvm->draw->rasterizer->gl_rasterization_rules;
key->need_edgeflags = (llvm->draw->vs.edgeflag_output ? TRUE : FALSE);
key->nr_planes = llvm->draw->nr_planes;
key->pad = 0;
/* All variants of this shader will have the same value for /* All variants of this shader will have the same value for
* nr_samplers. Not yet trying to compact away holes in the * nr_samplers. Not yet trying to compact away holes in the
* sampler array. * sampler array.
@ -1066,9 +1467,9 @@ draw_llvm_set_mapped_texture(struct draw_context *draw,
unsigned sampler_idx, unsigned sampler_idx,
uint32_t width, uint32_t height, uint32_t depth, uint32_t width, uint32_t height, uint32_t depth,
uint32_t last_level, uint32_t last_level,
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS], uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS], uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
const void *data[DRAW_MAX_TEXTURE_LEVELS]) const void *data[PIPE_MAX_TEXTURE_LEVELS])
{ {
unsigned j; unsigned j;
struct draw_jit_texture *jit_tex; struct draw_jit_texture *jit_tex;

View file

@ -41,7 +41,6 @@
#include <llvm-c/Target.h> #include <llvm-c/Target.h>
#include <llvm-c/ExecutionEngine.h> #include <llvm-c/ExecutionEngine.h>
#define DRAW_MAX_TEXTURE_LEVELS 13 /* 4K x 4K for now */
struct draw_llvm; struct draw_llvm;
struct llvm_vertex_shader; struct llvm_vertex_shader;
@ -52,9 +51,9 @@ struct draw_jit_texture
uint32_t height; uint32_t height;
uint32_t depth; uint32_t depth;
uint32_t last_level; uint32_t last_level;
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS]; uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS];
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS]; uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS];
const void *data[DRAW_MAX_TEXTURE_LEVELS]; const void *data[PIPE_MAX_TEXTURE_LEVELS];
float min_lod; float min_lod;
float max_lod; float max_lod;
float lod_bias; float lod_bias;
@ -97,7 +96,8 @@ struct draw_jit_context
{ {
const float *vs_constants; const float *vs_constants;
const float *gs_constants; const float *gs_constants;
float (*planes) [12][4];
float *viewport;
struct draw_jit_texture textures[PIPE_MAX_VERTEX_SAMPLERS]; struct draw_jit_texture textures[PIPE_MAX_VERTEX_SAMPLERS];
}; };
@ -109,18 +109,22 @@ struct draw_jit_context
#define draw_jit_context_gs_constants(_builder, _ptr) \ #define draw_jit_context_gs_constants(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 1, "gs_constants") lp_build_struct_get(_builder, _ptr, 1, "gs_constants")
#define DRAW_JIT_CTX_TEXTURES 2 #define draw_jit_context_planes(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 2, "planes")
#define draw_jit_context_viewport(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 3, "viewport")
#define DRAW_JIT_CTX_TEXTURES 4
#define draw_jit_context_textures(_builder, _ptr) \ #define draw_jit_context_textures(_builder, _ptr) \
lp_build_struct_get_ptr(_builder, _ptr, DRAW_JIT_CTX_TEXTURES, "textures") lp_build_struct_get_ptr(_builder, _ptr, DRAW_JIT_CTX_TEXTURES, "textures")
#define draw_jit_header_id(_builder, _ptr) \ #define draw_jit_header_id(_builder, _ptr) \
lp_build_struct_get_ptr(_builder, _ptr, 0, "id") lp_build_struct_get_ptr(_builder, _ptr, 0, "id")
#define draw_jit_header_clip(_builder, _ptr) \ #define draw_jit_header_clip(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 1, "clip") lp_build_struct_get_ptr(_builder, _ptr, 1, "clip")
#define draw_jit_header_data(_builder, _ptr) \ #define draw_jit_header_data(_builder, _ptr) \
lp_build_struct_get_ptr(_builder, _ptr, 2, "data") lp_build_struct_get_ptr(_builder, _ptr, 2, "data")
@ -136,7 +140,7 @@ struct draw_jit_context
lp_build_struct_get(_builder, _ptr, 2, "buffer_offset") lp_build_struct_get(_builder, _ptr, 2, "buffer_offset")
typedef void typedef int
(*draw_jit_vert_func)(struct draw_jit_context *context, (*draw_jit_vert_func)(struct draw_jit_context *context,
struct vertex_header *io, struct vertex_header *io,
const char *vbuffers[PIPE_MAX_ATTRIBS], const char *vbuffers[PIPE_MAX_ATTRIBS],
@ -147,7 +151,7 @@ typedef void
unsigned instance_id); unsigned instance_id);
typedef void typedef int
(*draw_jit_vert_func_elts)(struct draw_jit_context *context, (*draw_jit_vert_func_elts)(struct draw_jit_context *context,
struct vertex_header *io, struct vertex_header *io,
const char *vbuffers[PIPE_MAX_ATTRIBS], const char *vbuffers[PIPE_MAX_ATTRIBS],
@ -159,8 +163,16 @@ typedef void
struct draw_llvm_variant_key struct draw_llvm_variant_key
{ {
unsigned nr_vertex_elements:16; unsigned nr_vertex_elements:8;
unsigned nr_samplers:16; unsigned nr_samplers:8;
unsigned clip_xy:1;
unsigned clip_z:1;
unsigned clip_user:1;
unsigned clip_halfz:1;
unsigned bypass_viewport:1;
unsigned need_edgeflags:1;
unsigned nr_planes:4;
unsigned pad:6;
/* Variable number of vertex elements: /* Variable number of vertex elements:
*/ */
@ -290,8 +302,8 @@ draw_llvm_set_mapped_texture(struct draw_context *draw,
unsigned sampler_idx, unsigned sampler_idx,
uint32_t width, uint32_t height, uint32_t depth, uint32_t width, uint32_t height, uint32_t depth,
uint32_t last_level, uint32_t last_level,
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS], uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS], uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
const void *data[DRAW_MAX_TEXTURE_LEVELS]); const void *data[PIPE_MAX_TEXTURE_LEVELS]);
#endif #endif

View file

@ -169,6 +169,9 @@ struct draw_context
unsigned vs_constants_size[PIPE_MAX_CONSTANT_BUFFERS]; unsigned vs_constants_size[PIPE_MAX_CONSTANT_BUFFERS];
const void *gs_constants[PIPE_MAX_CONSTANT_BUFFERS]; const void *gs_constants[PIPE_MAX_CONSTANT_BUFFERS];
unsigned gs_constants_size[PIPE_MAX_CONSTANT_BUFFERS]; unsigned gs_constants_size[PIPE_MAX_CONSTANT_BUFFERS];
/* pointer to planes */
float (*planes)[12][4];
} user; } user;
boolean test_fse; /* enable FSE even though its not correct (eg for softpipe) */ boolean test_fse; /* enable FSE even though its not correct (eg for softpipe) */

View file

@ -287,6 +287,84 @@ draw_print_arrays(struct draw_context *draw, uint prim, int start, uint count)
} }
/** Helper code for below */
#define PRIM_RESTART_LOOP(elements) \
do { \
for (i = start; i < end; i++) { \
if (elements[i] == info->restart_index) { \
if (cur_count > 0) { \
/* draw elts up to prev pos */ \
draw_pt_arrays(draw, prim, cur_start, cur_count); \
} \
/* begin new prim at next elt */ \
cur_start = i + 1; \
cur_count = 0; \
} \
else { \
cur_count++; \
} \
} \
if (cur_count > 0) { \
draw_pt_arrays(draw, prim, cur_start, cur_count); \
} \
} while (0)
/**
* For drawing prims with primitive restart enabled.
* Scan for restart indexes and draw the runs of elements/vertices between
* the restarts.
*/
static void
draw_pt_arrays_restart(struct draw_context *draw,
const struct pipe_draw_info *info)
{
const unsigned prim = info->mode;
const unsigned start = info->start;
const unsigned count = info->count;
const unsigned end = start + count;
unsigned i, cur_start, cur_count;
assert(info->primitive_restart);
if (draw->pt.user.elts) {
/* indexed prims (draw_elements) */
cur_start = start;
cur_count = 0;
switch (draw->pt.user.eltSize) {
case 1:
{
const ubyte *elt_ub = (const ubyte *) draw->pt.user.elts;
PRIM_RESTART_LOOP(elt_ub);
}
break;
case 2:
{
const ushort *elt_us = (const ushort *) draw->pt.user.elts;
PRIM_RESTART_LOOP(elt_us);
}
break;
case 4:
{
const uint *elt_ui = (const uint *) draw->pt.user.elts;
PRIM_RESTART_LOOP(elt_ui);
}
break;
default:
assert(0 && "bad eltSize in draw_arrays()");
}
}
else {
/* Non-indexed prims (draw_arrays).
* Primitive restart should have been handled in the state tracker.
*/
draw_pt_arrays(draw, prim, start, count);
}
}
/** /**
* Non-instanced drawing. * Non-instanced drawing.
* \sa draw_arrays_instanced * \sa draw_arrays_instanced
@ -395,6 +473,12 @@ draw_vbo(struct draw_context *draw,
for (instance = 0; instance < info->instance_count; instance++) { for (instance = 0; instance < info->instance_count; instance++) {
draw->instance_id = instance + info->start_instance; draw->instance_id = instance + info->start_instance;
if (info->primitive_restart) {
draw_pt_arrays_restart(draw, info);
}
else {
draw_pt_arrays(draw, info->mode, info->start, info->count); draw_pt_arrays(draw, info->mode, info->start, info->count);
} }
} }
}

View file

@ -175,6 +175,11 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
draw->pt.user.vs_constants[0]; draw->pt.user.vs_constants[0];
fpme->llvm->jit_context.gs_constants = fpme->llvm->jit_context.gs_constants =
draw->pt.user.gs_constants[0]; draw->pt.user.gs_constants[0];
fpme->llvm->jit_context.planes =
(float (*) [12][4]) draw->pt.user.planes[0];
fpme->llvm->jit_context.viewport =
(float *)draw->viewport.scale;
} }
@ -217,6 +222,7 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
struct draw_vertex_info gs_vert_info; struct draw_vertex_info gs_vert_info;
struct draw_vertex_info *vert_info; struct draw_vertex_info *vert_info;
unsigned opt = fpme->opt; unsigned opt = fpme->opt;
unsigned clipped = 0;
llvm_vert_info.count = fetch_info->count; llvm_vert_info.count = fetch_info->count;
llvm_vert_info.vertex_size = fpme->vertex_size; llvm_vert_info.vertex_size = fpme->vertex_size;
@ -230,7 +236,7 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
} }
if (fetch_info->linear) if (fetch_info->linear)
fpme->current_variant->jit_func( &fpme->llvm->jit_context, clipped = fpme->current_variant->jit_func( &fpme->llvm->jit_context,
llvm_vert_info.verts, llvm_vert_info.verts,
(const char **)draw->pt.user.vbuffer, (const char **)draw->pt.user.vbuffer,
fetch_info->start, fetch_info->start,
@ -239,7 +245,7 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
draw->pt.vertex_buffer, draw->pt.vertex_buffer,
draw->instance_id); draw->instance_id);
else else
fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context, clipped = fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context,
llvm_vert_info.verts, llvm_vert_info.verts,
(const char **)draw->pt.user.vbuffer, (const char **)draw->pt.user.vbuffer,
fetch_info->elts, fetch_info->elts,
@ -266,6 +272,9 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
FREE(vert_info->verts); FREE(vert_info->verts);
vert_info = &gs_vert_info; vert_info = &gs_vert_info;
prim_info = &gs_prim_info; prim_info = &gs_prim_info;
clipped = draw_pt_post_vs_run( fpme->post_vs, vert_info );
} }
/* stream output needs to be done before clipping */ /* stream output needs to be done before clipping */
@ -273,11 +282,11 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
vert_info, vert_info,
prim_info ); prim_info );
if (draw_pt_post_vs_run( fpme->post_vs, vert_info )) { if (clipped) {
opt |= PT_PIPELINE; opt |= PT_PIPELINE;
} }
/* Do we need to run the pipeline? /* Do we need to run the pipeline? Now will come here if clipped
*/ */
if (opt & PT_PIPELINE) { if (opt & PT_PIPELINE) {
pipeline( fpme, pipeline( fpme,

View file

@ -983,6 +983,12 @@ enum lp_build_round_sse41_mode
}; };
/**
* Helper for SSE4.1's ROUNDxx instructions.
*
* NOTE: In the SSE4.1's nearest mode, if two values are equally close, the
* result is the even value. That is, rounding 2.5 will be 2.0, and not 3.0.
*/
static INLINE LLVMValueRef static INLINE LLVMValueRef
lp_build_round_sse41(struct lp_build_context *bld, lp_build_round_sse41(struct lp_build_context *bld,
LLVMValueRef a, LLVMValueRef a,
@ -1053,10 +1059,58 @@ lp_build_round_sse41(struct lp_build_context *bld,
} }
static INLINE LLVMValueRef
lp_build_iround_nearest_sse2(struct lp_build_context *bld,
LLVMValueRef a)
{
const struct lp_type type = bld->type;
LLVMTypeRef i32t = LLVMInt32Type();
LLVMTypeRef ret_type = lp_build_int_vec_type(type);
const char *intrinsic;
LLVMValueRef res;
assert(type.floating);
/* using the double precision conversions is a bit more complicated */
assert(type.width == 32);
assert(lp_check_value(type, a));
assert(util_cpu_caps.has_sse2);
/* This is relying on MXCSR rounding mode, which should always be nearest. */
if (type.length == 1) {
LLVMTypeRef vec_type;
LLVMValueRef undef;
LLVMValueRef arg;
LLVMValueRef index0 = LLVMConstInt(i32t, 0, 0);
vec_type = LLVMVectorType(bld->elem_type, 4);
intrinsic = "llvm.x86.sse.cvtss2si";
undef = LLVMGetUndef(vec_type);
arg = LLVMBuildInsertElement(bld->builder, undef, a, index0, "");
res = lp_build_intrinsic_unary(bld->builder, intrinsic,
ret_type, arg);
}
else {
assert(type.width*type.length == 128);
intrinsic = "llvm.x86.sse2.cvtps2dq";
res = lp_build_intrinsic_unary(bld->builder, intrinsic,
ret_type, a);
}
return res;
}
/** /**
* Return the integer part of a float (vector) value. The returned value is * Return the integer part of a float (vector) value (== round toward zero).
* a float (vector). * The returned value is a float (vector).
* Ex: trunc(-1.5) = 1.0 * Ex: trunc(-1.5) = -1.0
*/ */
LLVMValueRef LLVMValueRef
lp_build_trunc(struct lp_build_context *bld, lp_build_trunc(struct lp_build_context *bld,
@ -1181,9 +1235,9 @@ lp_build_fract(struct lp_build_context *bld,
/** /**
* Return the integer part of a float (vector) value. The returned value is * Return the integer part of a float (vector) value (== round toward zero).
* an integer (vector). * The returned value is an integer (vector).
* Ex: itrunc(-1.5) = 1 * Ex: itrunc(-1.5) = -1
*/ */
LLVMValueRef LLVMValueRef
lp_build_itrunc(struct lp_build_context *bld, lp_build_itrunc(struct lp_build_context *bld,
@ -1217,7 +1271,11 @@ lp_build_iround(struct lp_build_context *bld,
assert(lp_check_value(type, a)); assert(lp_check_value(type, a));
if (util_cpu_caps.has_sse4_1 && if (util_cpu_caps.has_sse2 &&
((type.width == 32) && (type.length == 1 || type.length == 4))) {
return lp_build_iround_nearest_sse2(bld, a);
}
else if (util_cpu_caps.has_sse4_1 &&
(type.length == 1 || type.width*type.length == 128)) { (type.length == 1 || type.width*type.length == 128)) {
res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_NEAREST); res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_NEAREST);
} }
@ -1371,8 +1429,6 @@ lp_build_ifloor_fract(struct lp_build_context *bld,
LLVMValueRef *out_ipart, LLVMValueRef *out_ipart,
LLVMValueRef *out_fpart) LLVMValueRef *out_fpart)
{ {
const struct lp_type type = bld->type; const struct lp_type type = bld->type;
LLVMValueRef ipart; LLVMValueRef ipart;
@ -2209,6 +2265,71 @@ lp_build_exp2(struct lp_build_context *bld,
} }
/**
* Extract the exponent of a IEEE-754 floating point value.
*
* Optionally apply an integer bias.
*
* Result is an integer value with
*
* ifloor(log2(x)) + bias
*/
LLVMValueRef
lp_build_extract_exponent(struct lp_build_context *bld,
LLVMValueRef x,
int bias)
{
const struct lp_type type = bld->type;
unsigned mantissa = lp_mantissa(type);
LLVMValueRef res;
assert(type.floating);
assert(lp_check_value(bld->type, x));
x = LLVMBuildBitCast(bld->builder, x, bld->int_vec_type, "");
res = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
res = LLVMBuildAnd(bld->builder, res, lp_build_const_int_vec(type, 255), "");
res = LLVMBuildSub(bld->builder, res, lp_build_const_int_vec(type, 127 - bias), "");
return res;
}
/**
* Extract the mantissa of the a floating.
*
* Result is a floating point value with
*
* x / floor(log2(x))
*/
LLVMValueRef
lp_build_extract_mantissa(struct lp_build_context *bld,
LLVMValueRef x)
{
const struct lp_type type = bld->type;
unsigned mantissa = lp_mantissa(type);
LLVMValueRef mantmask = lp_build_const_int_vec(type, (1ULL << mantissa) - 1);
LLVMValueRef one = LLVMConstBitCast(bld->one, bld->int_vec_type);
LLVMValueRef res;
assert(lp_check_value(bld->type, x));
assert(type.floating);
x = LLVMBuildBitCast(bld->builder, x, bld->int_vec_type, "");
/* res = x / 2**ipart */
res = LLVMBuildAnd(bld->builder, x, mantmask, "");
res = LLVMBuildOr(bld->builder, res, one, "");
res = LLVMBuildBitCast(bld->builder, res, bld->vec_type, "");
return res;
}
/** /**
* Minimax polynomial fit of log2(x)/(x - 1), for x in range [1, 2[ * Minimax polynomial fit of log2(x)/(x - 1), for x in range [1, 2[
* These coefficients can be generate with * These coefficients can be generate with
@ -2333,7 +2454,10 @@ lp_build_log2(struct lp_build_context *bld,
/** /**
* Faster (and less accurate) log2. * Faster (and less accurate) log2.
* *
* log2(x) = floor(log2(x)) + frac(x) * log2(x) = floor(log2(x)) - 1 + x / 2**floor(log2(x))
*
* Piece-wise linear approximation, with exact results when x is a
* power of two.
* *
* See http://www.flipcode.com/archives/Fast_log_Function.shtml * See http://www.flipcode.com/archives/Fast_log_Function.shtml
*/ */
@ -2341,35 +2465,21 @@ LLVMValueRef
lp_build_fast_log2(struct lp_build_context *bld, lp_build_fast_log2(struct lp_build_context *bld,
LLVMValueRef x) LLVMValueRef x)
{ {
const struct lp_type type = bld->type;
LLVMTypeRef vec_type = bld->vec_type;
LLVMTypeRef int_vec_type = bld->int_vec_type;
unsigned mantissa = lp_mantissa(type);
LLVMValueRef mantmask = lp_build_const_int_vec(type, (1ULL << mantissa) - 1);
LLVMValueRef one = LLVMConstBitCast(bld->one, int_vec_type);
LLVMValueRef ipart; LLVMValueRef ipart;
LLVMValueRef fpart; LLVMValueRef fpart;
assert(lp_check_value(bld->type, x)); assert(lp_check_value(bld->type, x));
assert(type.floating); assert(bld->type.floating);
x = LLVMBuildBitCast(bld->builder, x, int_vec_type, "");
/* ipart = floor(log2(x)) - 1 */ /* ipart = floor(log2(x)) - 1 */
ipart = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), ""); ipart = lp_build_extract_exponent(bld, x, -1);
ipart = LLVMBuildAnd(bld->builder, ipart, lp_build_const_int_vec(type, 255), ""); ipart = LLVMBuildSIToFP(bld->builder, ipart, bld->vec_type, "");
ipart = LLVMBuildSub(bld->builder, ipart, lp_build_const_int_vec(type, 128), "");
ipart = LLVMBuildSIToFP(bld->builder, ipart, vec_type, "");
/* fpart = 1.0 + frac(x) */ /* fpart = x / 2**ipart */
fpart = LLVMBuildAnd(bld->builder, x, mantmask, ""); fpart = lp_build_extract_mantissa(bld, x);
fpart = LLVMBuildOr(bld->builder, fpart, one, "");
fpart = LLVMBuildBitCast(bld->builder, fpart, vec_type, "");
/* floor(log2(x)) + frac(x) */ /* ipart + fpart */
return LLVMBuildFAdd(bld->builder, ipart, fpart, ""); return LLVMBuildFAdd(bld->builder, ipart, fpart, "");
} }
@ -2383,27 +2493,18 @@ LLVMValueRef
lp_build_ilog2(struct lp_build_context *bld, lp_build_ilog2(struct lp_build_context *bld,
LLVMValueRef x) LLVMValueRef x)
{ {
const struct lp_type type = bld->type; LLVMValueRef sqrt2 = lp_build_const_vec(bld->type, M_SQRT2);
LLVMTypeRef int_vec_type = bld->int_vec_type;
unsigned mantissa = lp_mantissa(type);
LLVMValueRef sqrt2 = lp_build_const_vec(type, 1.4142135623730951);
LLVMValueRef ipart; LLVMValueRef ipart;
assert(lp_check_value(bld->type, x)); assert(bld->type.floating);
assert(type.floating); assert(lp_check_value(bld->type, x));
/* x * 2^(0.5) i.e., add 0.5 to the log2(x) */ /* x * 2^(0.5) i.e., add 0.5 to the log2(x) */
x = LLVMBuildFMul(bld->builder, x, sqrt2, ""); x = LLVMBuildFMul(bld->builder, x, sqrt2, "");
x = LLVMBuildBitCast(bld->builder, x, int_vec_type, "");
/* ipart = floor(log2(x) + 0.5) */ /* ipart = floor(log2(x) + 0.5) */
ipart = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), ""); ipart = lp_build_extract_exponent(bld, x, 0);
ipart = LLVMBuildAnd(bld->builder, ipart, lp_build_const_int_vec(type, 255), "");
ipart = LLVMBuildSub(bld->builder, ipart, lp_build_const_int_vec(type, 127), "");
return ipart; return ipart;
} }

View file

@ -214,6 +214,15 @@ LLVMValueRef
lp_build_exp2(struct lp_build_context *bld, lp_build_exp2(struct lp_build_context *bld,
LLVMValueRef a); LLVMValueRef a);
LLVMValueRef
lp_build_extract_exponent(struct lp_build_context *bld,
LLVMValueRef x,
int bias);
LLVMValueRef
lp_build_extract_mantissa(struct lp_build_context *bld,
LLVMValueRef x);
LLVMValueRef LLVMValueRef
lp_build_log2(struct lp_build_context *bld, lp_build_log2(struct lp_build_context *bld,
LLVMValueRef a); LLVMValueRef a);
@ -226,7 +235,6 @@ LLVMValueRef
lp_build_ilog2(struct lp_build_context *bld, lp_build_ilog2(struct lp_build_context *bld,
LLVMValueRef x); LLVMValueRef x);
void void
lp_build_exp2_approx(struct lp_build_context *bld, lp_build_exp2_approx(struct lp_build_context *bld,
LLVMValueRef x, LLVMValueRef x,

View file

@ -97,58 +97,104 @@ lp_build_clamped_float_to_unsigned_norm(LLVMBuilderRef builder,
LLVMTypeRef int_vec_type = lp_build_int_vec_type(src_type); LLVMTypeRef int_vec_type = lp_build_int_vec_type(src_type);
LLVMValueRef res; LLVMValueRef res;
unsigned mantissa; unsigned mantissa;
unsigned n;
assert(src_type.floating);
assert(dst_width <= src_type.width);
src_type.sign = FALSE;
mantissa = lp_mantissa(src_type);
if (dst_width <= mantissa) {
/*
* Apply magic coefficients that will make the desired result to appear
* in the lowest significant bits of the mantissa, with correct rounding.
*
* This only works if the destination width fits in the mantissa.
*/
unsigned long long ubound; unsigned long long ubound;
unsigned long long mask; unsigned long long mask;
double scale; double scale;
double bias; double bias;
assert(src_type.floating); ubound = (1ULL << dst_width);
mantissa = lp_mantissa(src_type);
/* We cannot carry more bits than the mantissa */
n = MIN2(mantissa, dst_width);
/* This magic coefficients will make the desired result to appear in the
* lowest significant bits of the mantissa.
*/
ubound = ((unsigned long long)1 << n);
mask = ubound - 1; mask = ubound - 1;
scale = (double)mask/ubound; scale = (double)mask/ubound;
bias = (double)((unsigned long long)1 << (mantissa - n)); bias = (double)(1ULL << (mantissa - dst_width));
res = LLVMBuildFMul(builder, src, lp_build_const_vec(src_type, scale), ""); res = LLVMBuildFMul(builder, src, lp_build_const_vec(src_type, scale), "");
res = LLVMBuildFAdd(builder, res, lp_build_const_vec(src_type, bias), ""); res = LLVMBuildFAdd(builder, res, lp_build_const_vec(src_type, bias), "");
res = LLVMBuildBitCast(builder, res, int_vec_type, ""); res = LLVMBuildBitCast(builder, res, int_vec_type, "");
if(dst_width > n) {
int shift = dst_width - n;
res = LLVMBuildShl(builder, res, lp_build_const_int_vec(src_type, shift), "");
/* TODO: Fill in the empty lower bits for additional precision? */
/* YES: this fixes progs/trivial/tri-z-eq.c.
* Otherwise vertex Z=1.0 values get converted to something like
* 0xfffffb00 and the test for equality with 0xffffffff fails.
*/
#if 0
{
LLVMValueRef msb;
msb = LLVMBuildLShr(builder, res, lp_build_const_int_vec(src_type, dst_width - 1), "");
msb = LLVMBuildShl(builder, msb, lp_build_const_int_vec(src_type, shift), "");
msb = LLVMBuildSub(builder, msb, lp_build_const_int_vec(src_type, 1), "");
res = LLVMBuildOr(builder, res, msb, "");
}
#elif 0
while(shift > 0) {
res = LLVMBuildOr(builder, res, LLVMBuildLShr(builder, res, lp_build_const_int_vec(src_type, n), ""), "");
shift -= n;
n *= 2;
}
#endif
}
else
res = LLVMBuildAnd(builder, res, lp_build_const_int_vec(src_type, mask), ""); res = LLVMBuildAnd(builder, res, lp_build_const_int_vec(src_type, mask), "");
}
else if (dst_width == (mantissa + 1)) {
/*
* The destination width matches exactly what can be represented in
* floating point (i.e., mantissa + 1 bits). So do a straight
* multiplication followed by casting. No further rounding is necessary.
*/
double scale;
scale = (double)((1ULL << dst_width) - 1);
res = LLVMBuildFMul(builder, src, lp_build_const_vec(src_type, scale), "");
res = LLVMBuildFPToSI(builder, res, int_vec_type, "");
}
else {
/*
* The destination exceeds what can be represented in the floating point.
* So multiply by the largest power two we get away with, and when
* subtract the most significant bit to rescale to normalized values.
*
* The largest power of two factor we can get away is
* (1 << (src_type.width - 1)), because we need to use signed . In theory it
* should be (1 << (src_type.width - 2)), but IEEE 754 rules states
* INT_MIN should be returned in FPToSI, which is the correct result for
* values near 1.0!
*
* This means we get (src_type.width - 1) correct bits for values near 0.0,
* and (mantissa + 1) correct bits for values near 1.0. Equally or more
* important, we also get exact results for 0.0 and 1.0.
*/
unsigned n = MIN2(src_type.width - 1, dst_width);
double scale = (double)(1ULL << n);
unsigned lshift = dst_width - n;
unsigned rshift = n;
LLVMValueRef lshifted;
LLVMValueRef rshifted;
res = LLVMBuildFMul(builder, src, lp_build_const_vec(src_type, scale), "");
res = LLVMBuildFPToSI(builder, res, int_vec_type, "");
/*
* Align the most significant bit to its final place.
*
* This will cause 1.0 to overflow to 0, but the later adjustment will
* get it right.
*/
if (lshift) {
lshifted = LLVMBuildShl(builder, res,
lp_build_const_int_vec(src_type, lshift), "");
} else {
lshifted = res;
}
/*
* Align the most significant bit to the right.
*/
rshifted = LLVMBuildAShr(builder, res,
lp_build_const_int_vec(src_type, rshift), "");
/*
* Subtract the MSB to the LSB, therefore re-scaling from
* (1 << dst_width) to ((1 << dst_width) - 1).
*/
res = LLVMBuildSub(builder, lshifted, rshifted, "");
}
return res; return res;
} }
@ -178,6 +224,16 @@ lp_build_unsigned_norm_to_float(LLVMBuilderRef builder,
assert(dst_type.floating); assert(dst_type.floating);
/* Special-case int8->float, though most cases could be handled
* this way:
*/
if (src_width == 8) {
scale = 1.0/255.0;
res = LLVMBuildSIToFP(builder, src, vec_type, "");
res = LLVMBuildFMul(builder, res, lp_build_const_vec(dst_type, scale), "");
return res;
}
mantissa = lp_mantissa(dst_type); mantissa = lp_mantissa(dst_type);
n = MIN2(mantissa, src_width); n = MIN2(mantissa, src_width);
@ -257,7 +313,9 @@ lp_build_conv(LLVMBuilderRef builder,
dst_type.sign == 0 && dst_type.sign == 0 &&
dst_type.norm == 1 && dst_type.norm == 1 &&
dst_type.width == 8 && dst_type.width == 8 &&
dst_type.length == 16) dst_type.length == 16 &&
util_cpu_caps.has_sse2)
{ {
int i; int i;
@ -296,23 +354,7 @@ lp_build_conv(LLVMBuilderRef builder,
c = LLVMBuildFMul(builder, src[2], const_255f, ""); c = LLVMBuildFMul(builder, src[2], const_255f, "");
d = LLVMBuildFMul(builder, src[3], const_255f, ""); d = LLVMBuildFMul(builder, src[3], const_255f, "");
/* lp_build_round generates excessively general code without {
* sse4, so do rounding manually.
*/
if (!util_cpu_caps.has_sse4_1) {
LLVMValueRef const_half = lp_build_const_vec(src_type, 0.5f);
a = LLVMBuildFAdd(builder, a, const_half, "");
b = LLVMBuildFAdd(builder, b, const_half, "");
c = LLVMBuildFAdd(builder, c, const_half, "");
d = LLVMBuildFAdd(builder, d, const_half, "");
src_int0 = LLVMBuildFPToSI(builder, a, int32_vec_type, "");
src_int1 = LLVMBuildFPToSI(builder, b, int32_vec_type, "");
src_int2 = LLVMBuildFPToSI(builder, c, int32_vec_type, "");
src_int3 = LLVMBuildFPToSI(builder, d, int32_vec_type, "");
}
else {
struct lp_build_context bld; struct lp_build_context bld;
bld.builder = builder; bld.builder = builder;
@ -329,7 +371,7 @@ lp_build_conv(LLVMBuilderRef builder,
src_int2 = lp_build_iround(&bld, c); src_int2 = lp_build_iround(&bld, c);
src_int3 = lp_build_iround(&bld, d); src_int3 = lp_build_iround(&bld, d);
} }
/* relying on clamping behavior of sse2 intrinsics here */
lo = lp_build_pack2(builder, int32_type, int16_type, src_int0, src_int1); lo = lp_build_pack2(builder, int32_type, int16_type, src_int0, src_int1);
hi = lp_build_pack2(builder, int32_type, int16_type, src_int2, src_int3); hi = lp_build_pack2(builder, int32_type, int16_type, src_int2, src_int3);
dst[i] = lp_build_pack2(builder, int16_type, dst_type, lo, hi); dst[i] = lp_build_pack2(builder, int16_type, dst_type, lo, hi);

View file

@ -57,6 +57,8 @@ lp_disassemble(const void* func)
#ifdef HAVE_UDIS86 #ifdef HAVE_UDIS86
ud_t ud_obj; ud_t ud_obj;
uint64_t max_jmp_pc; uint64_t max_jmp_pc;
uint inst_no;
boolean emit_addrs = TRUE, emit_line_nos = FALSE;
ud_init(&ud_obj); ud_init(&ud_obj);
@ -76,13 +78,18 @@ lp_disassemble(const void* func)
while (ud_disassemble(&ud_obj)) { while (ud_disassemble(&ud_obj)) {
if (emit_addrs) {
#ifdef PIPE_ARCH_X86 #ifdef PIPE_ARCH_X86
debug_printf("0x%08lx:\t", (unsigned long)ud_insn_off(&ud_obj)); debug_printf("0x%08lx:\t", (unsigned long)ud_insn_off(&ud_obj));
#endif #endif
#ifdef PIPE_ARCH_X86_64 #ifdef PIPE_ARCH_X86_64
debug_printf("0x%016llx:\t", (unsigned long long)ud_insn_off(&ud_obj)); debug_printf("0x%016llx:\t", (unsigned long long)ud_insn_off(&ud_obj));
#endif #endif
}
else if (emit_line_nos) {
debug_printf("%6d:\t", inst_no);
inst_no++;
}
#if 0 #if 0
debug_printf("%-16s ", ud_insn_hex(&ud_obj)); debug_printf("%-16s ", ud_insn_hex(&ud_obj));
#endif #endif
@ -115,8 +122,10 @@ lp_disassemble(const void* func)
} }
} }
if ((ud_insn_off(&ud_obj) >= max_jmp_pc && ud_obj.mnemonic == UD_Iret) || if (ud_obj.mnemonic == UD_Iinvalid ||
ud_obj.mnemonic == UD_Iinvalid) (ud_insn_off(&ud_obj) >= max_jmp_pc &&
(ud_obj.mnemonic == UD_Iret ||
ud_obj.mnemonic == UD_Ijmp)))
break; break;
} }

View file

@ -36,11 +36,12 @@
#include "util/u_string.h" #include "util/u_string.h"
#define GALLIVM_DEBUG_TGSI 0x1 #define GALLIVM_DEBUG_TGSI (1 << 0)
#define GALLIVM_DEBUG_IR 0x2 #define GALLIVM_DEBUG_IR (1 << 1)
#define GALLIVM_DEBUG_ASM 0x4 #define GALLIVM_DEBUG_ASM (1 << 2)
#define GALLIVM_DEBUG_NO_OPT 0x8 #define GALLIVM_DEBUG_NO_OPT (1 << 3)
#define GALLIVM_DEBUG_PERF 0x10 #define GALLIVM_DEBUG_PERF (1 << 4)
#define GALLIVM_DEBUG_NO_BRILINEAR (1 << 5)
#ifdef DEBUG #ifdef DEBUG

View file

@ -38,273 +38,15 @@
#include "lp_bld_flow.h" #include "lp_bld_flow.h"
#define LP_BUILD_FLOW_MAX_VARIABLES 64
#define LP_BUILD_FLOW_MAX_DEPTH 32
/** /**
* Enumeration of all possible flow constructs. * Insert a new block, right where builder is pointing to.
*/
enum lp_build_flow_construct_kind {
LP_BUILD_FLOW_SCOPE,
LP_BUILD_FLOW_SKIP,
LP_BUILD_FLOW_IF
};
/**
* Variable declaration scope.
*/
struct lp_build_flow_scope
{
/** Number of variables declared in this scope */
unsigned num_variables;
};
/**
* Early exit. Useful to skip to the end of a function or block when
* the execution mask becomes zero or when there is an error condition.
*/
struct lp_build_flow_skip
{
/** Block to skip to */
LLVMBasicBlockRef block;
/** Number of variables declared at the beginning */
unsigned num_variables;
LLVMValueRef *phi; /**< array [num_variables] */
};
/**
* if/else/endif.
*/
struct lp_build_flow_if
{
unsigned num_variables;
LLVMValueRef *phi; /**< array [num_variables] */
LLVMValueRef condition;
LLVMBasicBlockRef entry_block, true_block, false_block, merge_block;
};
/**
* Union of all possible flow constructs' data
*/
union lp_build_flow_construct_data
{
struct lp_build_flow_scope scope;
struct lp_build_flow_skip skip;
struct lp_build_flow_if ifthen;
};
/**
* Element of the flow construct stack.
*/
struct lp_build_flow_construct
{
enum lp_build_flow_construct_kind kind;
union lp_build_flow_construct_data data;
};
/**
* All necessary data to generate LLVM control flow constructs.
* *
* Besides keeping track of the control flow construct themselves we also * This is useful important not only for aesthetic reasons, but also for
* need to keep track of variables in order to generate SSA Phi values. * performance reasons, as frequently run blocks should be laid out next to
*/ * each other and fall-throughs maximized.
struct lp_build_flow_context
{
LLVMBuilderRef builder;
/**
* Control flow stack.
*/
struct lp_build_flow_construct constructs[LP_BUILD_FLOW_MAX_DEPTH];
unsigned num_constructs;
/**
* Variable stack
*/
LLVMValueRef *variables[LP_BUILD_FLOW_MAX_VARIABLES];
unsigned num_variables;
};
struct lp_build_flow_context *
lp_build_flow_create(LLVMBuilderRef builder)
{
struct lp_build_flow_context *flow;
flow = CALLOC_STRUCT(lp_build_flow_context);
if(!flow)
return NULL;
flow->builder = builder;
return flow;
}
void
lp_build_flow_destroy(struct lp_build_flow_context *flow)
{
assert(flow->num_constructs == 0);
assert(flow->num_variables == 0);
FREE(flow);
}
/**
* Begin/push a new flow control construct, such as a loop, skip block
* or variable scope.
*/
static union lp_build_flow_construct_data *
lp_build_flow_push(struct lp_build_flow_context *flow,
enum lp_build_flow_construct_kind kind)
{
assert(flow->num_constructs < LP_BUILD_FLOW_MAX_DEPTH);
if(flow->num_constructs >= LP_BUILD_FLOW_MAX_DEPTH)
return NULL;
flow->constructs[flow->num_constructs].kind = kind;
return &flow->constructs[flow->num_constructs++].data;
}
/**
* Return the current/top flow control construct on the stack.
* \param kind the expected type of the top-most construct
*/
static union lp_build_flow_construct_data *
lp_build_flow_peek(struct lp_build_flow_context *flow,
enum lp_build_flow_construct_kind kind)
{
assert(flow->num_constructs);
if(!flow->num_constructs)
return NULL;
assert(flow->constructs[flow->num_constructs - 1].kind == kind);
if(flow->constructs[flow->num_constructs - 1].kind != kind)
return NULL;
return &flow->constructs[flow->num_constructs - 1].data;
}
/**
* End/pop the current/top flow control construct on the stack.
* \param kind the expected type of the top-most construct
*/
static union lp_build_flow_construct_data *
lp_build_flow_pop(struct lp_build_flow_context *flow,
enum lp_build_flow_construct_kind kind)
{
assert(flow->num_constructs);
if(!flow->num_constructs)
return NULL;
assert(flow->constructs[flow->num_constructs - 1].kind == kind);
if(flow->constructs[flow->num_constructs - 1].kind != kind)
return NULL;
return &flow->constructs[--flow->num_constructs].data;
}
/**
* Begin a variable scope.
* *
* See also llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp.
* *
*/
void
lp_build_flow_scope_begin(struct lp_build_flow_context *flow)
{
struct lp_build_flow_scope *scope;
scope = &lp_build_flow_push(flow, LP_BUILD_FLOW_SCOPE)->scope;
if(!scope)
return;
scope->num_variables = 0;
}
/**
* Declare a variable.
*
* A variable is a named entity which can have different LLVMValueRef's at
* different points of the program. This is relevant for control flow because
* when there are multiple branches to a same location we need to replace
* the variable's value with a Phi function as explained in
* http://en.wikipedia.org/wiki/Static_single_assignment_form .
*
* We keep track of variables by keeping around a pointer to where they're
* current.
*
* There are a few cautions to observe:
*
* - Variable's value must not be NULL. If there is no initial value then
* LLVMGetUndef() should be used.
*
* - Variable's value must be kept up-to-date. If the variable is going to be
* modified by a function then a pointer should be passed so that its value
* is accurate. Failure to do this will cause some of the variables'
* transient values to be lost, leading to wrong results.
*
* - A program should be written from top to bottom, by always appending
* instructions to the bottom with a single LLVMBuilderRef. Inserting and/or
* modifying existing statements will most likely lead to wrong results.
*
*/
void
lp_build_flow_scope_declare(struct lp_build_flow_context *flow,
LLVMValueRef *variable)
{
struct lp_build_flow_scope *scope;
scope = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SCOPE)->scope;
if(!scope)
return;
assert(*variable);
if(!*variable)
return;
assert(flow->num_variables < LP_BUILD_FLOW_MAX_VARIABLES);
if(flow->num_variables >= LP_BUILD_FLOW_MAX_VARIABLES)
return;
flow->variables[flow->num_variables++] = variable;
++scope->num_variables;
}
void
lp_build_flow_scope_end(struct lp_build_flow_context *flow)
{
struct lp_build_flow_scope *scope;
scope = &lp_build_flow_pop(flow, LP_BUILD_FLOW_SCOPE)->scope;
if(!scope)
return;
assert(flow->num_variables >= scope->num_variables);
if(flow->num_variables < scope->num_variables) {
flow->num_variables = 0;
return;
}
flow->num_variables -= scope->num_variables;
}
/**
* Note: this function has no dependencies on the flow code and could * Note: this function has no dependencies on the flow code and could
* be used elsewhere. * be used elsewhere.
*/ */
@ -334,52 +76,18 @@ lp_build_insert_new_block(LLVMBuilderRef builder, const char *name)
} }
static LLVMBasicBlockRef
lp_build_flow_insert_block(struct lp_build_flow_context *flow)
{
return lp_build_insert_new_block(flow->builder, "");
}
/** /**
* Begin a "skip" block. Inside this block we can test a condition and * Begin a "skip" block. Inside this block we can test a condition and
* skip to the end of the block if the condition is false. * skip to the end of the block if the condition is false.
*/ */
void void
lp_build_flow_skip_begin(struct lp_build_flow_context *flow) lp_build_flow_skip_begin(struct lp_build_skip_context *skip,
LLVMBuilderRef builder)
{ {
struct lp_build_flow_skip *skip; skip->builder = builder;
LLVMBuilderRef builder;
unsigned i;
skip = &lp_build_flow_push(flow, LP_BUILD_FLOW_SKIP)->skip;
if(!skip)
return;
/* create new basic block */ /* create new basic block */
skip->block = lp_build_flow_insert_block(flow); skip->block = lp_build_insert_new_block(skip->builder, "skip");
skip->num_variables = flow->num_variables;
if(!skip->num_variables) {
skip->phi = NULL;
return;
}
/* Allocate a Phi node for each variable in this skip scope */
skip->phi = MALLOC(skip->num_variables * sizeof *skip->phi);
if(!skip->phi) {
skip->num_variables = 0;
return;
}
builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, skip->block);
/* create a Phi node for each variable */
for(i = 0; i < skip->num_variables; ++i)
skip->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
LLVMDisposeBuilder(builder);
} }
@ -388,83 +96,50 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
* skip block if the condition is true. * skip block if the condition is true.
*/ */
void void
lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow, lp_build_flow_skip_cond_break(struct lp_build_skip_context *skip,
LLVMValueRef cond) LLVMValueRef cond)
{ {
struct lp_build_flow_skip *skip;
LLVMBasicBlockRef current_block;
LLVMBasicBlockRef new_block; LLVMBasicBlockRef new_block;
unsigned i;
skip = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SKIP)->skip; new_block = lp_build_insert_new_block(skip->builder, "");
if(!skip)
return;
current_block = LLVMGetInsertBlock(flow->builder);
new_block = lp_build_flow_insert_block(flow);
/* for each variable, update the Phi node with a (variable, block) pair */
for(i = 0; i < skip->num_variables; ++i) {
assert(*flow->variables[i]);
assert(LLVMTypeOf(skip->phi[i]) == LLVMTypeOf(*flow->variables[i]));
LLVMAddIncoming(skip->phi[i], flow->variables[i], &current_block, 1);
}
/* if cond is true, goto skip->block, else goto new_block */ /* if cond is true, goto skip->block, else goto new_block */
LLVMBuildCondBr(flow->builder, cond, skip->block, new_block); LLVMBuildCondBr(skip->builder, cond, skip->block, new_block);
LLVMPositionBuilderAtEnd(flow->builder, new_block); LLVMPositionBuilderAtEnd(skip->builder, new_block);
} }
void void
lp_build_flow_skip_end(struct lp_build_flow_context *flow) lp_build_flow_skip_end(struct lp_build_skip_context *skip)
{ {
struct lp_build_flow_skip *skip;
LLVMBasicBlockRef current_block;
unsigned i;
skip = &lp_build_flow_pop(flow, LP_BUILD_FLOW_SKIP)->skip;
if(!skip)
return;
current_block = LLVMGetInsertBlock(flow->builder);
/* add (variable, block) tuples to the phi nodes */
for(i = 0; i < skip->num_variables; ++i) {
assert(*flow->variables[i]);
assert(LLVMTypeOf(skip->phi[i]) == LLVMTypeOf(*flow->variables[i]));
LLVMAddIncoming(skip->phi[i], flow->variables[i], &current_block, 1);
*flow->variables[i] = skip->phi[i];
}
/* goto block */ /* goto block */
LLVMBuildBr(flow->builder, skip->block); LLVMBuildBr(skip->builder, skip->block);
LLVMPositionBuilderAtEnd(flow->builder, skip->block); LLVMPositionBuilderAtEnd(skip->builder, skip->block);
FREE(skip->phi);
} }
/** /**
* Check if the mask predicate is zero. If so, jump to the end of the block. * Check if the mask predicate is zero. If so, jump to the end of the block.
*/ */
static void void
lp_build_mask_check(struct lp_build_mask_context *mask) lp_build_mask_check(struct lp_build_mask_context *mask)
{ {
LLVMBuilderRef builder = mask->flow->builder; LLVMBuilderRef builder = mask->skip.builder;
LLVMValueRef value;
LLVMValueRef cond; LLVMValueRef cond;
value = lp_build_mask_value(mask);
/* cond = (mask == 0) */ /* cond = (mask == 0) */
cond = LLVMBuildICmp(builder, cond = LLVMBuildICmp(builder,
LLVMIntEQ, LLVMIntEQ,
LLVMBuildBitCast(builder, mask->value, mask->reg_type, ""), LLVMBuildBitCast(builder, value, mask->reg_type, ""),
LLVMConstNull(mask->reg_type), LLVMConstNull(mask->reg_type),
""); "");
/* if cond, goto end of block */ /* if cond, goto end of block */
lp_build_flow_skip_cond_break(mask->flow, cond); lp_build_flow_skip_cond_break(&mask->skip, cond);
} }
@ -477,21 +152,27 @@ lp_build_mask_check(struct lp_build_mask_context *mask)
*/ */
void void
lp_build_mask_begin(struct lp_build_mask_context *mask, lp_build_mask_begin(struct lp_build_mask_context *mask,
struct lp_build_flow_context *flow, LLVMBuilderRef builder,
struct lp_type type, struct lp_type type,
LLVMValueRef value) LLVMValueRef value)
{ {
memset(mask, 0, sizeof *mask); memset(mask, 0, sizeof *mask);
mask->flow = flow;
mask->reg_type = LLVMIntType(type.width * type.length); mask->reg_type = LLVMIntType(type.width * type.length);
mask->value = value; mask->var = lp_build_alloca(builder,
lp_build_int_vec_type(type),
"execution_mask");
lp_build_flow_scope_begin(flow); LLVMBuildStore(builder, value, mask->var);
lp_build_flow_scope_declare(flow, &mask->value);
lp_build_flow_skip_begin(flow);
lp_build_mask_check(mask); lp_build_flow_skip_begin(&mask->skip, builder);
}
LLVMValueRef
lp_build_mask_value(struct lp_build_mask_context *mask)
{
return LLVMBuildLoad(mask->skip.builder, mask->var, "");
} }
@ -504,9 +185,10 @@ void
lp_build_mask_update(struct lp_build_mask_context *mask, lp_build_mask_update(struct lp_build_mask_context *mask,
LLVMValueRef value) LLVMValueRef value)
{ {
mask->value = LLVMBuildAnd( mask->flow->builder, mask->value, value, ""); value = LLVMBuildAnd(mask->skip.builder,
lp_build_mask_value(mask),
lp_build_mask_check(mask); value, "");
LLVMBuildStore(mask->skip.builder, value, mask->var);
} }
@ -516,9 +198,8 @@ lp_build_mask_update(struct lp_build_mask_context *mask,
LLVMValueRef LLVMValueRef
lp_build_mask_end(struct lp_build_mask_context *mask) lp_build_mask_end(struct lp_build_mask_context *mask)
{ {
lp_build_flow_skip_end(mask->flow); lp_build_flow_skip_end(&mask->skip);
lp_build_flow_scope_end(mask->flow); return lp_build_mask_value(mask);
return mask->value;
} }
@ -528,19 +209,47 @@ lp_build_loop_begin(LLVMBuilderRef builder,
LLVMValueRef start, LLVMValueRef start,
struct lp_build_loop_state *state) struct lp_build_loop_state *state)
{ {
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder); state->block = lp_build_insert_new_block(builder, "loop_begin");
LLVMValueRef function = LLVMGetBasicBlockParent(block);
state->block = LLVMAppendBasicBlock(function, "loop"); state->counter_var = lp_build_alloca(builder, LLVMTypeOf(start), "loop_counter");
LLVMBuildStore(builder, start, state->counter_var);
LLVMBuildBr(builder, state->block); LLVMBuildBr(builder, state->block);
LLVMPositionBuilderAtEnd(builder, state->block); LLVMPositionBuilderAtEnd(builder, state->block);
state->counter = LLVMBuildPhi(builder, LLVMTypeOf(start), ""); state->counter = LLVMBuildLoad(builder, state->counter_var, "");
}
LLVMAddIncoming(state->counter, &start, &block, 1);
void
lp_build_loop_end_cond(LLVMBuilderRef builder,
LLVMValueRef end,
LLVMValueRef step,
LLVMIntPredicate llvm_cond,
struct lp_build_loop_state *state)
{
LLVMValueRef next;
LLVMValueRef cond;
LLVMBasicBlockRef after_block;
if (!step)
step = LLVMConstInt(LLVMTypeOf(end), 1, 0);
next = LLVMBuildAdd(builder, state->counter, step, "");
LLVMBuildStore(builder, next, state->counter_var);
cond = LLVMBuildICmp(builder, llvm_cond, next, end, "");
after_block = lp_build_insert_new_block(builder, "loop_end");
LLVMBuildCondBr(builder, cond, after_block, state->block);
LLVMPositionBuilderAtEnd(builder, after_block);
state->counter = LLVMBuildLoad(builder, state->counter_var, "");
} }
@ -550,55 +259,7 @@ lp_build_loop_end(LLVMBuilderRef builder,
LLVMValueRef step, LLVMValueRef step,
struct lp_build_loop_state *state) struct lp_build_loop_state *state)
{ {
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder); lp_build_loop_end_cond(builder, end, step, LLVMIntNE, state);
LLVMValueRef function = LLVMGetBasicBlockParent(block);
LLVMValueRef next;
LLVMValueRef cond;
LLVMBasicBlockRef after_block;
if (!step)
step = LLVMConstInt(LLVMTypeOf(end), 1, 0);
next = LLVMBuildAdd(builder, state->counter, step, "");
cond = LLVMBuildICmp(builder, LLVMIntNE, next, end, "");
after_block = LLVMAppendBasicBlock(function, "");
LLVMBuildCondBr(builder, cond, after_block, state->block);
LLVMAddIncoming(state->counter, &next, &block, 1);
LLVMPositionBuilderAtEnd(builder, after_block);
}
void
lp_build_loop_end_cond(LLVMBuilderRef builder,
LLVMValueRef end,
LLVMValueRef step,
int llvm_cond,
struct lp_build_loop_state *state)
{
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
LLVMValueRef function = LLVMGetBasicBlockParent(block);
LLVMValueRef next;
LLVMValueRef cond;
LLVMBasicBlockRef after_block;
if (!step)
step = LLVMConstInt(LLVMTypeOf(end), 1, 0);
next = LLVMBuildAdd(builder, state->counter, step, "");
cond = LLVMBuildICmp(builder, llvm_cond, next, end, "");
after_block = LLVMAppendBasicBlock(function, "");
LLVMBuildCondBr(builder, cond, after_block, state->block);
LLVMAddIncoming(state->counter, &next, &block, 1);
LLVMPositionBuilderAtEnd(builder, after_block);
} }
@ -616,24 +277,16 @@ lp_build_loop_end_cond(LLVMBuilderRef builder,
Is built with: Is built with:
LLVMValueRef x = LLVMGetUndef(); // or something else // x needs an alloca variable
x = lp_build_alloca(builder, type, "x");
flow = lp_build_flow_create(builder);
lp_build_flow_scope_begin(flow); lp_build_if(ctx, builder, cond);
LLVMBuildStore(LLVMBuildAdd(1, 2), x);
// x needs a phi node
lp_build_flow_scope_declare(flow, &x);
lp_build_if(ctx, flow, builder, cond);
x = LLVMAdd(1, 2);
lp_build_else(ctx); lp_build_else(ctx);
x = LLVMAdd(2, 3); LLVMBuildStore(LLVMBuildAdd(2, 3). x);
lp_build_endif(ctx); lp_build_endif(ctx);
lp_build_flow_scope_end(flow);
lp_build_flow_destroy(flow);
*/ */
@ -642,47 +295,19 @@ lp_build_loop_end_cond(LLVMBuilderRef builder,
* Begin an if/else/endif construct. * Begin an if/else/endif construct.
*/ */
void void
lp_build_if(struct lp_build_if_state *ctx, lp_build_if(struct lp_build_if_state *ifthen,
struct lp_build_flow_context *flow,
LLVMBuilderRef builder, LLVMBuilderRef builder,
LLVMValueRef condition) LLVMValueRef condition)
{ {
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder); LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
struct lp_build_flow_if *ifthen;
unsigned i;
memset(ctx, 0, sizeof(*ctx)); memset(ifthen, 0, sizeof *ifthen);
ctx->builder = builder; ifthen->builder = builder;
ctx->flow = flow;
/* push/create new scope */
ifthen = &lp_build_flow_push(flow, LP_BUILD_FLOW_IF)->ifthen;
assert(ifthen);
ifthen->num_variables = flow->num_variables;
ifthen->condition = condition; ifthen->condition = condition;
ifthen->entry_block = block; ifthen->entry_block = block;
/* create a Phi node for each variable in this flow scope */
ifthen->phi = MALLOC(ifthen->num_variables * sizeof(*ifthen->phi));
if (!ifthen->phi) {
ifthen->num_variables = 0;
return;
}
/* create endif/merge basic block for the phi functions */ /* create endif/merge basic block for the phi functions */
ifthen->merge_block = lp_build_insert_new_block(builder, "endif-block"); ifthen->merge_block = lp_build_insert_new_block(builder, "endif-block");
LLVMPositionBuilderAtEnd(builder, ifthen->merge_block);
/* create a phi node for each variable */
for (i = 0; i < flow->num_variables; i++) {
ifthen->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
/* add add the initial value of the var from the entry block */
if (!LLVMIsUndef(*flow->variables[i]))
LLVMAddIncoming(ifthen->phi[i], flow->variables[i],
&ifthen->entry_block, 1);
}
/* create/insert true_block before merge_block */ /* create/insert true_block before merge_block */
ifthen->true_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-true-block"); ifthen->true_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-true-block");
@ -696,27 +321,16 @@ lp_build_if(struct lp_build_if_state *ctx,
* Begin else-part of a conditional * Begin else-part of a conditional
*/ */
void void
lp_build_else(struct lp_build_if_state *ctx) lp_build_else(struct lp_build_if_state *ifthen)
{ {
struct lp_build_flow_context *flow = ctx->flow; /* Append an unconditional Br(anch) instruction on the true_block */
struct lp_build_flow_if *ifthen; LLVMBuildBr(ifthen->builder, ifthen->merge_block);
unsigned i;
ifthen = &lp_build_flow_peek(flow, LP_BUILD_FLOW_IF)->ifthen;
assert(ifthen);
/* for each variable, update the Phi node with a (variable, block) pair */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
for (i = 0; i < flow->num_variables; i++) {
assert(*flow->variables[i]);
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
}
/* create/insert false_block before the merge block */ /* create/insert false_block before the merge block */
ifthen->false_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-false-block"); ifthen->false_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-false-block");
/* successive code goes into the else block */ /* successive code goes into the else block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block); LLVMPositionBuilderAtEnd(ifthen->builder, ifthen->false_block);
} }
@ -724,75 +338,30 @@ lp_build_else(struct lp_build_if_state *ctx)
* End a conditional. * End a conditional.
*/ */
void void
lp_build_endif(struct lp_build_if_state *ctx) lp_build_endif(struct lp_build_if_state *ifthen)
{ {
struct lp_build_flow_context *flow = ctx->flow;
struct lp_build_flow_if *ifthen;
LLVMBasicBlockRef curBlock = LLVMGetInsertBlock(ctx->builder);
unsigned i;
ifthen = &lp_build_flow_pop(flow, LP_BUILD_FLOW_IF)->ifthen;
assert(ifthen);
/* Insert branch to the merge block from current block */ /* Insert branch to the merge block from current block */
LLVMBuildBr(ctx->builder, ifthen->merge_block); LLVMBuildBr(ifthen->builder, ifthen->merge_block);
if (ifthen->false_block) { /*
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block); * Now patch in the various branch instructions.
/* for each variable, update the Phi node with a (variable, block) pair */ */
for (i = 0; i < flow->num_variables; i++) {
assert(*flow->variables[i]);
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &curBlock, 1);
/* replace the variable ref with the phi function */
*flow->variables[i] = ifthen->phi[i];
}
}
else {
/* no else clause */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
for (i = 0; i < flow->num_variables; i++) {
assert(*flow->variables[i]);
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
/* replace the variable ref with the phi function */
*flow->variables[i] = ifthen->phi[i];
}
}
FREE(ifthen->phi);
/***
*** Now patch in the various branch instructions.
***/
/* Insert the conditional branch instruction at the end of entry_block */ /* Insert the conditional branch instruction at the end of entry_block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->entry_block); LLVMPositionBuilderAtEnd(ifthen->builder, ifthen->entry_block);
if (ifthen->false_block) { if (ifthen->false_block) {
/* we have an else clause */ /* we have an else clause */
LLVMBuildCondBr(ctx->builder, ifthen->condition, LLVMBuildCondBr(ifthen->builder, ifthen->condition,
ifthen->true_block, ifthen->false_block); ifthen->true_block, ifthen->false_block);
} }
else { else {
/* no else clause */ /* no else clause */
LLVMBuildCondBr(ctx->builder, ifthen->condition, LLVMBuildCondBr(ifthen->builder, ifthen->condition,
ifthen->true_block, ifthen->merge_block); ifthen->true_block, ifthen->merge_block);
} }
/* Insert branch from end of true_block to merge_block */
if (ifthen->false_block) {
/* Append an unconditional Br(anch) instruction on the true_block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->true_block);
LLVMBuildBr(ctx->builder, ifthen->merge_block);
}
else {
/* No else clause.
* Note that we've already inserted the branch at the end of
* true_block. See the very first LLVMBuildBr() call in this function.
*/
}
/* Resume building code at end of the ifthen->merge_block */ /* Resume building code at end of the ifthen->merge_block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block); LLVMPositionBuilderAtEnd(ifthen->builder, ifthen->merge_block);
} }
@ -830,6 +399,7 @@ lp_build_alloca(LLVMBuilderRef builder,
} }
res = LLVMBuildAlloca(first_builder, type, name); res = LLVMBuildAlloca(first_builder, type, name);
LLVMBuildStore(builder, LLVMConstNull(type), res);
LLVMDisposeBuilder(first_builder); LLVMDisposeBuilder(first_builder);

View file

@ -41,52 +41,49 @@
struct lp_type; struct lp_type;
struct lp_build_flow_context; /**
* Early exit. Useful to skip to the end of a function or block when
* the execution mask becomes zero or when there is an error condition.
*/
struct lp_build_skip_context
{
LLVMBuilderRef builder;
/** Block to skip to */
struct lp_build_flow_context * LLVMBasicBlockRef block;
lp_build_flow_create(LLVMBuilderRef builder); };
void void
lp_build_flow_destroy(struct lp_build_flow_context *flow); lp_build_flow_skip_begin(struct lp_build_skip_context *ctx,
LLVMBuilderRef builder);
void void
lp_build_flow_scope_begin(struct lp_build_flow_context *flow); lp_build_flow_skip_cond_break(struct lp_build_skip_context *ctx,
void
lp_build_flow_scope_declare(struct lp_build_flow_context *flow,
LLVMValueRef *variable);
void
lp_build_flow_scope_end(struct lp_build_flow_context *flow);
void
lp_build_flow_skip_begin(struct lp_build_flow_context *flow);
void
lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
LLVMValueRef cond); LLVMValueRef cond);
void void
lp_build_flow_skip_end(struct lp_build_flow_context *flow); lp_build_flow_skip_end(struct lp_build_skip_context *ctx);
struct lp_build_mask_context struct lp_build_mask_context
{ {
struct lp_build_flow_context *flow; struct lp_build_skip_context skip;
LLVMTypeRef reg_type; LLVMTypeRef reg_type;
LLVMValueRef value; LLVMValueRef var;
}; };
void void
lp_build_mask_begin(struct lp_build_mask_context *mask, lp_build_mask_begin(struct lp_build_mask_context *mask,
struct lp_build_flow_context *flow, LLVMBuilderRef builder,
struct lp_type type, struct lp_type type,
LLVMValueRef value); LLVMValueRef value);
LLVMValueRef
lp_build_mask_value(struct lp_build_mask_context *mask);
/** /**
* Bitwise AND the mask with the given value, if a previous mask was set. * Bitwise AND the mask with the given value, if a previous mask was set.
*/ */
@ -94,6 +91,9 @@ void
lp_build_mask_update(struct lp_build_mask_context *mask, lp_build_mask_update(struct lp_build_mask_context *mask,
LLVMValueRef value); LLVMValueRef value);
void
lp_build_mask_check(struct lp_build_mask_context *mask);
LLVMValueRef LLVMValueRef
lp_build_mask_end(struct lp_build_mask_context *mask); lp_build_mask_end(struct lp_build_mask_context *mask);
@ -108,6 +108,7 @@ lp_build_mask_end(struct lp_build_mask_context *mask);
struct lp_build_loop_state struct lp_build_loop_state
{ {
LLVMBasicBlockRef block; LLVMBasicBlockRef block;
LLVMValueRef counter_var;
LLVMValueRef counter; LLVMValueRef counter;
}; };
@ -128,22 +129,28 @@ void
lp_build_loop_end_cond(LLVMBuilderRef builder, lp_build_loop_end_cond(LLVMBuilderRef builder,
LLVMValueRef end, LLVMValueRef end,
LLVMValueRef step, LLVMValueRef step,
int cond, /* LLVM condition */ LLVMIntPredicate cond,
struct lp_build_loop_state *state); struct lp_build_loop_state *state);
/**
* if/else/endif.
*/
struct lp_build_if_state struct lp_build_if_state
{ {
LLVMBuilderRef builder; LLVMBuilderRef builder;
struct lp_build_flow_context *flow; LLVMValueRef condition;
LLVMBasicBlockRef entry_block;
LLVMBasicBlockRef true_block;
LLVMBasicBlockRef false_block;
LLVMBasicBlockRef merge_block;
}; };
void void
lp_build_if(struct lp_build_if_state *ctx, lp_build_if(struct lp_build_if_state *ctx,
struct lp_build_flow_context *flow,
LLVMBuilderRef builder, LLVMBuilderRef builder,
LLVMValueRef condition); LLVMValueRef condition);

View file

@ -44,6 +44,7 @@ static const struct debug_named_value lp_bld_debug_flags[] = {
{ "asm", GALLIVM_DEBUG_ASM, NULL }, { "asm", GALLIVM_DEBUG_ASM, NULL },
{ "nopt", GALLIVM_DEBUG_NO_OPT, NULL }, { "nopt", GALLIVM_DEBUG_NO_OPT, NULL },
{ "perf", GALLIVM_DEBUG_PERF, NULL }, { "perf", GALLIVM_DEBUG_PERF, NULL },
{ "no_brilinear", GALLIVM_DEBUG_NO_BRILINEAR, NULL },
DEBUG_NAMED_VALUE_END DEBUG_NAMED_VALUE_END
}; };

View file

@ -47,4 +47,10 @@ lp_build_init(void);
extern void extern void
lp_func_delete_body(LLVMValueRef func); lp_func_delete_body(LLVMValueRef func);
extern LLVMValueRef
lp_build_load_volatile(LLVMBuilderRef B, LLVMValueRef PointerVal,
const char *Name);
#endif /* !LP_BLD_INIT_H */ #endif /* !LP_BLD_INIT_H */

View file

@ -462,10 +462,12 @@ lp_build_select(struct lp_build_context *bld,
LLVMTypeRef arg_type; LLVMTypeRef arg_type;
LLVMValueRef args[3]; LLVMValueRef args[3];
if (type.width == 64) { if (type.floating &&
type.width == 64) {
intrinsic = "llvm.x86.sse41.blendvpd"; intrinsic = "llvm.x86.sse41.blendvpd";
arg_type = LLVMVectorType(LLVMDoubleType(), 2); arg_type = LLVMVectorType(LLVMDoubleType(), 2);
} else if (type.width == 32) { } else if (type.floating &&
type.width == 32) {
intrinsic = "llvm.x86.sse41.blendvps"; intrinsic = "llvm.x86.sse41.blendvps";
arg_type = LLVMVectorType(LLVMFloatType(), 4); arg_type = LLVMVectorType(LLVMFloatType(), 4);
} else { } else {

View file

@ -178,3 +178,13 @@ lp_func_delete_body(LLVMValueRef FF)
llvm::Function *func = llvm::unwrap<llvm::Function>(FF); llvm::Function *func = llvm::unwrap<llvm::Function>(FF);
func->deleteBody(); func->deleteBody();
} }
extern "C"
LLVMValueRef
lp_build_load_volatile(LLVMBuilderRef B, LLVMValueRef PointerVal,
const char *Name)
{
return llvm::wrap(llvm::unwrap(B)->CreateLoad(llvm::unwrap(PointerVal), true, Name));
}

View file

@ -29,6 +29,8 @@
#include "util/u_debug.h" #include "util/u_debug.h"
#include "util/u_memory.h" #include "util/u_memory.h"
#include "util/u_string.h"
#include "lp_bld_const.h"
#include "lp_bld_printf.h" #include "lp_bld_printf.h"
@ -119,3 +121,22 @@ lp_build_printf(LLVMBuilderRef builder, const char *fmt, ...)
return LLVMBuildCall(builder, func_printf, params, argcount + 1, ""); return LLVMBuildCall(builder, func_printf, params, argcount + 1, "");
} }
/**
* Print a float[4] vector.
*/
LLVMValueRef
lp_build_print_vec4(LLVMBuilderRef builder, const char *msg, LLVMValueRef vec)
{
char format[1000];
LLVMValueRef x, y, z, w;
x = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(0), "");
y = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(1), "");
z = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(2), "");
w = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(3), "");
util_snprintf(format, sizeof(format), "%s %%f %%f %%f %%f\n", msg);
return lp_build_printf(builder, format, x, y, z, w);
}

View file

@ -35,5 +35,9 @@
LLVMValueRef lp_build_const_string_variable(LLVMModuleRef module, const char *str, int len); LLVMValueRef lp_build_const_string_variable(LLVMModuleRef module, const char *str, int len);
LLVMValueRef lp_build_printf(LLVMBuilderRef builder, const char *fmt, ...); LLVMValueRef lp_build_printf(LLVMBuilderRef builder, const char *fmt, ...);
LLVMValueRef
lp_build_print_vec4(LLVMBuilderRef builder, const char *msg, LLVMValueRef vec);
#endif #endif

View file

@ -81,11 +81,15 @@ LLVMValueRef
lp_build_scalar_ddx(struct lp_build_context *bld, lp_build_scalar_ddx(struct lp_build_context *bld,
LLVMValueRef a) LLVMValueRef a)
{ {
LLVMValueRef idx_left = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_TOP_LEFT, 0); LLVMTypeRef i32t = LLVMInt32Type();
LLVMValueRef idx_right = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_TOP_RIGHT, 0); LLVMValueRef idx_left = LLVMConstInt(i32t, LP_BLD_QUAD_TOP_LEFT, 0);
LLVMValueRef a_left = LLVMBuildExtractElement(bld->builder, a, idx_left, ""); LLVMValueRef idx_right = LLVMConstInt(i32t, LP_BLD_QUAD_TOP_RIGHT, 0);
LLVMValueRef a_right = LLVMBuildExtractElement(bld->builder, a, idx_right, ""); LLVMValueRef a_left = LLVMBuildExtractElement(bld->builder, a, idx_left, "left");
return lp_build_sub(bld, a_right, a_left); LLVMValueRef a_right = LLVMBuildExtractElement(bld->builder, a, idx_right, "right");
if (bld->type.floating)
return LLVMBuildFSub(bld->builder, a_right, a_left, "ddx");
else
return LLVMBuildSub(bld->builder, a_right, a_left, "ddx");
} }
@ -93,9 +97,13 @@ LLVMValueRef
lp_build_scalar_ddy(struct lp_build_context *bld, lp_build_scalar_ddy(struct lp_build_context *bld,
LLVMValueRef a) LLVMValueRef a)
{ {
LLVMValueRef idx_top = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_TOP_LEFT, 0); LLVMTypeRef i32t = LLVMInt32Type();
LLVMValueRef idx_bottom = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_BOTTOM_LEFT, 0); LLVMValueRef idx_top = LLVMConstInt(i32t, LP_BLD_QUAD_TOP_LEFT, 0);
LLVMValueRef a_top = LLVMBuildExtractElement(bld->builder, a, idx_top, ""); LLVMValueRef idx_bottom = LLVMConstInt(i32t, LP_BLD_QUAD_BOTTOM_LEFT, 0);
LLVMValueRef a_bottom = LLVMBuildExtractElement(bld->builder, a, idx_bottom, ""); LLVMValueRef a_top = LLVMBuildExtractElement(bld->builder, a, idx_top, "top");
return lp_build_sub(bld, a_bottom, a_top); LLVMValueRef a_bottom = LLVMBuildExtractElement(bld->builder, a, idx_bottom, "bottom");
if (bld->type.floating)
return LLVMBuildFSub(bld->builder, a_bottom, a_top, "ddy");
else
return LLVMBuildSub(bld->builder, a_bottom, a_top, "ddy");
} }

View file

@ -47,8 +47,7 @@
/* /*
* Bri-linear factor. Use zero or any other number less than one to force * Bri-linear factor. Should be greater than one.
* tri-linear filtering.
*/ */
#define BRILINEAR_FACTOR 2 #define BRILINEAR_FACTOR 2
@ -201,8 +200,8 @@ lp_build_rho(struct lp_build_sample_context *bld,
LLVMValueRef float_size; LLVMValueRef float_size;
LLVMValueRef rho; LLVMValueRef rho;
dsdx = LLVMBuildExtractElement(bld->builder, ddx[0], index0, "dsdx"); dsdx = ddx[0];
dsdy = LLVMBuildExtractElement(bld->builder, ddy[0], index0, "dsdy"); dsdy = ddy[0];
if (dims <= 1) { if (dims <= 1) {
rho_x = dsdx; rho_x = dsdx;
@ -215,15 +214,15 @@ lp_build_rho(struct lp_build_sample_context *bld,
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, dsdx, index0, ""); rho_x = LLVMBuildInsertElement(bld->builder, rho_x, dsdx, index0, "");
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, dsdy, index0, ""); rho_y = LLVMBuildInsertElement(bld->builder, rho_y, dsdy, index0, "");
dtdx = LLVMBuildExtractElement(bld->builder, ddx[1], index0, "dtdx"); dtdx = ddx[1];
dtdy = LLVMBuildExtractElement(bld->builder, ddy[1], index0, "dtdy"); dtdy = ddy[1];
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, dtdx, index1, ""); rho_x = LLVMBuildInsertElement(bld->builder, rho_x, dtdx, index1, "");
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, dtdy, index1, ""); rho_y = LLVMBuildInsertElement(bld->builder, rho_y, dtdy, index1, "");
if (dims >= 3) { if (dims >= 3) {
drdx = LLVMBuildExtractElement(bld->builder, ddx[2], index0, "drdx"); drdx = ddx[2];
drdy = LLVMBuildExtractElement(bld->builder, ddy[2], index0, "drdy"); drdy = ddy[2];
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, drdx, index2, ""); rho_x = LLVMBuildInsertElement(bld->builder, rho_x, drdx, index2, "");
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, drdy, index2, ""); rho_y = LLVMBuildInsertElement(bld->builder, rho_y, drdy, index2, "");
@ -294,31 +293,30 @@ lp_build_rho(struct lp_build_sample_context *bld,
* TODO: This could be done in fixed point, where applicable. * TODO: This could be done in fixed point, where applicable.
*/ */
static void static void
lp_build_brilinear_lod(struct lp_build_sample_context *bld, lp_build_brilinear_lod(struct lp_build_context *bld,
LLVMValueRef lod, LLVMValueRef lod,
double factor, double factor,
LLVMValueRef *out_lod_ipart, LLVMValueRef *out_lod_ipart,
LLVMValueRef *out_lod_fpart) LLVMValueRef *out_lod_fpart)
{ {
struct lp_build_context *float_bld = &bld->float_bld;
LLVMValueRef lod_fpart; LLVMValueRef lod_fpart;
float pre_offset = (factor - 0.5)/factor - 0.5; double pre_offset = (factor - 0.5)/factor - 0.5;
float post_offset = 1 - factor; double post_offset = 1 - factor;
if (0) { if (0) {
lp_build_printf(bld->builder, "lod = %f\n", lod); lp_build_printf(bld->builder, "lod = %f\n", lod);
} }
lod = lp_build_add(float_bld, lod, lod = lp_build_add(bld, lod,
lp_build_const_vec(float_bld->type, pre_offset)); lp_build_const_vec(bld->type, pre_offset));
lp_build_ifloor_fract(float_bld, lod, out_lod_ipart, &lod_fpart); lp_build_ifloor_fract(bld, lod, out_lod_ipart, &lod_fpart);
lod_fpart = lp_build_mul(float_bld, lod_fpart, lod_fpart = lp_build_mul(bld, lod_fpart,
lp_build_const_vec(float_bld->type, factor)); lp_build_const_vec(bld->type, factor));
lod_fpart = lp_build_add(float_bld, lod_fpart, lod_fpart = lp_build_add(bld, lod_fpart,
lp_build_const_vec(float_bld->type, post_offset)); lp_build_const_vec(bld->type, post_offset));
/* /*
* It's not necessary to clamp lod_fpart since: * It's not necessary to clamp lod_fpart since:
@ -335,6 +333,61 @@ lp_build_brilinear_lod(struct lp_build_sample_context *bld,
} }
/*
* Combined log2 and brilinear lod computation.
*
* It's in all identical to calling lp_build_fast_log2() and
* lp_build_brilinear_lod() above, but by combining we can compute the interger
* and fractional part independently.
*/
static void
lp_build_brilinear_rho(struct lp_build_context *bld,
LLVMValueRef rho,
double factor,
LLVMValueRef *out_lod_ipart,
LLVMValueRef *out_lod_fpart)
{
LLVMValueRef lod_ipart;
LLVMValueRef lod_fpart;
const double pre_factor = (2*factor - 0.5)/(M_SQRT2*factor);
const double post_offset = 1 - 2*factor;
assert(bld->type.floating);
assert(lp_check_value(bld->type, rho));
/*
* The pre factor will make the intersections with the exact powers of two
* happen precisely where we want then to be, which means that the integer
* part will not need any post adjustments.
*/
rho = lp_build_mul(bld, rho,
lp_build_const_vec(bld->type, pre_factor));
/* ipart = ifloor(log2(rho)) */
lod_ipart = lp_build_extract_exponent(bld, rho, 0);
/* fpart = rho / 2**ipart */
lod_fpart = lp_build_extract_mantissa(bld, rho);
lod_fpart = lp_build_mul(bld, lod_fpart,
lp_build_const_vec(bld->type, factor));
lod_fpart = lp_build_add(bld, lod_fpart,
lp_build_const_vec(bld->type, post_offset));
/*
* Like lp_build_brilinear_lod, it's not necessary to clamp lod_fpart since:
* - the above expression will never produce numbers greater than one.
* - the mip filtering branch is only taken if lod_fpart is positive
*/
*out_lod_ipart = lod_ipart;
*out_lod_fpart = lod_fpart;
}
/** /**
* Generate code to compute texture level of detail (lambda). * Generate code to compute texture level of detail (lambda).
* \param ddx partial derivatives of (s, t, r, q) with respect to X * \param ddx partial derivatives of (s, t, r, q) with respect to X
@ -389,17 +442,33 @@ lp_build_lod_selector(struct lp_build_sample_context *bld,
rho = lp_build_rho(bld, ddx, ddy); rho = lp_build_rho(bld, ddx, ddy);
/* compute lod = log2(rho) */ /*
if ((mip_filter == PIPE_TEX_MIPFILTER_NONE || * Compute lod = log2(rho)
mip_filter == PIPE_TEX_MIPFILTER_NEAREST) && */
!lod_bias &&
if (!lod_bias &&
!bld->static_state->lod_bias_non_zero && !bld->static_state->lod_bias_non_zero &&
!bld->static_state->apply_max_lod && !bld->static_state->apply_max_lod &&
!bld->static_state->apply_min_lod) { !bld->static_state->apply_min_lod) {
/*
* Special case when there are no post-log2 adjustments, which
* saves instructions but keeping the integer and fractional lod
* computations separate from the start.
*/
if (mip_filter == PIPE_TEX_MIPFILTER_NONE ||
mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
*out_lod_ipart = lp_build_ilog2(float_bld, rho); *out_lod_ipart = lp_build_ilog2(float_bld, rho);
*out_lod_fpart = bld->float_bld.zero; *out_lod_fpart = bld->float_bld.zero;
return; return;
} }
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR &&
!(gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR)) {
lp_build_brilinear_rho(float_bld, rho, BRILINEAR_FACTOR,
out_lod_ipart, out_lod_fpart);
return;
}
}
if (0) { if (0) {
lod = lp_build_log2(float_bld, rho); lod = lp_build_log2(float_bld, rho);
@ -437,21 +506,22 @@ lp_build_lod_selector(struct lp_build_sample_context *bld,
} }
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
if (BRILINEAR_FACTOR > 1.0) { if (!(gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR)) {
lp_build_brilinear_lod(bld, lod, BRILINEAR_FACTOR, lp_build_brilinear_lod(float_bld, lod, BRILINEAR_FACTOR,
out_lod_ipart, out_lod_fpart); out_lod_ipart, out_lod_fpart);
} }
else { else {
lp_build_ifloor_fract(float_bld, lod, out_lod_ipart, out_lod_fpart); lp_build_ifloor_fract(float_bld, lod, out_lod_ipart, out_lod_fpart);
} }
lp_build_name(*out_lod_ipart, "lod_ipart");
lp_build_name(*out_lod_fpart, "lod_fpart"); lp_build_name(*out_lod_fpart, "lod_fpart");
} }
else { else {
*out_lod_ipart = lp_build_iround(float_bld, lod); *out_lod_ipart = lp_build_iround(float_bld, lod);
} }
lp_build_name(*out_lod_ipart, "lod_ipart");
return; return;
} }
@ -630,37 +700,21 @@ lp_build_get_level_stride_vec(struct lp_build_sample_context *bld,
void void
lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld, lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
LLVMValueRef ilevel, LLVMValueRef ilevel,
LLVMValueRef *out_width_vec, LLVMValueRef *out_size,
LLVMValueRef *out_height_vec,
LLVMValueRef *out_depth_vec,
LLVMValueRef *row_stride_vec, LLVMValueRef *row_stride_vec,
LLVMValueRef *img_stride_vec) LLVMValueRef *img_stride_vec)
{ {
const unsigned dims = bld->dims; const unsigned dims = bld->dims;
LLVMValueRef ilevel_vec; LLVMValueRef ilevel_vec;
LLVMValueRef size_vec;
LLVMTypeRef i32t = LLVMInt32Type();
ilevel_vec = lp_build_broadcast_scalar(&bld->int_size_bld, ilevel); ilevel_vec = lp_build_broadcast_scalar(&bld->int_size_bld, ilevel);
/* /*
* Compute width, height, depth at mipmap level 'ilevel' * Compute width, height, depth at mipmap level 'ilevel'
*/ */
size_vec = lp_build_minify(&bld->int_size_bld, bld->int_size, ilevel_vec); *out_size = lp_build_minify(&bld->int_size_bld, bld->int_size, ilevel_vec);
*out_width_vec = lp_build_extract_broadcast(bld->builder,
bld->int_size_type,
bld->int_coord_type,
size_vec,
LLVMConstInt(i32t, 0, 0));
if (dims >= 2) { if (dims >= 2) {
*out_height_vec = lp_build_extract_broadcast(bld->builder,
bld->int_size_type,
bld->int_coord_type,
size_vec,
LLVMConstInt(i32t, 1, 0));
*row_stride_vec = lp_build_get_level_stride_vec(bld, *row_stride_vec = lp_build_get_level_stride_vec(bld,
bld->row_stride_array, bld->row_stride_array,
ilevel); ilevel);
@ -668,18 +722,90 @@ lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
*img_stride_vec = lp_build_get_level_stride_vec(bld, *img_stride_vec = lp_build_get_level_stride_vec(bld,
bld->img_stride_array, bld->img_stride_array,
ilevel); ilevel);
if (dims == 3) {
*out_depth_vec = lp_build_extract_broadcast(bld->builder,
bld->int_size_type,
bld->int_coord_type,
size_vec,
LLVMConstInt(i32t, 2, 0));
}
} }
} }
} }
/**
* Extract and broadcast texture size.
*
* @param size_type type of the texture size vector (either
* bld->int_size_type or bld->float_size_type)
* @param coord_type type of the texture size vector (either
* bld->int_coord_type or bld->coord_type)
* @param int_size vector with the integer texture size (width, height,
* depth)
*/
void
lp_build_extract_image_sizes(struct lp_build_sample_context *bld,
struct lp_type size_type,
struct lp_type coord_type,
LLVMValueRef size,
LLVMValueRef *out_width,
LLVMValueRef *out_height,
LLVMValueRef *out_depth)
{
const unsigned dims = bld->dims;
LLVMTypeRef i32t = LLVMInt32Type();
*out_width = lp_build_extract_broadcast(bld->builder,
size_type,
coord_type,
size,
LLVMConstInt(i32t, 0, 0));
if (dims >= 2) {
*out_height = lp_build_extract_broadcast(bld->builder,
size_type,
coord_type,
size,
LLVMConstInt(i32t, 1, 0));
if (dims == 3) {
*out_depth = lp_build_extract_broadcast(bld->builder,
size_type,
coord_type,
size,
LLVMConstInt(i32t, 2, 0));
}
}
}
/**
* Unnormalize coords.
*
* @param int_size vector with the integer texture size (width, height, depth)
*/
void
lp_build_unnormalized_coords(struct lp_build_sample_context *bld,
LLVMValueRef flt_size,
LLVMValueRef *s,
LLVMValueRef *t,
LLVMValueRef *r)
{
const unsigned dims = bld->dims;
LLVMValueRef width;
LLVMValueRef height;
LLVMValueRef depth;
lp_build_extract_image_sizes(bld,
bld->float_size_type,
bld->coord_type,
flt_size,
&width,
&height,
&depth);
/* s = s * width, t = t * height */
*s = lp_build_mul(&bld->coord_bld, *s, width);
if (dims >= 2) {
*t = lp_build_mul(&bld->coord_bld, *t, height);
if (dims >= 3) {
*r = lp_build_mul(&bld->coord_bld, *r, depth);
}
}
}
/** Helper used by lp_build_cube_lookup() */ /** Helper used by lp_build_cube_lookup() */
static LLVMValueRef static LLVMValueRef
@ -798,25 +924,16 @@ lp_build_cube_lookup(struct lp_build_sample_context *bld,
rz_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, rz, float_bld->zero, ""); rz_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, rz, float_bld->zero, "");
{ {
struct lp_build_flow_context *flow_ctx;
struct lp_build_if_state if_ctx; struct lp_build_if_state if_ctx;
LLVMValueRef face_s_var;
LLVMValueRef face_t_var;
LLVMValueRef face_var;
flow_ctx = lp_build_flow_create(bld->builder); face_s_var = lp_build_alloca(bld->builder, bld->coord_bld.vec_type, "face_s_var");
lp_build_flow_scope_begin(flow_ctx); face_t_var = lp_build_alloca(bld->builder, bld->coord_bld.vec_type, "face_t_var");
face_var = lp_build_alloca(bld->builder, bld->int_bld.vec_type, "face_var");
*face_s = bld->coord_bld.undef; lp_build_if(&if_ctx, bld->builder, arx_ge_ary_arz);
*face_t = bld->coord_bld.undef;
*face = bld->int_bld.undef;
lp_build_name(*face_s, "face_s");
lp_build_name(*face_t, "face_t");
lp_build_name(*face, "face");
lp_build_flow_scope_declare(flow_ctx, face_s);
lp_build_flow_scope_declare(flow_ctx, face_t);
lp_build_flow_scope_declare(flow_ctx, face);
lp_build_if(&if_ctx, flow_ctx, bld->builder, arx_ge_ary_arz);
{ {
/* +/- X face */ /* +/- X face */
LLVMValueRef sign = lp_build_sgn(float_bld, rx); LLVMValueRef sign = lp_build_sgn(float_bld, rx);
@ -826,57 +943,52 @@ lp_build_cube_lookup(struct lp_build_sample_context *bld,
*face = lp_build_cube_face(bld, rx, *face = lp_build_cube_face(bld, rx,
PIPE_TEX_FACE_POS_X, PIPE_TEX_FACE_POS_X,
PIPE_TEX_FACE_NEG_X); PIPE_TEX_FACE_NEG_X);
LLVMBuildStore(bld->builder, *face_s, face_s_var);
LLVMBuildStore(bld->builder, *face_t, face_t_var);
LLVMBuildStore(bld->builder, *face, face_var);
} }
lp_build_else(&if_ctx); lp_build_else(&if_ctx);
{ {
struct lp_build_flow_context *flow_ctx2;
struct lp_build_if_state if_ctx2; struct lp_build_if_state if_ctx2;
LLVMValueRef face_s2 = bld->coord_bld.undef;
LLVMValueRef face_t2 = bld->coord_bld.undef;
LLVMValueRef face2 = bld->int_bld.undef;
flow_ctx2 = lp_build_flow_create(bld->builder);
lp_build_flow_scope_begin(flow_ctx2);
lp_build_flow_scope_declare(flow_ctx2, &face_s2);
lp_build_flow_scope_declare(flow_ctx2, &face_t2);
lp_build_flow_scope_declare(flow_ctx2, &face2);
ary_ge_arx_arz = LLVMBuildAnd(bld->builder, ary_ge_arx, ary_ge_arz, ""); ary_ge_arx_arz = LLVMBuildAnd(bld->builder, ary_ge_arx, ary_ge_arz, "");
lp_build_if(&if_ctx2, flow_ctx2, bld->builder, ary_ge_arx_arz); lp_build_if(&if_ctx2, bld->builder, ary_ge_arx_arz);
{ {
/* +/- Y face */ /* +/- Y face */
LLVMValueRef sign = lp_build_sgn(float_bld, ry); LLVMValueRef sign = lp_build_sgn(float_bld, ry);
LLVMValueRef ima = lp_build_cube_ima(coord_bld, t); LLVMValueRef ima = lp_build_cube_ima(coord_bld, t);
face_s2 = lp_build_cube_coord(coord_bld, NULL, -1, s, ima); *face_s = lp_build_cube_coord(coord_bld, NULL, -1, s, ima);
face_t2 = lp_build_cube_coord(coord_bld, sign, -1, r, ima); *face_t = lp_build_cube_coord(coord_bld, sign, -1, r, ima);
face2 = lp_build_cube_face(bld, ry, *face = lp_build_cube_face(bld, ry,
PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_POS_Y,
PIPE_TEX_FACE_NEG_Y); PIPE_TEX_FACE_NEG_Y);
LLVMBuildStore(bld->builder, *face_s, face_s_var);
LLVMBuildStore(bld->builder, *face_t, face_t_var);
LLVMBuildStore(bld->builder, *face, face_var);
} }
lp_build_else(&if_ctx2); lp_build_else(&if_ctx2);
{ {
/* +/- Z face */ /* +/- Z face */
LLVMValueRef sign = lp_build_sgn(float_bld, rz); LLVMValueRef sign = lp_build_sgn(float_bld, rz);
LLVMValueRef ima = lp_build_cube_ima(coord_bld, r); LLVMValueRef ima = lp_build_cube_ima(coord_bld, r);
face_s2 = lp_build_cube_coord(coord_bld, sign, -1, s, ima); *face_s = lp_build_cube_coord(coord_bld, sign, -1, s, ima);
face_t2 = lp_build_cube_coord(coord_bld, NULL, +1, t, ima); *face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
face2 = lp_build_cube_face(bld, rz, *face = lp_build_cube_face(bld, rz,
PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_POS_Z,
PIPE_TEX_FACE_NEG_Z); PIPE_TEX_FACE_NEG_Z);
LLVMBuildStore(bld->builder, *face_s, face_s_var);
LLVMBuildStore(bld->builder, *face_t, face_t_var);
LLVMBuildStore(bld->builder, *face, face_var);
} }
lp_build_endif(&if_ctx2); lp_build_endif(&if_ctx2);
lp_build_flow_scope_end(flow_ctx2);
lp_build_flow_destroy(flow_ctx2);
*face_s = face_s2;
*face_t = face_t2;
*face = face2;
} }
lp_build_endif(&if_ctx); lp_build_endif(&if_ctx);
lp_build_flow_scope_end(flow_ctx);
lp_build_flow_destroy(flow_ctx); *face_s = LLVMBuildLoad(bld->builder, face_s_var, "face_s");
*face_t = LLVMBuildLoad(bld->builder, face_t_var, "face_t");
*face = LLVMBuildLoad(bld->builder, face_var, "face");
} }
} }

View file

@ -197,10 +197,6 @@ struct lp_build_sample_context
struct lp_type coord_type; struct lp_type coord_type;
struct lp_build_context coord_bld; struct lp_build_context coord_bld;
/** Unsigned integer coordinates */
struct lp_type uint_coord_type;
struct lp_build_context uint_coord_bld;
/** Signed integer coordinates */ /** Signed integer coordinates */
struct lp_type int_coord_type; struct lp_type int_coord_type;
struct lp_build_context int_coord_bld; struct lp_build_context int_coord_bld;
@ -333,13 +329,29 @@ lp_build_get_const_mipmap_level(struct lp_build_sample_context *bld,
void void
lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld, lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
LLVMValueRef ilevel, LLVMValueRef ilevel,
LLVMValueRef *out_width_vec, LLVMValueRef *out_size_vec,
LLVMValueRef *out_height_vec,
LLVMValueRef *out_depth_vec,
LLVMValueRef *row_stride_vec, LLVMValueRef *row_stride_vec,
LLVMValueRef *img_stride_vec); LLVMValueRef *img_stride_vec);
void
lp_build_extract_image_sizes(struct lp_build_sample_context *bld,
struct lp_type size_type,
struct lp_type coord_type,
LLVMValueRef size,
LLVMValueRef *out_width,
LLVMValueRef *out_height,
LLVMValueRef *out_depth);
void
lp_build_unnormalized_coords(struct lp_build_sample_context *bld,
LLVMValueRef flt_size,
LLVMValueRef *s,
LLVMValueRef *t,
LLVMValueRef *r);
void void
lp_build_cube_lookup(struct lp_build_sample_context *bld, lp_build_cube_lookup(struct lp_build_sample_context *bld,
LLVMValueRef s, LLVMValueRef s,

View file

@ -45,6 +45,7 @@
#include "lp_bld_const.h" #include "lp_bld_const.h"
#include "lp_bld_conv.h" #include "lp_bld_conv.h"
#include "lp_bld_arit.h" #include "lp_bld_arit.h"
#include "lp_bld_bitarit.h"
#include "lp_bld_logic.h" #include "lp_bld_logic.h"
#include "lp_bld_swizzle.h" #include "lp_bld_swizzle.h"
#include "lp_bld_pack.h" #include "lp_bld_pack.h"
@ -80,11 +81,10 @@ lp_build_sample_wrap_nearest_int(struct lp_build_sample_context *bld,
LLVMValueRef *out_offset, LLVMValueRef *out_offset,
LLVMValueRef *out_i) 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; struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
LLVMValueRef length_minus_one; LLVMValueRef length_minus_one;
length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one); length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
switch(wrap_mode) { switch(wrap_mode) {
case PIPE_TEX_WRAP_REPEAT: case PIPE_TEX_WRAP_REPEAT:
@ -92,7 +92,7 @@ lp_build_sample_wrap_nearest_int(struct lp_build_sample_context *bld,
coord = LLVMBuildAnd(bld->builder, coord, length_minus_one, ""); coord = LLVMBuildAnd(bld->builder, coord, length_minus_one, "");
else { else {
/* Add a bias to the texcoord to handle negative coords */ /* Add a bias to the texcoord to handle negative coords */
LLVMValueRef bias = lp_build_mul_imm(uint_coord_bld, length, 1024); LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
coord = LLVMBuildAdd(bld->builder, coord, bias, ""); coord = LLVMBuildAdd(bld->builder, coord, bias, "");
coord = LLVMBuildURem(bld->builder, coord, length, ""); coord = LLVMBuildURem(bld->builder, coord, length, "");
} }
@ -113,7 +113,7 @@ lp_build_sample_wrap_nearest_int(struct lp_build_sample_context *bld,
assert(0); assert(0);
} }
lp_build_sample_partial_offset(uint_coord_bld, block_length, coord, stride, lp_build_sample_partial_offset(int_coord_bld, block_length, coord, stride,
out_offset, out_i); out_offset, out_i);
} }
@ -146,7 +146,6 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
LLVMValueRef *i0, LLVMValueRef *i0,
LLVMValueRef *i1) LLVMValueRef *i1)
{ {
struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
struct lp_build_context *int_coord_bld = &bld->int_coord_bld; struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
LLVMValueRef length_minus_one; LLVMValueRef length_minus_one;
LLVMValueRef lmask, umask, mask; LLVMValueRef lmask, umask, mask;
@ -188,8 +187,8 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
* multiplication. * multiplication.
*/ */
*i0 = uint_coord_bld->zero; *i0 = int_coord_bld->zero;
*i1 = uint_coord_bld->zero; *i1 = int_coord_bld->zero;
length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one); length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
@ -200,7 +199,7 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
} }
else { else {
/* Add a bias to the texcoord to handle negative coords */ /* Add a bias to the texcoord to handle negative coords */
LLVMValueRef bias = lp_build_mul_imm(uint_coord_bld, length, 1024); LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
coord0 = LLVMBuildAdd(bld->builder, coord0, bias, ""); coord0 = LLVMBuildAdd(bld->builder, coord0, bias, "");
coord0 = LLVMBuildURem(bld->builder, coord0, length, ""); coord0 = LLVMBuildURem(bld->builder, coord0, length, "");
} }
@ -208,9 +207,9 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
mask = lp_build_compare(bld->builder, int_coord_bld->type, mask = lp_build_compare(bld->builder, int_coord_bld->type,
PIPE_FUNC_NOTEQUAL, coord0, length_minus_one); PIPE_FUNC_NOTEQUAL, coord0, length_minus_one);
*offset0 = lp_build_mul(uint_coord_bld, coord0, stride); *offset0 = lp_build_mul(int_coord_bld, coord0, stride);
*offset1 = LLVMBuildAnd(bld->builder, *offset1 = LLVMBuildAnd(bld->builder,
lp_build_add(uint_coord_bld, *offset0, stride), lp_build_add(int_coord_bld, *offset0, stride),
mask, ""); mask, "");
break; break;
@ -225,8 +224,8 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
mask = LLVMBuildAnd(bld->builder, lmask, umask, ""); mask = LLVMBuildAnd(bld->builder, lmask, umask, "");
*offset0 = lp_build_mul(uint_coord_bld, coord0, stride); *offset0 = lp_build_mul(int_coord_bld, coord0, stride);
*offset1 = lp_build_add(uint_coord_bld, *offset1 = lp_build_add(int_coord_bld,
*offset0, *offset0,
LLVMBuildAnd(bld->builder, stride, mask, "")); LLVMBuildAnd(bld->builder, stride, mask, ""));
break; break;
@ -239,8 +238,8 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
default: default:
assert(0); assert(0);
*offset0 = uint_coord_bld->zero; *offset0 = int_coord_bld->zero;
*offset1 = uint_coord_bld->zero; *offset1 = int_coord_bld->zero;
break; break;
} }
} }
@ -253,9 +252,7 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
*/ */
static void static void
lp_build_sample_image_nearest(struct lp_build_sample_context *bld, lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
LLVMValueRef width_vec, LLVMValueRef int_size,
LLVMValueRef height_vec,
LLVMValueRef depth_vec,
LLVMValueRef row_stride_vec, LLVMValueRef row_stride_vec,
LLVMValueRef img_stride_vec, LLVMValueRef img_stride_vec,
LLVMValueRef data_ptr, LLVMValueRef data_ptr,
@ -270,7 +267,8 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
struct lp_build_context i32, h16, u8n; struct lp_build_context i32, h16, u8n;
LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type; LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type;
LLVMValueRef i32_c8; LLVMValueRef i32_c8;
LLVMValueRef s_ipart, t_ipart, r_ipart; LLVMValueRef width_vec, height_vec, depth_vec;
LLVMValueRef s_ipart, t_ipart = NULL, r_ipart = NULL;
LLVMValueRef x_stride; LLVMValueRef x_stride;
LLVMValueRef x_offset, offset; LLVMValueRef x_offset, offset;
LLVMValueRef x_subcoord, y_subcoord, z_subcoord; LLVMValueRef x_subcoord, y_subcoord, z_subcoord;
@ -283,30 +281,33 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
h16_vec_type = lp_build_vec_type(h16.type); h16_vec_type = lp_build_vec_type(h16.type);
u8n_vec_type = lp_build_vec_type(u8n.type); u8n_vec_type = lp_build_vec_type(u8n.type);
if (bld->static_state->normalized_coords) { lp_build_extract_image_sizes(bld,
/* s = s * width, t = t * height */ bld->int_size_type,
LLVMTypeRef coord_vec_type = lp_build_vec_type(bld->coord_type); bld->int_coord_type,
LLVMValueRef fp_width = LLVMBuildSIToFP(bld->builder, width_vec, int_size,
coord_vec_type, ""); &width_vec,
s = lp_build_mul(&bld->coord_bld, s, fp_width); &height_vec,
if (dims >= 2) { &depth_vec);
LLVMValueRef fp_height = LLVMBuildSIToFP(bld->builder, height_vec,
coord_vec_type, "");
t = lp_build_mul(&bld->coord_bld, t, fp_height);
if (dims >= 3) {
LLVMValueRef fp_depth = LLVMBuildSIToFP(bld->builder, depth_vec,
coord_vec_type, "");
r = lp_build_mul(&bld->coord_bld, r, fp_depth);
}
}
}
if (bld->static_state->normalized_coords) {
LLVMValueRef scaled_size;
LLVMValueRef flt_size;
/* scale size by 256 (8 fractional bits) */
scaled_size = lp_build_shl_imm(&bld->int_size_bld, int_size, 8);
flt_size = lp_build_int_to_float(&bld->float_size_bld, scaled_size);
lp_build_unnormalized_coords(bld, flt_size, &s, &t, &r);
}
else {
/* scale coords by 256 (8 fractional bits) */ /* scale coords by 256 (8 fractional bits) */
s = lp_build_mul_imm(&bld->coord_bld, s, 256); s = lp_build_mul_imm(&bld->coord_bld, s, 256);
if (dims >= 2) if (dims >= 2)
t = lp_build_mul_imm(&bld->coord_bld, t, 256); t = lp_build_mul_imm(&bld->coord_bld, t, 256);
if (dims >= 3) if (dims >= 3)
r = lp_build_mul_imm(&bld->coord_bld, r, 256); r = lp_build_mul_imm(&bld->coord_bld, r, 256);
}
/* convert float to int */ /* convert float to int */
s = LLVMBuildFPToSI(builder, s, i32_vec_type, ""); s = LLVMBuildFPToSI(builder, s, i32_vec_type, "");
@ -324,7 +325,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
r_ipart = LLVMBuildAShr(builder, r, i32_c8, ""); r_ipart = LLVMBuildAShr(builder, r, i32_c8, "");
/* get pixel, row, image strides */ /* get pixel, row, image strides */
x_stride = lp_build_const_vec(bld->uint_coord_bld.type, x_stride = lp_build_const_vec(bld->int_coord_bld.type,
bld->format_desc->block.bits/8); bld->format_desc->block.bits/8);
/* Do texcoord wrapping, compute texel offset */ /* Do texcoord wrapping, compute texel offset */
@ -343,7 +344,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
bld->static_state->pot_height, bld->static_state->pot_height,
bld->static_state->wrap_t, bld->static_state->wrap_t,
&y_offset, &y_subcoord); &y_offset, &y_subcoord);
offset = lp_build_add(&bld->uint_coord_bld, offset, y_offset); offset = lp_build_add(&bld->int_coord_bld, offset, y_offset);
if (dims >= 3) { if (dims >= 3) {
LLVMValueRef z_offset; LLVMValueRef z_offset;
lp_build_sample_wrap_nearest_int(bld, lp_build_sample_wrap_nearest_int(bld,
@ -352,13 +353,13 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
bld->static_state->pot_height, bld->static_state->pot_height,
bld->static_state->wrap_r, bld->static_state->wrap_r,
&z_offset, &z_subcoord); &z_offset, &z_subcoord);
offset = lp_build_add(&bld->uint_coord_bld, offset, z_offset); offset = lp_build_add(&bld->int_coord_bld, offset, z_offset);
} }
else if (bld->static_state->target == PIPE_TEXTURE_CUBE) { else if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
LLVMValueRef z_offset; LLVMValueRef z_offset;
/* The r coord is the cube face in [0,5] */ /* The r coord is the cube face in [0,5] */
z_offset = lp_build_mul(&bld->uint_coord_bld, r, img_stride_vec); z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
offset = lp_build_add(&bld->uint_coord_bld, offset, z_offset); offset = lp_build_add(&bld->int_coord_bld, offset, z_offset);
} }
} }
@ -417,9 +418,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
*/ */
static void static void
lp_build_sample_image_linear(struct lp_build_sample_context *bld, lp_build_sample_image_linear(struct lp_build_sample_context *bld,
LLVMValueRef width_vec, LLVMValueRef int_size,
LLVMValueRef height_vec,
LLVMValueRef depth_vec,
LLVMValueRef row_stride_vec, LLVMValueRef row_stride_vec,
LLVMValueRef img_stride_vec, LLVMValueRef img_stride_vec,
LLVMValueRef data_ptr, LLVMValueRef data_ptr,
@ -434,9 +433,10 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
struct lp_build_context i32, h16, u8n; struct lp_build_context i32, h16, u8n;
LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type; LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type;
LLVMValueRef i32_c8, i32_c128, i32_c255; LLVMValueRef i32_c8, i32_c128, i32_c255;
LLVMValueRef width_vec, height_vec, depth_vec;
LLVMValueRef s_ipart, s_fpart, s_fpart_lo, s_fpart_hi; LLVMValueRef s_ipart, s_fpart, s_fpart_lo, s_fpart_hi;
LLVMValueRef t_ipart, t_fpart, t_fpart_lo, t_fpart_hi; LLVMValueRef t_ipart = NULL, t_fpart = NULL, t_fpart_lo = NULL, t_fpart_hi = NULL;
LLVMValueRef r_ipart, r_fpart, r_fpart_lo, r_fpart_hi; LLVMValueRef r_ipart = NULL, r_fpart = NULL, r_fpart_lo = NULL, r_fpart_hi = NULL;
LLVMValueRef x_stride, y_stride, z_stride; LLVMValueRef x_stride, y_stride, z_stride;
LLVMValueRef x_offset0, x_offset1; LLVMValueRef x_offset0, x_offset1;
LLVMValueRef y_offset0, y_offset1; LLVMValueRef y_offset0, y_offset1;
@ -458,30 +458,33 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
h16_vec_type = lp_build_vec_type(h16.type); h16_vec_type = lp_build_vec_type(h16.type);
u8n_vec_type = lp_build_vec_type(u8n.type); u8n_vec_type = lp_build_vec_type(u8n.type);
if (bld->static_state->normalized_coords) { lp_build_extract_image_sizes(bld,
/* s = s * width, t = t * height */ bld->int_size_type,
LLVMTypeRef coord_vec_type = lp_build_vec_type(bld->coord_type); bld->int_coord_type,
LLVMValueRef fp_width = LLVMBuildSIToFP(bld->builder, width_vec, int_size,
coord_vec_type, ""); &width_vec,
s = lp_build_mul(&bld->coord_bld, s, fp_width); &height_vec,
if (dims >= 2) { &depth_vec);
LLVMValueRef fp_height = LLVMBuildSIToFP(bld->builder, height_vec,
coord_vec_type, "");
t = lp_build_mul(&bld->coord_bld, t, fp_height);
}
if (dims >= 3) {
LLVMValueRef fp_depth = LLVMBuildSIToFP(bld->builder, depth_vec,
coord_vec_type, "");
r = lp_build_mul(&bld->coord_bld, r, fp_depth);
}
}
if (bld->static_state->normalized_coords) {
LLVMValueRef scaled_size;
LLVMValueRef flt_size;
/* scale size by 256 (8 fractional bits) */
scaled_size = lp_build_shl_imm(&bld->int_size_bld, int_size, 8);
flt_size = lp_build_int_to_float(&bld->float_size_bld, scaled_size);
lp_build_unnormalized_coords(bld, flt_size, &s, &t, &r);
}
else {
/* scale coords by 256 (8 fractional bits) */ /* scale coords by 256 (8 fractional bits) */
s = lp_build_mul_imm(&bld->coord_bld, s, 256); s = lp_build_mul_imm(&bld->coord_bld, s, 256);
if (dims >= 2) if (dims >= 2)
t = lp_build_mul_imm(&bld->coord_bld, t, 256); t = lp_build_mul_imm(&bld->coord_bld, t, 256);
if (dims >= 3) if (dims >= 3)
r = lp_build_mul_imm(&bld->coord_bld, r, 256); r = lp_build_mul_imm(&bld->coord_bld, r, 256);
}
/* convert float to int */ /* convert float to int */
s = LLVMBuildFPToSI(builder, s, i32_vec_type, ""); s = LLVMBuildFPToSI(builder, s, i32_vec_type, "");
@ -517,7 +520,7 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
r_fpart = LLVMBuildAnd(builder, r, i32_c255, ""); r_fpart = LLVMBuildAnd(builder, r, i32_c255, "");
/* get pixel, row and image strides */ /* get pixel, row and image strides */
x_stride = lp_build_const_vec(bld->uint_coord_bld.type, x_stride = lp_build_const_vec(bld->int_coord_bld.type,
bld->format_desc->block.bits/8); bld->format_desc->block.bits/8);
y_stride = row_stride_vec; y_stride = row_stride_vec;
z_stride = img_stride_vec; z_stride = img_stride_vec;
@ -548,9 +551,9 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
for (z = 0; z < 2; z++) { for (z = 0; z < 2; z++) {
for (x = 0; x < 2; x++) { for (x = 0; x < 2; x++) {
offset[z][0][x] = lp_build_add(&bld->uint_coord_bld, offset[z][0][x] = lp_build_add(&bld->int_coord_bld,
offset[z][0][x], y_offset0); offset[z][0][x], y_offset0);
offset[z][1][x] = lp_build_add(&bld->uint_coord_bld, offset[z][1][x] = lp_build_add(&bld->int_coord_bld,
offset[z][1][x], y_offset1); offset[z][1][x], y_offset1);
} }
} }
@ -566,20 +569,20 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
&z_subcoord[0], &z_subcoord[1]); &z_subcoord[0], &z_subcoord[1]);
for (y = 0; y < 2; y++) { for (y = 0; y < 2; y++) {
for (x = 0; x < 2; x++) { for (x = 0; x < 2; x++) {
offset[0][y][x] = lp_build_add(&bld->uint_coord_bld, offset[0][y][x] = lp_build_add(&bld->int_coord_bld,
offset[0][y][x], z_offset0); offset[0][y][x], z_offset0);
offset[1][y][x] = lp_build_add(&bld->uint_coord_bld, offset[1][y][x] = lp_build_add(&bld->int_coord_bld,
offset[1][y][x], z_offset1); offset[1][y][x], z_offset1);
} }
} }
} }
else if (bld->static_state->target == PIPE_TEXTURE_CUBE) { else if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
LLVMValueRef z_offset; LLVMValueRef z_offset;
z_offset = lp_build_mul(&bld->uint_coord_bld, r, img_stride_vec); z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
for (y = 0; y < 2; y++) { for (y = 0; y < 2; y++) {
for (x = 0; x < 2; x++) { for (x = 0; x < 2; x++) {
/* The r coord is the cube face in [0,5] */ /* The r coord is the cube face in [0,5] */
offset[0][y][x] = lp_build_add(&bld->uint_coord_bld, offset[0][y][x] = lp_build_add(&bld->int_coord_bld,
offset[0][y][x], z_offset); offset[0][y][x], z_offset);
} }
} }
@ -788,12 +791,8 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
LLVMValueRef colors_hi_var) LLVMValueRef colors_hi_var)
{ {
LLVMBuilderRef builder = bld->builder; LLVMBuilderRef builder = bld->builder;
LLVMValueRef width0_vec; LLVMValueRef size0;
LLVMValueRef width1_vec; LLVMValueRef size1;
LLVMValueRef height0_vec;
LLVMValueRef height1_vec;
LLVMValueRef depth0_vec;
LLVMValueRef depth1_vec;
LLVMValueRef row_stride0_vec; LLVMValueRef row_stride0_vec;
LLVMValueRef row_stride1_vec; LLVMValueRef row_stride1_vec;
LLVMValueRef img_stride0_vec; LLVMValueRef img_stride0_vec;
@ -806,12 +805,12 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
/* sample the first mipmap level */ /* sample the first mipmap level */
lp_build_mipmap_level_sizes(bld, ilevel0, lp_build_mipmap_level_sizes(bld, ilevel0,
&width0_vec, &height0_vec, &depth0_vec, &size0,
&row_stride0_vec, &img_stride0_vec); &row_stride0_vec, &img_stride0_vec);
data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0); data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
if (img_filter == PIPE_TEX_FILTER_NEAREST) { if (img_filter == PIPE_TEX_FILTER_NEAREST) {
lp_build_sample_image_nearest(bld, lp_build_sample_image_nearest(bld,
width0_vec, height0_vec, depth0_vec, size0,
row_stride0_vec, img_stride0_vec, row_stride0_vec, img_stride0_vec,
data_ptr0, s, t, r, data_ptr0, s, t, r,
&colors0_lo, &colors0_hi); &colors0_lo, &colors0_hi);
@ -819,7 +818,7 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
else { else {
assert(img_filter == PIPE_TEX_FILTER_LINEAR); assert(img_filter == PIPE_TEX_FILTER_LINEAR);
lp_build_sample_image_linear(bld, lp_build_sample_image_linear(bld,
width0_vec, height0_vec, depth0_vec, size0,
row_stride0_vec, img_stride0_vec, row_stride0_vec, img_stride0_vec,
data_ptr0, s, t, r, data_ptr0, s, t, r,
&colors0_lo, &colors0_hi); &colors0_lo, &colors0_hi);
@ -832,12 +831,9 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
LLVMValueRef h16_scale = LLVMConstReal(LLVMFloatType(), 256.0); LLVMValueRef h16_scale = LLVMConstReal(LLVMFloatType(), 256.0);
LLVMTypeRef i32_type = LLVMIntType(32); LLVMTypeRef i32_type = LLVMIntType(32);
struct lp_build_flow_context *flow_ctx;
struct lp_build_if_state if_ctx; struct lp_build_if_state if_ctx;
LLVMValueRef need_lerp; LLVMValueRef need_lerp;
flow_ctx = lp_build_flow_create(builder);
lod_fpart = LLVMBuildFMul(builder, lod_fpart, h16_scale, ""); lod_fpart = LLVMBuildFMul(builder, lod_fpart, h16_scale, "");
lod_fpart = LLVMBuildFPToSI(builder, lod_fpart, i32_type, "lod_fpart.fixed16"); lod_fpart = LLVMBuildFPToSI(builder, lod_fpart, i32_type, "lod_fpart.fixed16");
@ -846,7 +842,7 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
lod_fpart, LLVMConstNull(i32_type), lod_fpart, LLVMConstNull(i32_type),
"need_lerp"); "need_lerp");
lp_build_if(&if_ctx, flow_ctx, builder, need_lerp); lp_build_if(&if_ctx, builder, need_lerp);
{ {
struct lp_build_context h16_bld; struct lp_build_context h16_bld;
@ -854,19 +850,19 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
/* sample the second mipmap level */ /* sample the second mipmap level */
lp_build_mipmap_level_sizes(bld, ilevel1, lp_build_mipmap_level_sizes(bld, ilevel1,
&width1_vec, &height1_vec, &depth1_vec, &size1,
&row_stride1_vec, &img_stride1_vec); &row_stride1_vec, &img_stride1_vec);
data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1); data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
if (img_filter == PIPE_TEX_FILTER_NEAREST) { if (img_filter == PIPE_TEX_FILTER_NEAREST) {
lp_build_sample_image_nearest(bld, lp_build_sample_image_nearest(bld,
width1_vec, height1_vec, depth1_vec, size1,
row_stride1_vec, img_stride1_vec, row_stride1_vec, img_stride1_vec,
data_ptr1, s, t, r, data_ptr1, s, t, r,
&colors1_lo, &colors1_hi); &colors1_lo, &colors1_hi);
} }
else { else {
lp_build_sample_image_linear(bld, lp_build_sample_image_linear(bld,
width1_vec, height1_vec, depth1_vec, size1,
row_stride1_vec, img_stride1_vec, row_stride1_vec, img_stride1_vec,
data_ptr1, s, t, r, data_ptr1, s, t, r,
&colors1_lo, &colors1_hi); &colors1_lo, &colors1_hi);
@ -877,6 +873,26 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
lod_fpart = LLVMBuildTrunc(builder, lod_fpart, h16_bld.elem_type, ""); lod_fpart = LLVMBuildTrunc(builder, lod_fpart, h16_bld.elem_type, "");
lod_fpart = lp_build_broadcast_scalar(&h16_bld, lod_fpart); lod_fpart = lp_build_broadcast_scalar(&h16_bld, lod_fpart);
#if HAVE_LLVM == 0x208
/* This is a work-around for a bug in LLVM 2.8.
* Evidently, something goes wrong in the construction of the
* lod_fpart short[8] vector. Adding this no-effect shuffle seems
* to force the vector to be properly constructed.
* Tested with mesa-demos/src/tests/mipmap_limits.c (press t, f).
*/
{
LLVMValueRef shuffles[8], shuffle;
int i;
assert(h16_bld.type.length <= Elements(shuffles));
for (i = 0; i < h16_bld.type.length; i++)
shuffles[i] = lp_build_const_int32(2 * (i & 1));
shuffle = LLVMConstVector(shuffles, h16_bld.type.length);
lod_fpart = LLVMBuildShuffleVector(builder,
lod_fpart, lod_fpart,
shuffle, "");
}
#endif
colors0_lo = lp_build_lerp(&h16_bld, lod_fpart, colors0_lo = lp_build_lerp(&h16_bld, lod_fpart,
colors0_lo, colors1_lo); colors0_lo, colors1_lo);
colors0_hi = lp_build_lerp(&h16_bld, lod_fpart, colors0_hi = lp_build_lerp(&h16_bld, lod_fpart,
@ -886,8 +902,6 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
LLVMBuildStore(builder, colors0_hi, colors_hi_var); LLVMBuildStore(builder, colors0_hi, colors_hi_var);
} }
lp_build_endif(&if_ctx); lp_build_endif(&if_ctx);
lp_build_flow_destroy(flow_ctx);
} }
} }
@ -946,12 +960,12 @@ lp_build_sample_aos(struct lp_build_sample_context *bld,
r = lp_build_broadcast_scalar(&bld->int_coord_bld, face); /* vec */ r = lp_build_broadcast_scalar(&bld->int_coord_bld, face); /* vec */
/* recompute ddx, ddy using the new (s,t) face texcoords */ /* recompute ddx, ddy using the new (s,t) face texcoords */
face_ddx[0] = lp_build_ddx(&bld->coord_bld, s); face_ddx[0] = lp_build_scalar_ddx(&bld->coord_bld, s);
face_ddx[1] = lp_build_ddx(&bld->coord_bld, t); face_ddx[1] = lp_build_scalar_ddx(&bld->coord_bld, t);
face_ddx[2] = NULL; face_ddx[2] = NULL;
face_ddx[3] = NULL; face_ddx[3] = NULL;
face_ddy[0] = lp_build_ddy(&bld->coord_bld, s); face_ddy[0] = lp_build_scalar_ddy(&bld->coord_bld, s);
face_ddy[1] = lp_build_ddy(&bld->coord_bld, t); face_ddy[1] = lp_build_scalar_ddy(&bld->coord_bld, t);
face_ddy[2] = NULL; face_ddy[2] = NULL;
face_ddy[3] = NULL; face_ddy[3] = NULL;
ddx = face_ddx; ddx = face_ddx;
@ -1027,17 +1041,14 @@ lp_build_sample_aos(struct lp_build_sample_context *bld,
/* Emit conditional to choose min image filter or mag image filter /* Emit conditional to choose min image filter or mag image filter
* depending on the lod being > 0 or <= 0, respectively. * depending on the lod being > 0 or <= 0, respectively.
*/ */
struct lp_build_flow_context *flow_ctx;
struct lp_build_if_state if_ctx; struct lp_build_if_state if_ctx;
LLVMValueRef minify; LLVMValueRef minify;
flow_ctx = lp_build_flow_create(builder);
/* minify = lod >= 0.0 */ /* minify = lod >= 0.0 */
minify = LLVMBuildICmp(builder, LLVMIntSGE, minify = LLVMBuildICmp(builder, LLVMIntSGE,
lod_ipart, int_bld->zero, ""); lod_ipart, int_bld->zero, "");
lp_build_if(&if_ctx, flow_ctx, builder, minify); lp_build_if(&if_ctx, builder, minify);
{ {
/* Use the minification filter */ /* Use the minification filter */
lp_build_sample_mipmap(bld, lp_build_sample_mipmap(bld,
@ -1056,8 +1067,6 @@ lp_build_sample_aos(struct lp_build_sample_context *bld,
packed_lo, packed_hi); packed_lo, packed_hi);
} }
lp_build_endif(&if_ctx); lp_build_endif(&if_ctx);
lp_build_flow_destroy(flow_ctx);
} }
/* /*

View file

@ -131,7 +131,7 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld,
} }
/* convert x,y,z coords to linear offset from start of texture, in bytes */ /* convert x,y,z coords to linear offset from start of texture, in bytes */
lp_build_sample_offset(&bld->uint_coord_bld, lp_build_sample_offset(&bld->int_coord_bld,
bld->format_desc, bld->format_desc,
x, y, z, y_stride, z_stride, x, y, z, y_stride, z_stride,
&offset, &i, &j); &offset, &i, &j);
@ -145,7 +145,7 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld,
* coords which are out of bounds to become zero. Zero's guaranteed * coords which are out of bounds to become zero. Zero's guaranteed
* to be inside the texture image. * to be inside the texture image.
*/ */
offset = lp_build_andnot(&bld->uint_coord_bld, offset, use_border); offset = lp_build_andnot(&bld->int_coord_bld, offset, use_border);
} }
lp_build_fetch_rgba_soa(bld->builder, lp_build_fetch_rgba_soa(bld->builder,
@ -202,11 +202,7 @@ lp_build_coord_mirror(struct lp_build_sample_context *bld,
struct lp_build_context *int_coord_bld = &bld->int_coord_bld; struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
LLVMValueRef fract, flr, isOdd; LLVMValueRef fract, flr, isOdd;
/* fract = coord - floor(coord) */ lp_build_ifloor_fract(coord_bld, coord, &flr, &fract);
fract = lp_build_sub(coord_bld, coord, lp_build_floor(coord_bld, coord));
/* flr = ifloor(coord); */
flr = lp_build_ifloor(coord_bld, coord);
/* isOdd = flr & 1 */ /* isOdd = flr & 1 */
isOdd = LLVMBuildAnd(bld->builder, flr, int_coord_bld->one, ""); isOdd = LLVMBuildAnd(bld->builder, flr, int_coord_bld->one, "");
@ -234,6 +230,7 @@ static void
lp_build_sample_wrap_linear(struct lp_build_sample_context *bld, lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
LLVMValueRef coord, LLVMValueRef coord,
LLVMValueRef length, LLVMValueRef length,
LLVMValueRef length_f,
boolean is_pot, boolean is_pot,
unsigned wrap_mode, unsigned wrap_mode,
LLVMValueRef *x0_out, LLVMValueRef *x0_out,
@ -242,10 +239,8 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
{ {
struct lp_build_context *coord_bld = &bld->coord_bld; struct lp_build_context *coord_bld = &bld->coord_bld;
struct lp_build_context *int_coord_bld = &bld->int_coord_bld; struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
LLVMValueRef half = lp_build_const_vec(coord_bld->type, 0.5); LLVMValueRef half = lp_build_const_vec(coord_bld->type, 0.5);
LLVMValueRef length_f = lp_build_int_to_float(coord_bld, length); LLVMValueRef length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
LLVMValueRef length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one);
LLVMValueRef coord0, coord1, weight; LLVMValueRef coord0, coord1, weight;
switch(wrap_mode) { switch(wrap_mode) {
@ -255,19 +250,23 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
coord = lp_build_sub(coord_bld, coord, half); coord = lp_build_sub(coord_bld, coord, half);
/* convert to int, compute lerp weight */ /* convert to int, compute lerp weight */
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight); lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
coord1 = lp_build_add(uint_coord_bld, coord0, uint_coord_bld->one);
/* repeat wrap */ /* repeat wrap */
if (is_pot) { if (is_pot) {
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
coord0 = LLVMBuildAnd(bld->builder, coord0, length_minus_one, ""); coord0 = LLVMBuildAnd(bld->builder, coord0, length_minus_one, "");
coord1 = LLVMBuildAnd(bld->builder, coord1, length_minus_one, ""); coord1 = LLVMBuildAnd(bld->builder, coord1, length_minus_one, "");
} }
else { else {
/* Add a bias to the texcoord to handle negative coords */ /* Add a bias to the texcoord to handle negative coords */
LLVMValueRef bias = lp_build_mul_imm(uint_coord_bld, length, 1024); LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
LLVMValueRef mask;
coord0 = LLVMBuildAdd(bld->builder, coord0, bias, ""); coord0 = LLVMBuildAdd(bld->builder, coord0, bias, "");
coord1 = LLVMBuildAdd(bld->builder, coord1, bias, "");
coord0 = LLVMBuildURem(bld->builder, coord0, length, ""); coord0 = LLVMBuildURem(bld->builder, coord0, length, "");
coord1 = LLVMBuildURem(bld->builder, coord1, length, ""); mask = lp_build_compare(bld->builder, int_coord_bld->type,
PIPE_FUNC_NOTEQUAL, coord0, length_minus_one);
coord1 = LLVMBuildAnd(bld->builder,
lp_build_add(int_coord_bld, coord0, int_coord_bld->one),
mask, "");
} }
break; break;
@ -288,41 +287,39 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
break; break;
case PIPE_TEX_WRAP_CLAMP_TO_EDGE: case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
{
struct lp_build_context abs_coord_bld = bld->coord_bld;
abs_coord_bld.type.sign = FALSE;
if (bld->static_state->normalized_coords) { if (bld->static_state->normalized_coords) {
/* clamp to [0,1] */ /* mul by tex size */
coord = lp_build_clamp(coord_bld, coord, coord_bld->zero, coord_bld->one);
/* mul by tex size and subtract 0.5 */
coord = lp_build_mul(coord_bld, coord, length_f); coord = lp_build_mul(coord_bld, coord, length_f);
}
/* clamp to length max */
coord = lp_build_min(coord_bld, coord, length_f);
/* subtract 0.5 */
coord = lp_build_sub(coord_bld, coord, half); coord = lp_build_sub(coord_bld, coord, half);
} /* clamp to [0, length - 0.5] */
else { coord = lp_build_max(coord_bld, coord, coord_bld->zero);
LLVMValueRef min, max;
/* clamp to [0.5, length - 0.5] */
min = half;
max = lp_build_sub(coord_bld, length_f, min);
coord = lp_build_clamp(coord_bld, coord, min, max);
}
/* convert to int, compute lerp weight */ /* convert to int, compute lerp weight */
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight); lp_build_ifloor_fract(&abs_coord_bld, coord, &coord0, &weight);
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
/* coord0 = max(coord0, 0) */
coord0 = lp_build_max(int_coord_bld, coord0, int_coord_bld->zero);
/* coord1 = min(coord1, length-1) */ /* coord1 = min(coord1, length-1) */
coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one); coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
break; break;
}
case PIPE_TEX_WRAP_CLAMP_TO_BORDER: case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
{ {
LLVMValueRef min, max; LLVMValueRef min;
if (bld->static_state->normalized_coords) { if (bld->static_state->normalized_coords) {
/* scale coord to length */ /* scale coord to length */
coord = lp_build_mul(coord_bld, coord, length_f); coord = lp_build_mul(coord_bld, coord, length_f);
} }
/* clamp to [-0.5, length + 0.5] */ /* was: clamp to [-0.5, length + 0.5], then sub 0.5 */
min = lp_build_const_vec(coord_bld->type, -0.5F);
max = lp_build_sub(coord_bld, length_f, min);
coord = lp_build_clamp(coord_bld, coord, min, max);
coord = lp_build_sub(coord_bld, coord, half); coord = lp_build_sub(coord_bld, coord, half);
min = lp_build_const_vec(coord_bld->type, -1.0F);
coord = lp_build_clamp(coord_bld, coord, min, length_f);
/* convert to int, compute lerp weight */ /* convert to int, compute lerp weight */
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight); lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
@ -368,7 +365,8 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
{ {
LLVMValueRef min, max; LLVMValueRef min, max;
struct lp_build_context abs_coord_bld = bld->coord_bld;
abs_coord_bld.type.sign = FALSE;
coord = lp_build_abs(coord_bld, coord); coord = lp_build_abs(coord_bld, coord);
if (bld->static_state->normalized_coords) { if (bld->static_state->normalized_coords) {
@ -384,15 +382,13 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
coord = lp_build_sub(coord_bld, coord, half); coord = lp_build_sub(coord_bld, coord, half);
/* convert to int, compute lerp weight */ /* convert to int, compute lerp weight */
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight); lp_build_ifloor_fract(&abs_coord_bld, coord, &coord0, &weight);
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
} }
break; break;
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
{ {
LLVMValueRef min, max;
coord = lp_build_abs(coord_bld, coord); coord = lp_build_abs(coord_bld, coord);
if (bld->static_state->normalized_coords) { if (bld->static_state->normalized_coords) {
@ -400,12 +396,10 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
coord = lp_build_mul(coord_bld, coord, length_f); coord = lp_build_mul(coord_bld, coord, length_f);
} }
/* clamp to [-0.5, length + 0.5] */ /* was: clamp to [-0.5, length + 0.5] then sub 0.5 */
min = lp_build_negate(coord_bld, half); /* skip -0.5 clamp (always positive), do sub first */
max = lp_build_sub(coord_bld, length_f, min);
coord = lp_build_clamp(coord_bld, coord, min, max);
coord = lp_build_sub(coord_bld, coord, half); coord = lp_build_sub(coord_bld, coord, half);
coord = lp_build_min(coord_bld, coord, length_f);
/* convert to int, compute lerp weight */ /* convert to int, compute lerp weight */
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight); lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
@ -437,14 +431,13 @@ static LLVMValueRef
lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld, lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
LLVMValueRef coord, LLVMValueRef coord,
LLVMValueRef length, LLVMValueRef length,
LLVMValueRef length_f,
boolean is_pot, boolean is_pot,
unsigned wrap_mode) unsigned wrap_mode)
{ {
struct lp_build_context *coord_bld = &bld->coord_bld; struct lp_build_context *coord_bld = &bld->coord_bld;
struct lp_build_context *int_coord_bld = &bld->int_coord_bld; struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld; LLVMValueRef length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
LLVMValueRef length_f = lp_build_int_to_float(coord_bld, length);
LLVMValueRef length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one);
LLVMValueRef icoord; LLVMValueRef icoord;
switch(wrap_mode) { switch(wrap_mode) {
@ -455,7 +448,7 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
icoord = LLVMBuildAnd(bld->builder, icoord, length_minus_one, ""); icoord = LLVMBuildAnd(bld->builder, icoord, length_minus_one, "");
else { else {
/* Add a bias to the texcoord to handle negative coords */ /* Add a bias to the texcoord to handle negative coords */
LLVMValueRef bias = lp_build_mul_imm(uint_coord_bld, length, 1024); LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
icoord = LLVMBuildAdd(bld->builder, icoord, bias, ""); icoord = LLVMBuildAdd(bld->builder, icoord, bias, "");
icoord = LLVMBuildURem(bld->builder, icoord, length, ""); icoord = LLVMBuildURem(bld->builder, icoord, length, "");
} }
@ -469,7 +462,8 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
} }
/* floor */ /* floor */
icoord = lp_build_ifloor(coord_bld, coord); /* use itrunc instead since we clamp to 0 anyway */
icoord = lp_build_itrunc(coord_bld, coord);
/* clamp to [0, length - 1]. */ /* clamp to [0, length - 1]. */
icoord = lp_build_clamp(int_coord_bld, icoord, int_coord_bld->zero, icoord = lp_build_clamp(int_coord_bld, icoord, int_coord_bld->zero,
@ -503,7 +497,8 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
assert(bld->static_state->normalized_coords); assert(bld->static_state->normalized_coords);
coord = lp_build_mul(coord_bld, coord, length_f); coord = lp_build_mul(coord_bld, coord, length_f);
icoord = lp_build_ifloor(coord_bld, coord); /* itrunc == ifloor here */
icoord = lp_build_itrunc(coord_bld, coord);
/* clamp to [0, length - 1] */ /* clamp to [0, length - 1] */
icoord = lp_build_min(int_coord_bld, icoord, length_minus_one); icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
@ -518,7 +513,8 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
coord = lp_build_mul(coord_bld, coord, length_f); coord = lp_build_mul(coord_bld, coord, length_f);
} }
icoord = lp_build_ifloor(coord_bld, coord); /* itrunc == ifloor here */
icoord = lp_build_itrunc(coord_bld, coord);
/* clamp to [0, length - 1] */ /* clamp to [0, length - 1] */
icoord = lp_build_min(int_coord_bld, icoord, length_minus_one); icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
@ -532,7 +528,8 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
coord = lp_build_mul(coord_bld, coord, length_f); coord = lp_build_mul(coord_bld, coord, length_f);
} }
icoord = lp_build_ifloor(coord_bld, coord); /* itrunc == ifloor here */
icoord = lp_build_itrunc(coord_bld, coord);
/* clamp to [0, length] */ /* clamp to [0, length] */
icoord = lp_build_min(int_coord_bld, icoord, length); icoord = lp_build_min(int_coord_bld, icoord, length);
@ -554,9 +551,7 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
static void static void
lp_build_sample_image_nearest(struct lp_build_sample_context *bld, lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
unsigned unit, unsigned unit,
LLVMValueRef width_vec, LLVMValueRef size,
LLVMValueRef height_vec,
LLVMValueRef depth_vec,
LLVMValueRef row_stride_vec, LLVMValueRef row_stride_vec,
LLVMValueRef img_stride_vec, LLVMValueRef img_stride_vec,
LLVMValueRef data_ptr, LLVMValueRef data_ptr,
@ -566,24 +561,45 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
LLVMValueRef colors_out[4]) LLVMValueRef colors_out[4])
{ {
const unsigned dims = bld->dims; const unsigned dims = bld->dims;
LLVMValueRef width_vec;
LLVMValueRef height_vec;
LLVMValueRef depth_vec;
LLVMValueRef flt_size;
LLVMValueRef flt_width_vec;
LLVMValueRef flt_height_vec;
LLVMValueRef flt_depth_vec;
LLVMValueRef x, y, z; LLVMValueRef x, y, z;
lp_build_extract_image_sizes(bld,
bld->int_size_type,
bld->int_coord_type,
size,
&width_vec, &height_vec, &depth_vec);
flt_size = lp_build_int_to_float(&bld->float_size_bld, size);
lp_build_extract_image_sizes(bld,
bld->float_size_type,
bld->coord_type,
flt_size,
&flt_width_vec, &flt_height_vec, &flt_depth_vec);
/* /*
* Compute integer texcoords. * Compute integer texcoords.
*/ */
x = lp_build_sample_wrap_nearest(bld, s, width_vec, x = lp_build_sample_wrap_nearest(bld, s, width_vec, flt_width_vec,
bld->static_state->pot_width, bld->static_state->pot_width,
bld->static_state->wrap_s); bld->static_state->wrap_s);
lp_build_name(x, "tex.x.wrapped"); lp_build_name(x, "tex.x.wrapped");
if (dims >= 2) { if (dims >= 2) {
y = lp_build_sample_wrap_nearest(bld, t, height_vec, y = lp_build_sample_wrap_nearest(bld, t, height_vec, flt_height_vec,
bld->static_state->pot_height, bld->static_state->pot_height,
bld->static_state->wrap_t); bld->static_state->wrap_t);
lp_build_name(y, "tex.y.wrapped"); lp_build_name(y, "tex.y.wrapped");
if (dims == 3) { if (dims == 3) {
z = lp_build_sample_wrap_nearest(bld, r, depth_vec, z = lp_build_sample_wrap_nearest(bld, r, depth_vec, flt_depth_vec,
bld->static_state->pot_depth, bld->static_state->pot_depth,
bld->static_state->wrap_r); bld->static_state->wrap_r);
lp_build_name(z, "tex.z.wrapped"); lp_build_name(z, "tex.z.wrapped");
@ -617,9 +633,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
static void static void
lp_build_sample_image_linear(struct lp_build_sample_context *bld, lp_build_sample_image_linear(struct lp_build_sample_context *bld,
unsigned unit, unsigned unit,
LLVMValueRef width_vec, LLVMValueRef size,
LLVMValueRef height_vec,
LLVMValueRef depth_vec,
LLVMValueRef row_stride_vec, LLVMValueRef row_stride_vec,
LLVMValueRef img_stride_vec, LLVMValueRef img_stride_vec,
LLVMValueRef data_ptr, LLVMValueRef data_ptr,
@ -629,15 +643,36 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
LLVMValueRef colors_out[4]) LLVMValueRef colors_out[4])
{ {
const unsigned dims = bld->dims; const unsigned dims = bld->dims;
LLVMValueRef width_vec;
LLVMValueRef height_vec;
LLVMValueRef depth_vec;
LLVMValueRef flt_size;
LLVMValueRef flt_width_vec;
LLVMValueRef flt_height_vec;
LLVMValueRef flt_depth_vec;
LLVMValueRef x0, y0, z0, x1, y1, z1; LLVMValueRef x0, y0, z0, x1, y1, z1;
LLVMValueRef s_fpart, t_fpart, r_fpart; LLVMValueRef s_fpart, t_fpart, r_fpart;
LLVMValueRef neighbors[2][2][4]; LLVMValueRef neighbors[2][2][4];
int chan; int chan;
lp_build_extract_image_sizes(bld,
bld->int_size_type,
bld->int_coord_type,
size,
&width_vec, &height_vec, &depth_vec);
flt_size = lp_build_int_to_float(&bld->float_size_bld, size);
lp_build_extract_image_sizes(bld,
bld->float_size_type,
bld->coord_type,
flt_size,
&flt_width_vec, &flt_height_vec, &flt_depth_vec);
/* /*
* Compute integer texcoords. * Compute integer texcoords.
*/ */
lp_build_sample_wrap_linear(bld, s, width_vec, lp_build_sample_wrap_linear(bld, s, width_vec, flt_width_vec,
bld->static_state->pot_width, bld->static_state->pot_width,
bld->static_state->wrap_s, bld->static_state->wrap_s,
&x0, &x1, &s_fpart); &x0, &x1, &s_fpart);
@ -645,7 +680,7 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
lp_build_name(x1, "tex.x1.wrapped"); lp_build_name(x1, "tex.x1.wrapped");
if (dims >= 2) { if (dims >= 2) {
lp_build_sample_wrap_linear(bld, t, height_vec, lp_build_sample_wrap_linear(bld, t, height_vec, flt_height_vec,
bld->static_state->pot_height, bld->static_state->pot_height,
bld->static_state->wrap_t, bld->static_state->wrap_t,
&y0, &y1, &t_fpart); &y0, &y1, &t_fpart);
@ -653,7 +688,7 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
lp_build_name(y1, "tex.y1.wrapped"); lp_build_name(y1, "tex.y1.wrapped");
if (dims == 3) { if (dims == 3) {
lp_build_sample_wrap_linear(bld, r, depth_vec, lp_build_sample_wrap_linear(bld, r, depth_vec, flt_depth_vec,
bld->static_state->pot_depth, bld->static_state->pot_depth,
bld->static_state->wrap_r, bld->static_state->wrap_r,
&z0, &z1, &r_fpart); &z0, &z1, &r_fpart);
@ -796,12 +831,8 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
LLVMValueRef *colors_out) LLVMValueRef *colors_out)
{ {
LLVMBuilderRef builder = bld->builder; LLVMBuilderRef builder = bld->builder;
LLVMValueRef width0_vec; LLVMValueRef size0;
LLVMValueRef width1_vec; LLVMValueRef size1;
LLVMValueRef height0_vec;
LLVMValueRef height1_vec;
LLVMValueRef depth0_vec;
LLVMValueRef depth1_vec;
LLVMValueRef row_stride0_vec; LLVMValueRef row_stride0_vec;
LLVMValueRef row_stride1_vec; LLVMValueRef row_stride1_vec;
LLVMValueRef img_stride0_vec; LLVMValueRef img_stride0_vec;
@ -813,12 +844,12 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
/* sample the first mipmap level */ /* sample the first mipmap level */
lp_build_mipmap_level_sizes(bld, ilevel0, lp_build_mipmap_level_sizes(bld, ilevel0,
&width0_vec, &height0_vec, &depth0_vec, &size0,
&row_stride0_vec, &img_stride0_vec); &row_stride0_vec, &img_stride0_vec);
data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0); data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
if (img_filter == PIPE_TEX_FILTER_NEAREST) { if (img_filter == PIPE_TEX_FILTER_NEAREST) {
lp_build_sample_image_nearest(bld, unit, lp_build_sample_image_nearest(bld, unit,
width0_vec, height0_vec, depth0_vec, size0,
row_stride0_vec, img_stride0_vec, row_stride0_vec, img_stride0_vec,
data_ptr0, s, t, r, data_ptr0, s, t, r,
colors0); colors0);
@ -826,7 +857,7 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
else { else {
assert(img_filter == PIPE_TEX_FILTER_LINEAR); assert(img_filter == PIPE_TEX_FILTER_LINEAR);
lp_build_sample_image_linear(bld, unit, lp_build_sample_image_linear(bld, unit,
width0_vec, height0_vec, depth0_vec, size0,
row_stride0_vec, img_stride0_vec, row_stride0_vec, img_stride0_vec,
data_ptr0, s, t, r, data_ptr0, s, t, r,
colors0); colors0);
@ -838,35 +869,32 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
} }
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
struct lp_build_flow_context *flow_ctx;
struct lp_build_if_state if_ctx; struct lp_build_if_state if_ctx;
LLVMValueRef need_lerp; LLVMValueRef need_lerp;
flow_ctx = lp_build_flow_create(builder);
/* need_lerp = lod_fpart > 0 */ /* need_lerp = lod_fpart > 0 */
need_lerp = LLVMBuildFCmp(builder, LLVMRealUGT, need_lerp = LLVMBuildFCmp(builder, LLVMRealUGT,
lod_fpart, lod_fpart,
bld->float_bld.zero, bld->float_bld.zero,
"need_lerp"); "need_lerp");
lp_build_if(&if_ctx, flow_ctx, builder, need_lerp); lp_build_if(&if_ctx, builder, need_lerp);
{ {
/* sample the second mipmap level */ /* sample the second mipmap level */
lp_build_mipmap_level_sizes(bld, ilevel1, lp_build_mipmap_level_sizes(bld, ilevel1,
&width1_vec, &height1_vec, &depth1_vec, &size1,
&row_stride1_vec, &img_stride1_vec); &row_stride1_vec, &img_stride1_vec);
data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1); data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
if (img_filter == PIPE_TEX_FILTER_NEAREST) { if (img_filter == PIPE_TEX_FILTER_NEAREST) {
lp_build_sample_image_nearest(bld, unit, lp_build_sample_image_nearest(bld, unit,
width1_vec, height1_vec, depth1_vec, size1,
row_stride1_vec, img_stride1_vec, row_stride1_vec, img_stride1_vec,
data_ptr1, s, t, r, data_ptr1, s, t, r,
colors1); colors1);
} }
else { else {
lp_build_sample_image_linear(bld, unit, lp_build_sample_image_linear(bld, unit,
width1_vec, height1_vec, depth1_vec, size1,
row_stride1_vec, img_stride1_vec, row_stride1_vec, img_stride1_vec,
data_ptr1, s, t, r, data_ptr1, s, t, r,
colors1); colors1);
@ -883,8 +911,6 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
} }
} }
lp_build_endif(&if_ctx); lp_build_endif(&if_ctx);
lp_build_flow_destroy(flow_ctx);
} }
} }
@ -937,12 +963,12 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
r = lp_build_broadcast_scalar(&bld->int_coord_bld, face); /* vec */ r = lp_build_broadcast_scalar(&bld->int_coord_bld, face); /* vec */
/* recompute ddx, ddy using the new (s,t) face texcoords */ /* recompute ddx, ddy using the new (s,t) face texcoords */
face_ddx[0] = lp_build_ddx(&bld->coord_bld, s); face_ddx[0] = lp_build_scalar_ddx(&bld->coord_bld, s);
face_ddx[1] = lp_build_ddx(&bld->coord_bld, t); face_ddx[1] = lp_build_scalar_ddx(&bld->coord_bld, t);
face_ddx[2] = NULL; face_ddx[2] = NULL;
face_ddx[3] = NULL; face_ddx[3] = NULL;
face_ddy[0] = lp_build_ddy(&bld->coord_bld, s); face_ddy[0] = lp_build_scalar_ddy(&bld->coord_bld, s);
face_ddy[1] = lp_build_ddy(&bld->coord_bld, t); face_ddy[1] = lp_build_scalar_ddy(&bld->coord_bld, t);
face_ddy[2] = NULL; face_ddy[2] = NULL;
face_ddy[3] = NULL; face_ddy[3] = NULL;
ddx = face_ddx; ddx = face_ddx;
@ -1020,17 +1046,14 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
/* Emit conditional to choose min image filter or mag image filter /* Emit conditional to choose min image filter or mag image filter
* depending on the lod being > 0 or <= 0, respectively. * depending on the lod being > 0 or <= 0, respectively.
*/ */
struct lp_build_flow_context *flow_ctx;
struct lp_build_if_state if_ctx; struct lp_build_if_state if_ctx;
LLVMValueRef minify; LLVMValueRef minify;
flow_ctx = lp_build_flow_create(builder);
/* minify = lod >= 0.0 */ /* minify = lod >= 0.0 */
minify = LLVMBuildICmp(builder, LLVMIntSGE, minify = LLVMBuildICmp(builder, LLVMIntSGE,
lod_ipart, int_bld->zero, ""); lod_ipart, int_bld->zero, "");
lp_build_if(&if_ctx, flow_ctx, builder, minify); lp_build_if(&if_ctx, builder, minify);
{ {
/* Use the minification filter */ /* Use the minification filter */
lp_build_sample_mipmap(bld, unit, lp_build_sample_mipmap(bld, unit,
@ -1049,8 +1072,6 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
texels); texels);
} }
lp_build_endif(&if_ctx); lp_build_endif(&if_ctx);
lp_build_flow_destroy(flow_ctx);
} }
for (chan = 0; chan < 4; ++chan) { for (chan = 0; chan < 4; ++chan) {
@ -1166,7 +1187,6 @@ lp_build_sample_soa(LLVMBuilderRef builder,
bld.float_type = lp_type_float(32); bld.float_type = lp_type_float(32);
bld.int_type = lp_type_int(32); bld.int_type = lp_type_int(32);
bld.coord_type = type; bld.coord_type = type;
bld.uint_coord_type = lp_uint_type(type);
bld.int_coord_type = lp_int_type(type); bld.int_coord_type = lp_int_type(type);
bld.float_size_type = lp_type_float(32); bld.float_size_type = lp_type_float(32);
bld.float_size_type.length = dims > 1 ? 4 : 1; bld.float_size_type.length = dims > 1 ? 4 : 1;
@ -1179,7 +1199,6 @@ lp_build_sample_soa(LLVMBuilderRef builder,
lp_build_context_init(&bld.float_vec_bld, builder, float_vec_type); lp_build_context_init(&bld.float_vec_bld, builder, float_vec_type);
lp_build_context_init(&bld.int_bld, builder, bld.int_type); lp_build_context_init(&bld.int_bld, builder, bld.int_type);
lp_build_context_init(&bld.coord_bld, builder, bld.coord_type); lp_build_context_init(&bld.coord_bld, builder, bld.coord_type);
lp_build_context_init(&bld.uint_coord_bld, builder, bld.uint_coord_type);
lp_build_context_init(&bld.int_coord_bld, builder, bld.int_coord_type); lp_build_context_init(&bld.int_coord_bld, builder, bld.int_coord_type);
lp_build_context_init(&bld.int_size_bld, builder, bld.int_size_type); lp_build_context_init(&bld.int_size_bld, builder, bld.int_size_type);
lp_build_context_init(&bld.float_size_bld, builder, bld.float_size_type); lp_build_context_init(&bld.float_size_bld, builder, bld.float_size_type);

View file

@ -36,6 +36,9 @@
#define LP_BLD_TGSI_H #define LP_BLD_TGSI_H
#include "gallivm/lp_bld.h" #include "gallivm/lp_bld.h"
#include "pipe/p_compiler.h"
#include "pipe/p_state.h"
#include "tgsi/tgsi_scan.h"
struct tgsi_token; struct tgsi_token;
@ -54,6 +57,75 @@ enum lp_build_tex_modifier {
}; };
/**
* Describe a channel of a register.
*
* The value can be a:
* - immediate value (i.e. derived from a IMM register)
* - CONST[n].x/y/z/w
* - IN[n].x/y/z/w
* - undetermined (when .file == TGSI_FILE_NULL)
*
* This is one of the analysis results, and is used to described
* the output color in terms of inputs.
*/
struct lp_tgsi_channel_info
{
unsigned file:4; /* TGSI_FILE_* */
unsigned swizzle:3; /* PIPE_SWIZZLE_x */
union {
uint32_t index;
float value; /* for TGSI_FILE_IMMEDIATE */
} u;
};
/**
* Describe a texture sampler interpolator.
*
* The interpolation is described in terms of regular inputs.
*/
struct lp_tgsi_texture_info
{
struct lp_tgsi_channel_info coord[4];
unsigned target:8; /* TGSI_TEXTURE_* */
unsigned unit:8; /* Sampler unit */
unsigned modifier:8; /* LP_BLD_TEX_MODIFIER_* */
};
struct lp_tgsi_info
{
struct tgsi_shader_info base;
/*
* Whether any of the texture opcodes access a register file other than
* TGSI_FILE_INPUT.
*
* We could also handle TGSI_FILE_CONST/IMMEDIATE here, but there is little
* benefit.
*/
unsigned indirect_textures:1;
/*
* Texture opcode description. Aimed at detecting and described direct
* texture opcodes.
*/
unsigned num_texs;
struct lp_tgsi_texture_info tex[PIPE_MAX_SAMPLERS];
/*
* Output description. Aimed at detecting and describing simple blit
* shaders.
*/
struct lp_tgsi_channel_info output[PIPE_MAX_SHADER_OUTPUTS][4];
/*
* Shortcut pointers into the above (for fragment shaders).
*/
const struct lp_tgsi_channel_info *cbuf[PIPE_MAX_COLOR_BUFS];
};
/** /**
* Sampler code generation interface. * Sampler code generation interface.
* *
@ -96,6 +168,11 @@ struct lp_build_sampler_aos
}; };
void
lp_build_tgsi_info(const struct tgsi_token *tokens,
struct lp_tgsi_info *info);
void void
lp_build_tgsi_soa(LLVMBuilderRef builder, lp_build_tgsi_soa(LLVMBuilderRef builder,
const struct tgsi_token *tokens, const struct tgsi_token *tokens,

View file

@ -513,7 +513,7 @@ emit_instruction(
{ {
LLVMValueRef src0, src1, src2; LLVMValueRef src0, src1, src2;
LLVMValueRef tmp0, tmp1; LLVMValueRef tmp0, tmp1;
LLVMValueRef dst0; LLVMValueRef dst0 = NULL;
/* /*
* Stores and write masks are handled in a general fashion after the long * Stores and write masks are handled in a general fashion after the long

View file

@ -0,0 +1,479 @@
/**************************************************************************
*
* 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 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.
*
**************************************************************************/
#include "util/u_memory.h"
#include "util/u_math.h"
#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_util.h"
#include "tgsi/tgsi_dump.h"
#include "lp_bld_debug.h"
#include "lp_bld_tgsi.h"
/**
* Analysis context.
*
* This is where we keep store the value of each channel of the IMM/TEMP/OUT
* register values, as we walk the shader.
*/
struct analysis_context
{
struct lp_tgsi_info *info;
unsigned num_imms;
float imm[32][4];
struct lp_tgsi_channel_info temp[32][4];
};
/**
* Describe the specified channel of the src register.
*/
static void
analyse_src(struct analysis_context *ctx,
struct lp_tgsi_channel_info *chan_info,
const struct tgsi_src_register *src,
unsigned chan)
{
chan_info->file = TGSI_FILE_NULL;
if (!src->Indirect && !src->Absolute && !src->Negate) {
unsigned swizzle = tgsi_util_get_src_register_swizzle(src, chan);
if (src->File == TGSI_FILE_TEMPORARY) {
if (src->Index < Elements(ctx->temp)) {
*chan_info = ctx->temp[src->Index][swizzle];
}
} else {
chan_info->file = src->File;
if (src->File == TGSI_FILE_IMMEDIATE) {
assert(src->Index < Elements(ctx->imm));
if (src->Index < Elements(ctx->imm)) {
chan_info->u.value = ctx->imm[src->Index][swizzle];
}
} else {
chan_info->u.index = src->Index;
chan_info->swizzle = swizzle;
}
}
}
}
/**
* Whether this register channel refers to a specific immediate value.
*/
static boolean
is_immediate(const struct lp_tgsi_channel_info *chan_info, float value)
{
return chan_info->file == TGSI_FILE_IMMEDIATE &&
chan_info->u.value == value;
}
static void
analyse_tex(struct analysis_context *ctx,
const struct tgsi_full_instruction *inst,
enum lp_build_tex_modifier modifier)
{
struct lp_tgsi_info *info = ctx->info;
unsigned chan;
if (info->num_texs < Elements(info->tex)) {
struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
bool indirect = FALSE;
unsigned readmask = 0;
tex_info->target = inst->Texture.Texture;
switch (inst->Texture.Texture) {
case TGSI_TEXTURE_1D:
readmask = TGSI_WRITEMASK_X;
break;
case TGSI_TEXTURE_2D:
case TGSI_TEXTURE_RECT:
readmask = TGSI_WRITEMASK_XY;
break;
case TGSI_TEXTURE_SHADOW1D:
case TGSI_TEXTURE_SHADOW2D:
case TGSI_TEXTURE_SHADOWRECT:
case TGSI_TEXTURE_3D:
case TGSI_TEXTURE_CUBE:
readmask = TGSI_WRITEMASK_XYZ;
break;
default:
assert(0);
return;
}
if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
/* We don't track explicit derivatives, although we could */
indirect = TRUE;
tex_info->unit = inst->Src[3].Register.Index;
} else {
if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED ||
modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
readmask |= TGSI_WRITEMASK_W;
}
tex_info->unit = inst->Src[1].Register.Index;
}
for (chan = 0; chan < 4; ++chan) {
struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
if (readmask & (1 << chan)) {
analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
if (chan_info->file != TGSI_FILE_INPUT) {
indirect = TRUE;
}
} else {
memset(chan_info, 0, sizeof *chan_info);
}
}
if (indirect) {
info->indirect_textures = TRUE;
}
++info->num_texs;
} else {
info->indirect_textures = TRUE;
}
}
/**
* Process an instruction, and update the register values accordingly.
*/
static void
analyse_instruction(struct analysis_context *ctx,
struct tgsi_full_instruction *inst)
{
struct lp_tgsi_info *info = ctx->info;
struct lp_tgsi_channel_info (*regs)[4];
unsigned max_regs;
unsigned i;
unsigned index;
unsigned chan;
for (i = 0; i < inst->Instruction.NumDstRegs; ++i) {
const struct tgsi_dst_register *dst = &inst->Dst[i].Register;
/*
* Get the lp_tgsi_channel_info array corresponding to the destination
* register file.
*/
if (dst->File == TGSI_FILE_TEMPORARY) {
regs = ctx->temp;
max_regs = Elements(ctx->temp);
} else if (dst->File == TGSI_FILE_OUTPUT) {
regs = info->output;
max_regs = Elements(info->output);
} else if (dst->File == TGSI_FILE_ADDRESS ||
dst->File == TGSI_FILE_PREDICATE) {
continue;
} else {
assert(0);
continue;
}
/*
* Detect direct TEX instructions
*/
switch (inst->Instruction.Opcode) {
case TGSI_OPCODE_TEX:
analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
break;
case TGSI_OPCODE_TXD:
analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV);
break;
case TGSI_OPCODE_TXB:
analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
break;
case TGSI_OPCODE_TXL:
analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
break;
case TGSI_OPCODE_TXP:
analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
break;
default:
break;
}
/*
* Keep track of assignments and writes
*/
if (dst->Indirect) {
/*
* It could be any register index so clear all register indices.
*/
for (chan = 0; chan < 4; ++chan) {
if (dst->WriteMask & (1 << chan)) {
for (index = 0; index < max_regs; ++index) {
regs[index][chan].file = TGSI_FILE_NULL;
}
}
}
} else if (dst->Index < max_regs) {
/*
* Update this destination register value.
*/
struct lp_tgsi_channel_info res[4];
memset(res, 0, sizeof res);
if (!inst->Instruction.Predicate &&
!inst->Instruction.Saturate) {
for (chan = 0; chan < 4; ++chan) {
if (dst->WriteMask & (1 << chan)) {
if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) {
analyse_src(ctx, &res[chan],
&inst->Src[0].Register, chan);
} else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) {
/*
* Propagate values across 1.0 and 0.0 multiplications.
*/
struct lp_tgsi_channel_info src0;
struct lp_tgsi_channel_info src1;
analyse_src(ctx, &src0, &inst->Src[0].Register, chan);
analyse_src(ctx, &src1, &inst->Src[1].Register, chan);
if (is_immediate(&src0, 0.0f)) {
res[chan] = src0;
} else if (is_immediate(&src1, 0.0f)) {
res[chan] = src1;
} else if (is_immediate(&src0, 1.0f)) {
res[chan] = src1;
} else if (is_immediate(&src1, 1.0f)) {
res[chan] = src0;
}
}
}
}
}
for (chan = 0; chan < 4; ++chan) {
if (dst->WriteMask & (1 << chan)) {
regs[dst->Index][chan] = res[chan];
}
}
}
}
/*
* Clear all temporaries information in presence of a control flow opcode.
*/
switch (inst->Instruction.Opcode) {
case TGSI_OPCODE_IF:
case TGSI_OPCODE_IFC:
case TGSI_OPCODE_ELSE:
case TGSI_OPCODE_ENDIF:
case TGSI_OPCODE_BGNLOOP:
case TGSI_OPCODE_BRK:
case TGSI_OPCODE_BREAKC:
case TGSI_OPCODE_CONT:
case TGSI_OPCODE_ENDLOOP:
case TGSI_OPCODE_CALLNZ:
case TGSI_OPCODE_CAL:
case TGSI_OPCODE_BGNSUB:
case TGSI_OPCODE_ENDSUB:
case TGSI_OPCODE_SWITCH:
case TGSI_OPCODE_CASE:
case TGSI_OPCODE_DEFAULT:
case TGSI_OPCODE_ENDSWITCH:
case TGSI_OPCODE_RET:
case TGSI_OPCODE_END:
/* XXX: Are there more cases? */
memset(&ctx->temp, 0, sizeof ctx->temp);
memset(&info->output, 0, sizeof info->output);
default:
break;
}
}
static INLINE void
dump_info(const struct tgsi_token *tokens,
struct lp_tgsi_info *info)
{
unsigned index;
unsigned chan;
tgsi_dump(tokens, 0);
for (index = 0; index < info->num_texs; ++index) {
const struct lp_tgsi_texture_info *tex_info = &info->tex[index];
debug_printf("TEX[%u] =", index);
for (chan = 0; chan < 4; ++chan) {
const struct lp_tgsi_channel_info *chan_info =
&tex_info->coord[chan];
if (chan_info->file != TGSI_FILE_NULL) {
debug_printf(" %s[%u].%c",
tgsi_file_names[chan_info->file],
chan_info->u.index,
"xyzw01"[chan_info->swizzle]);
} else {
debug_printf(" _");
}
}
debug_printf(", SAMP[%u], %s\n",
tex_info->unit,
tgsi_texture_names[tex_info->target]);
}
for (index = 0; index < PIPE_MAX_SHADER_OUTPUTS; ++index) {
for (chan = 0; chan < 4; ++chan) {
const struct lp_tgsi_channel_info *chan_info =
&info->output[index][chan];
if (chan_info->file != TGSI_FILE_NULL) {
debug_printf("OUT[%u].%c = ", index, "xyzw"[chan]);
if (chan_info->file == TGSI_FILE_IMMEDIATE) {
debug_printf("%f", chan_info->u.value);
} else {
const char *file_name;
switch (chan_info->file) {
case TGSI_FILE_CONSTANT:
file_name = "CONST";
break;
case TGSI_FILE_INPUT:
file_name = "IN";
break;
default:
file_name = "???";
break;
}
debug_printf("%s[%u].%c",
file_name,
chan_info->u.index,
"xyzw01"[chan_info->swizzle]);
}
debug_printf("\n");
}
}
}
}
/**
* Detect any direct relationship between the output color
*/
void
lp_build_tgsi_info(const struct tgsi_token *tokens,
struct lp_tgsi_info *info)
{
struct tgsi_parse_context parse;
struct analysis_context ctx;
unsigned index;
unsigned chan;
memset(info, 0, sizeof *info);
tgsi_scan_shader(tokens, &info->base);
memset(&ctx, 0, sizeof ctx);
ctx.info = info;
tgsi_parse_init(&parse, tokens);
while (!tgsi_parse_end_of_tokens(&parse)) {
tgsi_parse_token(&parse);
switch (parse.FullToken.Token.Type) {
case TGSI_TOKEN_TYPE_DECLARATION:
break;
case TGSI_TOKEN_TYPE_INSTRUCTION:
{
struct tgsi_full_instruction *inst =
&parse.FullToken.FullInstruction;
if (inst->Instruction.Opcode == TGSI_OPCODE_END ||
inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) {
/* We reached the end of main function body. */
goto finished;
}
analyse_instruction(&ctx, inst);
}
break;
case TGSI_TOKEN_TYPE_IMMEDIATE:
{
const unsigned size =
parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
assert(size <= 4);
if (ctx.num_imms < Elements(ctx.imm)) {
for (chan = 0; chan < size; ++chan) {
ctx.imm[ctx.num_imms][chan] =
parse.FullToken.FullImmediate.u[chan].Float;
}
++ctx.num_imms;
}
}
break;
case TGSI_TOKEN_TYPE_PROPERTY:
break;
default:
assert(0);
}
}
finished:
tgsi_parse_free(&parse);
/*
* Link the output color values.
*/
for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) {
const struct lp_tgsi_channel_info null_output[4];
info->cbuf[index] = null_output;
}
for (index = 0; index < info->base.num_outputs; ++index) {
unsigned semantic_name = info->base.output_semantic_name[index];
unsigned semantic_index = info->base.output_semantic_index[index];
if (semantic_name == TGSI_SEMANTIC_COLOR &&
semantic_index < PIPE_MAX_COLOR_BUFS) {
info->cbuf[semantic_index] = info->output[index];
}
}
if (gallivm_debug & GALLIVM_DEBUG_TGSI) {
dump_info(tokens, info);
}
}

View file

@ -887,21 +887,25 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
} }
if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) { if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
LLVMTypeRef i32t = LLVMInt32Type();
LLVMValueRef index0 = LLVMConstInt(i32t, 0, 0);
for (i = 0; i < num_coords; i++) { for (i = 0; i < num_coords; i++) {
ddx[i] = emit_fetch( bld, inst, 1, i ); LLVMValueRef src1 = emit_fetch( bld, inst, 1, i );
ddy[i] = emit_fetch( bld, inst, 2, i ); LLVMValueRef src2 = emit_fetch( bld, inst, 2, i );
ddx[i] = LLVMBuildExtractElement(bld->base.builder, src1, index0, "");
ddy[i] = LLVMBuildExtractElement(bld->base.builder, src2, index0, "");
} }
unit = inst->Src[3].Register.Index; unit = inst->Src[3].Register.Index;
} else { } else {
for (i = 0; i < num_coords; i++) { for (i = 0; i < num_coords; i++) {
ddx[i] = lp_build_ddx( &bld->base, coords[i] ); ddx[i] = lp_build_scalar_ddx( &bld->base, coords[i] );
ddy[i] = lp_build_ddy( &bld->base, coords[i] ); ddy[i] = lp_build_scalar_ddy( &bld->base, coords[i] );
} }
unit = inst->Src[1].Register.Index; unit = inst->Src[1].Register.Index;
} }
for (i = num_coords; i < 3; i++) { for (i = num_coords; i < 3; i++) {
ddx[i] = bld->base.undef; ddx[i] = LLVMGetUndef(bld->base.elem_type);
ddy[i] = bld->base.undef; ddy[i] = LLVMGetUndef(bld->base.elem_type);
} }
bld->sampler->emit_fetch_texel(bld->sampler, bld->sampler->emit_fetch_texel(bld->sampler,
@ -913,6 +917,43 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
texel); texel);
} }
static boolean
near_end_of_shader(struct lp_build_tgsi_soa_context *bld,
int pc)
{
int i;
for (i = 0; i < 5; i++) {
unsigned opcode;
if (pc + i >= bld->info->num_instructions)
return TRUE;
opcode = bld->instructions[pc + i].Instruction.Opcode;
if (opcode == TGSI_OPCODE_END)
return TRUE;
if (opcode == TGSI_OPCODE_TEX ||
opcode == TGSI_OPCODE_TXP ||
opcode == TGSI_OPCODE_TXD ||
opcode == TGSI_OPCODE_TXB ||
opcode == TGSI_OPCODE_TXL ||
opcode == TGSI_OPCODE_TXF ||
opcode == TGSI_OPCODE_TXQ ||
opcode == TGSI_OPCODE_CAL ||
opcode == TGSI_OPCODE_CALLNZ ||
opcode == TGSI_OPCODE_IF ||
opcode == TGSI_OPCODE_IFC ||
opcode == TGSI_OPCODE_BGNLOOP ||
opcode == TGSI_OPCODE_SWITCH)
return FALSE;
}
return TRUE;
}
/** /**
* Kill fragment if any of the src register values are negative. * Kill fragment if any of the src register values are negative.
@ -920,7 +961,8 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
static void static void
emit_kil( emit_kil(
struct lp_build_tgsi_soa_context *bld, struct lp_build_tgsi_soa_context *bld,
const struct tgsi_full_instruction *inst ) const struct tgsi_full_instruction *inst,
int pc)
{ {
const struct tgsi_full_src_register *reg = &inst->Src[0]; const struct tgsi_full_src_register *reg = &inst->Src[0];
LLVMValueRef terms[NUM_CHANNELS]; LLVMValueRef terms[NUM_CHANNELS];
@ -959,8 +1001,12 @@ emit_kil(
} }
} }
if(mask) if(mask) {
lp_build_mask_update(bld->mask, mask); lp_build_mask_update(bld->mask, mask);
if (!near_end_of_shader(bld, pc))
lp_build_mask_check(bld->mask);
}
} }
@ -972,7 +1018,8 @@ emit_kil(
*/ */
static void static void
emit_kilp(struct lp_build_tgsi_soa_context *bld, emit_kilp(struct lp_build_tgsi_soa_context *bld,
const struct tgsi_full_instruction *inst) const struct tgsi_full_instruction *inst,
int pc)
{ {
LLVMValueRef mask; LLVMValueRef mask;
@ -983,10 +1030,14 @@ emit_kilp(struct lp_build_tgsi_soa_context *bld,
mask = LLVMBuildNot(bld->base.builder, bld->exec_mask.exec_mask, "kilp"); mask = LLVMBuildNot(bld->base.builder, bld->exec_mask.exec_mask, "kilp");
} }
else { else {
mask = bld->base.zero; LLVMValueRef zero = LLVMConstNull(bld->base.int_vec_type);
mask = zero;
} }
lp_build_mask_update(bld->mask, mask); lp_build_mask_update(bld->mask, mask);
if (!near_end_of_shader(bld, pc))
lp_build_mask_check(bld->mask);
} }
static void static void
@ -1535,12 +1586,12 @@ emit_instruction(
case TGSI_OPCODE_KILP: case TGSI_OPCODE_KILP:
/* predicated kill */ /* predicated kill */
emit_kilp( bld, inst ); emit_kilp( bld, inst, (*pc)-1 );
break; break;
case TGSI_OPCODE_KIL: case TGSI_OPCODE_KIL:
/* conditional kill */ /* conditional kill */
emit_kil( bld, inst ); emit_kil( bld, inst, (*pc)-1 );
break; break;
case TGSI_OPCODE_PK2H: case TGSI_OPCODE_PK2H:

View file

@ -97,7 +97,7 @@ void (*ppc_get_func(struct ppc_function *p))(void)
return (void (*)(void)) NULL; return (void (*)(void)) NULL;
else else
#endif #endif
return (void (*)(void)) p->store; return (void (*)(void)) pointer_to_func(p->store);
} }

View file

@ -23,25 +23,12 @@
#include "cell/ppu/cell_public.h" #include "cell/ppu/cell_public.h"
#endif #endif
static INLINE struct pipe_screen * static INLINE struct pipe_screen *
sw_screen_create(struct sw_winsys *winsys) sw_screen_create_named(struct sw_winsys *winsys, const char *driver)
{ {
const char *default_driver;
const char *driver;
struct pipe_screen *screen = NULL; struct pipe_screen *screen = NULL;
#if defined(GALLIUM_CELL)
default_driver = "cell";
#elif defined(GALLIUM_LLVMPIPE)
default_driver = "llvmpipe";
#elif defined(GALLIUM_SOFTPIPE)
default_driver = "softpipe";
#else
default_driver = "";
#endif
driver = debug_get_option("GALLIUM_DRIVER", default_driver);
#if defined(GALLIUM_CELL) #if defined(GALLIUM_CELL)
if (screen == NULL && strcmp(driver, "cell") == 0) if (screen == NULL && strcmp(driver, "cell") == 0)
screen = cell_create_screen(winsys); screen = cell_create_screen(winsys);
@ -60,4 +47,26 @@ sw_screen_create(struct sw_winsys *winsys)
return screen; return screen;
} }
static INLINE struct pipe_screen *
sw_screen_create(struct sw_winsys *winsys)
{
const char *default_driver;
const char *driver;
#if defined(GALLIUM_CELL)
default_driver = "cell";
#elif defined(GALLIUM_LLVMPIPE)
default_driver = "llvmpipe";
#elif defined(GALLIUM_SOFTPIPE)
default_driver = "softpipe";
#else
default_driver = "";
#endif
driver = debug_get_option("GALLIUM_DRIVER", default_driver);
return sw_screen_create_named(winsys, driver);
}
#endif #endif

View file

@ -13,20 +13,26 @@ static INLINE struct pipe_screen *
sw_screen_wrap(struct pipe_screen *screen) sw_screen_wrap(struct pipe_screen *screen)
{ {
struct sw_winsys *sws; struct sw_winsys *sws;
struct pipe_screen *sw_screen; struct pipe_screen *sw_screen = NULL;
const char *driver;
sws = wrapper_sw_winsys_warp_pipe_screen(screen); driver = debug_get_option("GALLIUM_DRIVER", "native");
if (strcmp(driver, "native") == 0)
return screen;
sws = wrapper_sw_winsys_wrap_pipe_screen(screen);
if (!sws) if (!sws)
goto err; goto err;
sw_screen = sw_screen_create(sws); sw_screen = sw_screen_create_named(sws, driver);
if (sw_screen == screen)
if (!sw_screen)
goto err_winsys; goto err_winsys;
return sw_screen; return sw_screen;
err_winsys: err_winsys:
sws->destroy(sws); return wrapper_sw_winsys_dewrap_pipe_screen(sws);
err: err:
return screen; return screen;
} }

View file

@ -90,7 +90,8 @@ static const char *processor_type_names[] =
"GEOM" "GEOM"
}; };
static const char *file_names[TGSI_FILE_COUNT] = const char *
tgsi_file_names[TGSI_FILE_COUNT] =
{ {
"NULL", "NULL",
"CONST", "CONST",
@ -125,7 +126,8 @@ static const char *semantic_names[] =
"FACE", "FACE",
"EDGEFLAG", "EDGEFLAG",
"PRIM_ID", "PRIM_ID",
"INSTANCEID" "INSTANCEID",
"STENCIL"
}; };
static const char *immediate_type_names[] = static const char *immediate_type_names[] =
@ -135,7 +137,8 @@ static const char *immediate_type_names[] =
"INT32" "INT32"
}; };
static const char *swizzle_names[] = const char *
tgsi_swizzle_names[] =
{ {
"x", "x",
"y", "y",
@ -143,7 +146,8 @@ static const char *swizzle_names[] =
"w" "w"
}; };
static const char *texture_names[] = const char *
tgsi_texture_names[] =
{ {
"UNKNOWN", "UNKNOWN",
"1D", "1D",
@ -201,15 +205,15 @@ _dump_register_src(
struct dump_ctx *ctx, struct dump_ctx *ctx,
const struct tgsi_full_src_register *src ) const struct tgsi_full_src_register *src )
{ {
ENM(src->Register.File, file_names); ENM(src->Register.File, tgsi_file_names);
if (src->Register.Dimension) { if (src->Register.Dimension) {
if (src->Dimension.Indirect) { if (src->Dimension.Indirect) {
CHR( '[' ); CHR( '[' );
ENM( src->DimIndirect.File, file_names ); ENM( src->DimIndirect.File, tgsi_file_names );
CHR( '[' ); CHR( '[' );
SID( src->DimIndirect.Index ); SID( src->DimIndirect.Index );
TXT( "]." ); TXT( "]." );
ENM( src->DimIndirect.SwizzleX, swizzle_names ); ENM( src->DimIndirect.SwizzleX, tgsi_swizzle_names );
if (src->Dimension.Index != 0) { if (src->Dimension.Index != 0) {
if (src->Dimension.Index > 0) if (src->Dimension.Index > 0)
CHR( '+' ); CHR( '+' );
@ -224,11 +228,11 @@ _dump_register_src(
} }
if (src->Register.Indirect) { if (src->Register.Indirect) {
CHR( '[' ); CHR( '[' );
ENM( src->Indirect.File, file_names ); ENM( src->Indirect.File, tgsi_file_names );
CHR( '[' ); CHR( '[' );
SID( src->Indirect.Index ); SID( src->Indirect.Index );
TXT( "]." ); TXT( "]." );
ENM( src->Indirect.SwizzleX, swizzle_names ); ENM( src->Indirect.SwizzleX, tgsi_swizzle_names );
if (src->Register.Index != 0) { if (src->Register.Index != 0) {
if (src->Register.Index > 0) if (src->Register.Index > 0)
CHR( '+' ); CHR( '+' );
@ -248,15 +252,15 @@ _dump_register_dst(
struct dump_ctx *ctx, struct dump_ctx *ctx,
const struct tgsi_full_dst_register *dst ) const struct tgsi_full_dst_register *dst )
{ {
ENM(dst->Register.File, file_names); ENM(dst->Register.File, tgsi_file_names);
if (dst->Register.Dimension) { if (dst->Register.Dimension) {
if (dst->Dimension.Indirect) { if (dst->Dimension.Indirect) {
CHR( '[' ); CHR( '[' );
ENM( dst->DimIndirect.File, file_names ); ENM( dst->DimIndirect.File, tgsi_file_names );
CHR( '[' ); CHR( '[' );
SID( dst->DimIndirect.Index ); SID( dst->DimIndirect.Index );
TXT( "]." ); TXT( "]." );
ENM( dst->DimIndirect.SwizzleX, swizzle_names ); ENM( dst->DimIndirect.SwizzleX, tgsi_swizzle_names );
if (dst->Dimension.Index != 0) { if (dst->Dimension.Index != 0) {
if (dst->Dimension.Index > 0) if (dst->Dimension.Index > 0)
CHR( '+' ); CHR( '+' );
@ -271,11 +275,11 @@ _dump_register_dst(
} }
if (dst->Register.Indirect) { if (dst->Register.Indirect) {
CHR( '[' ); CHR( '[' );
ENM( dst->Indirect.File, file_names ); ENM( dst->Indirect.File, tgsi_file_names );
CHR( '[' ); CHR( '[' );
SID( dst->Indirect.Index ); SID( dst->Indirect.Index );
TXT( "]." ); TXT( "]." );
ENM( dst->Indirect.SwizzleX, swizzle_names ); ENM( dst->Indirect.SwizzleX, tgsi_swizzle_names );
if (dst->Register.Index != 0) { if (dst->Register.Index != 0) {
if (dst->Register.Index > 0) if (dst->Register.Index > 0)
CHR( '+' ); CHR( '+' );
@ -351,7 +355,7 @@ iter_declaration(
TXT( "DCL " ); TXT( "DCL " );
ENM(decl->Declaration.File, file_names); ENM(decl->Declaration.File, tgsi_file_names);
/* all geometry shader inputs are two dimensional */ /* all geometry shader inputs are two dimensional */
if (decl->Declaration.File == TGSI_FILE_INPUT && if (decl->Declaration.File == TGSI_FILE_INPUT &&
@ -585,10 +589,10 @@ iter_instruction(
inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z || inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) { inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
CHR( '.' ); CHR( '.' );
ENM( inst->Predicate.SwizzleX, swizzle_names ); ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names );
ENM( inst->Predicate.SwizzleY, swizzle_names ); ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names );
ENM( inst->Predicate.SwizzleZ, swizzle_names ); ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names );
ENM( inst->Predicate.SwizzleW, swizzle_names ); ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names );
} }
TXT( ") " ); TXT( ") " );
@ -641,10 +645,10 @@ iter_instruction(
src->Register.SwizzleZ != TGSI_SWIZZLE_Z || src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
src->Register.SwizzleW != TGSI_SWIZZLE_W) { src->Register.SwizzleW != TGSI_SWIZZLE_W) {
CHR( '.' ); CHR( '.' );
ENM( src->Register.SwizzleX, swizzle_names ); ENM( src->Register.SwizzleX, tgsi_swizzle_names );
ENM( src->Register.SwizzleY, swizzle_names ); ENM( src->Register.SwizzleY, tgsi_swizzle_names );
ENM( src->Register.SwizzleZ, swizzle_names ); ENM( src->Register.SwizzleZ, tgsi_swizzle_names );
ENM( src->Register.SwizzleW, swizzle_names ); ENM( src->Register.SwizzleW, tgsi_swizzle_names );
} }
if (src->Register.Absolute) if (src->Register.Absolute)
@ -655,7 +659,7 @@ iter_instruction(
if (inst->Instruction.Texture) { if (inst->Instruction.Texture) {
TXT( ", " ); TXT( ", " );
ENM( inst->Texture.Texture, texture_names ); ENM( inst->Texture.Texture, tgsi_texture_names );
} }
switch (inst->Instruction.Opcode) { switch (inst->Instruction.Opcode) {

View file

@ -35,6 +35,15 @@
extern "C" { extern "C" {
#endif #endif
extern const char *
tgsi_file_names[TGSI_FILE_COUNT];
extern const char *
tgsi_swizzle_names[];
extern const char *
tgsi_texture_names[];
void void
tgsi_dump_str( tgsi_dump_str(
const struct tgsi_token *tokens, const struct tgsi_token *tokens,

View file

@ -147,6 +147,7 @@ tgsi_scan_shader(const struct tgsi_token *tokens,
info->input_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name; info->input_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name;
info->input_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index; info->input_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index;
info->input_interpolate[reg] = (ubyte)fulldecl->Declaration.Interpolate; info->input_interpolate[reg] = (ubyte)fulldecl->Declaration.Interpolate;
info->input_centroid[reg] = (ubyte)fulldecl->Declaration.Centroid;
info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Declaration.CylindricalWrap; info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Declaration.CylindricalWrap;
info->num_inputs++; info->num_inputs++;
} }
@ -157,9 +158,11 @@ tgsi_scan_shader(const struct tgsi_token *tokens,
/* extra info for special outputs */ /* extra info for special outputs */
if (procType == TGSI_PROCESSOR_FRAGMENT && if (procType == TGSI_PROCESSOR_FRAGMENT &&
fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION) { fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION)
info->writes_z = TRUE; info->writes_z = TRUE;
} if (procType == TGSI_PROCESSOR_FRAGMENT &&
fulldecl->Semantic.Name == TGSI_SEMANTIC_STENCIL)
info->writes_stencil = TRUE;
if (procType == TGSI_PROCESSOR_VERTEX && if (procType == TGSI_PROCESSOR_VERTEX &&
fulldecl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG) { fulldecl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG) {
info->writes_edgeflag = TRUE; info->writes_edgeflag = TRUE;

View file

@ -45,6 +45,7 @@ struct tgsi_shader_info
ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; /**< TGSI_SEMANTIC_x */ ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; /**< TGSI_SEMANTIC_x */
ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS];
ubyte input_interpolate[PIPE_MAX_SHADER_INPUTS]; ubyte input_interpolate[PIPE_MAX_SHADER_INPUTS];
ubyte input_centroid[PIPE_MAX_SHADER_INPUTS];
ubyte input_usage_mask[PIPE_MAX_SHADER_INPUTS]; ubyte input_usage_mask[PIPE_MAX_SHADER_INPUTS];
ubyte input_cylindrical_wrap[PIPE_MAX_SHADER_INPUTS]; ubyte input_cylindrical_wrap[PIPE_MAX_SHADER_INPUTS];
ubyte output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; /**< TGSI_SEMANTIC_x */ ubyte output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; /**< TGSI_SEMANTIC_x */
@ -60,6 +61,7 @@ struct tgsi_shader_info
uint opcode_count[TGSI_OPCODE_LAST]; /**< opcode histogram */ uint opcode_count[TGSI_OPCODE_LAST]; /**< opcode histogram */
boolean writes_z; /**< does fragment shader write Z value? */ boolean writes_z; /**< does fragment shader write Z value? */
boolean writes_stencil; /**< does fragment shader write stencil value? */
boolean writes_edgeflag; /**< vertex shader outputs edgeflag */ boolean writes_edgeflag; /**< vertex shader outputs edgeflag */
boolean uses_kill; /**< KIL or KILP instruction used? */ boolean uses_kill; /**< KIL or KILP instruction used? */

View file

@ -68,6 +68,33 @@ struct translate_key {
}; };
struct translate;
typedef void (PIPE_CDECL *run_elts_func)(struct translate *,
const unsigned *elts,
unsigned count,
unsigned instance_id,
void *output_buffer);
typedef void (PIPE_CDECL *run_elts16_func)(struct translate *,
const uint16_t *elts,
unsigned count,
unsigned instance_id,
void *output_buffer);
typedef void (PIPE_CDECL *run_elts8_func)(struct translate *,
const uint8_t *elts,
unsigned count,
unsigned instance_id,
void *output_buffer);
typedef void (PIPE_CDECL *run_func)(struct translate *,
unsigned start,
unsigned count,
unsigned instance_id,
void *output_buffer);
struct translate { struct translate {
struct translate_key key; struct translate_key key;
@ -79,42 +106,14 @@ struct translate {
unsigned stride, unsigned stride,
unsigned max_index ); unsigned max_index );
void (PIPE_CDECL *run_elts)( struct translate *, run_elts_func run_elts;
const unsigned *elts, run_elts16_func run_elts16;
unsigned count, run_elts8_func run_elts8;
unsigned instance_id, run_func run;
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,
unsigned instance_id,
void *output_buffer);
}; };
#if 0
struct translate_context *translate_context_create( void );
void translate_context_destroy( struct translate_context * );
struct translate *translate_lookup_or_create( struct translate_context *tctx,
const struct translate_key *key );
#endif
struct translate *translate_create( const struct translate_key *key ); struct translate *translate_create( const struct translate_key *key );
boolean translate_is_output_format_supported(enum pipe_format format); boolean translate_is_output_format_supported(enum pipe_format format);

View file

@ -1495,19 +1495,19 @@ struct translate *translate_sse2_create( const struct translate_key *key )
if (!build_vertex_emit(p, &p->elt8_func, 1)) if (!build_vertex_emit(p, &p->elt8_func, 1))
goto fail; goto fail;
p->translate.run = (void*)x86_get_func(&p->linear_func); p->translate.run = (run_func) x86_get_func(&p->linear_func);
if (p->translate.run == NULL) if (p->translate.run == NULL)
goto fail; goto fail;
p->translate.run_elts = (void*)x86_get_func(&p->elt_func); p->translate.run_elts = (run_elts_func) x86_get_func(&p->elt_func);
if (p->translate.run_elts == NULL) if (p->translate.run_elts == NULL)
goto fail; goto fail;
p->translate.run_elts16 = (void*)x86_get_func(&p->elt16_func); p->translate.run_elts16 = (run_elts16_func) x86_get_func(&p->elt16_func);
if (p->translate.run_elts16 == NULL) if (p->translate.run_elts16 == NULL)
goto fail; goto fail;
p->translate.run_elts8 = (void*)x86_get_func(&p->elt8_func); p->translate.run_elts8 = (run_elts8_func) x86_get_func(&p->elt8_func);
if (p->translate.run_elts8 == NULL) if (p->translate.run_elts8 == NULL)
goto fail; goto fail;

View file

@ -38,6 +38,7 @@
#endif #endif
#include "u_dl.h" #include "u_dl.h"
#include "u_pointer.h"
struct util_dl_library * struct util_dl_library *
@ -58,7 +59,7 @@ util_dl_get_proc_address(struct util_dl_library *library,
const char *procname) const char *procname)
{ {
#if defined(PIPE_OS_UNIX) #if defined(PIPE_OS_UNIX)
return (util_dl_proc)dlsym((void *)library, procname); return (util_dl_proc) pointer_to_func(dlsym((void *)library, procname));
#elif defined(PIPE_OS_WINDOWS) #elif defined(PIPE_OS_WINDOWS)
return (util_dl_proc)GetProcAddress((HMODULE)library, procname); return (util_dl_proc)GetProcAddress((HMODULE)library, procname);
#else #else

View file

@ -109,9 +109,12 @@ PIPE_FORMAT_Z32_UNORM , plain, 1, 1, un32, , , , x___,
PIPE_FORMAT_Z32_FLOAT , plain, 1, 1, f32 , , , , x___, zs PIPE_FORMAT_Z32_FLOAT , plain, 1, 1, f32 , , , , x___, zs
PIPE_FORMAT_Z24_UNORM_S8_USCALED , plain, 1, 1, un24, u8 , , , xy__, zs PIPE_FORMAT_Z24_UNORM_S8_USCALED , plain, 1, 1, un24, u8 , , , xy__, zs
PIPE_FORMAT_S8_USCALED_Z24_UNORM , plain, 1, 1, u8 , un24, , , yx__, zs PIPE_FORMAT_S8_USCALED_Z24_UNORM , plain, 1, 1, u8 , un24, , , yx__, zs
PIPE_FORMAT_X24S8_USCALED , plain, 1, 1, x24, u8 , , , _y__, zs
PIPE_FORMAT_S8X24_USCALED , plain, 1, 1, u8 , x24 , , , _x__, zs
PIPE_FORMAT_Z24X8_UNORM , plain, 1, 1, un24, x8 , , , x___, zs PIPE_FORMAT_Z24X8_UNORM , plain, 1, 1, un24, x8 , , , x___, zs
PIPE_FORMAT_X8Z24_UNORM , plain, 1, 1, x8 , un24, , , y___, zs PIPE_FORMAT_X8Z24_UNORM , plain, 1, 1, x8 , un24, , , y___, zs
PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED , plain, 1, 1, f32, u8 , x24 , , xy__, zs PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED , plain, 1, 1, f32, u8 , x24 , , xy__, zs
PIPE_FORMAT_X32_S8X24_USCALED , plain, 1, 1, x32, u8 , x24 , , _y__, zs
# YUV formats # YUV formats
# http://www.fourcc.org/yuv.php#UYVY # http://www.fourcc.org/yuv.php#UYVY

Can't render this file because it contains an unexpected character in line 8 and column 3.

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
''' CopyRight = '''
/************************************************************************** /**************************************************************************
* *
* Copyright 2010 VMware, Inc. * Copyright 2010 VMware, Inc.
@ -89,7 +89,7 @@ def main():
print '/* This file is autogenerated by u_format_srgb.py. Do not edit directly. */' print '/* This file is autogenerated by u_format_srgb.py. Do not edit directly. */'
print print
# This will print the copyright message on the top of this file # This will print the copyright message on the top of this file
print __doc__.strip() print CopyRight.strip()
print print
print '#include "u_format_srgb.h"' print '#include "u_format_srgb.h"'
print print

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
''' CopyRight = '''
/************************************************************************** /**************************************************************************
* *
* Copyright 2010 VMware, Inc. * Copyright 2010 VMware, Inc.
@ -83,7 +83,7 @@ def write_format_table(formats):
print '/* This file is autogenerated by u_format_table.py from u_format.csv. Do not edit directly. */' print '/* This file is autogenerated by u_format_table.py from u_format.csv. Do not edit directly. */'
print print
# This will print the copyright message on the top of this file # This will print the copyright message on the top of this file
print __doc__.strip() print CopyRight.strip()
print print
print '#include "u_format.h"' print '#include "u_format.h"'
print '#include "u_format_s3tc.h"' print '#include "u_format_s3tc.h"'

View file

@ -918,3 +918,56 @@ util_format_z32_float_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned d
} }
} }
void
util_format_x24s8_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height)
{
util_format_z24_unorm_s8_uscaled_unpack_s_8uscaled(dst_row, dst_stride,
src_row, src_stride,
width, height);
}
void
util_format_x24s8_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height)
{
util_format_z24_unorm_s8_uscaled_pack_s_8uscaled(dst_row, dst_stride,
src_row, src_stride,
width, height);
}
void
util_format_s8x24_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height)
{
util_format_s8_uscaled_z24_unorm_unpack_s_8uscaled(dst_row, dst_stride,
src_row, src_stride,
width, height);
}
void
util_format_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height)
{
util_format_s8_uscaled_z24_unorm_pack_s_8uscaled(dst_row, dst_stride,
src_row, src_stride,
width, height);
}
void
util_format_x32_s8x24_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride,
const uint8_t *src_row, unsigned src_stride,
unsigned width, unsigned height)
{
util_format_z32_float_s8x24_uscaled_unpack_s_8uscaled(dst_row, dst_stride,
src_row, src_stride,
width, height);
}
void
util_format_x32_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride,
const uint8_t *src_row, unsigned src_stride,
unsigned width, unsigned height)
{
util_format_z32_float_s8x24_uscaled_pack_s_8uscaled(dst_row, dst_stride,
src_row, src_stride,
width, height);
}

View file

@ -192,5 +192,21 @@ util_format_z32_float_s8x24_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned
void void
util_format_z32_float_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height); util_format_z32_float_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
void
util_format_x24s8_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
void
util_format_x24s8_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
void
util_format_s8x24_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
void
util_format_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
void
util_format_x32_s8x24_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
void
util_format_x32_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_sride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
#endif /* U_FORMAT_ZS_H_ */ #endif /* U_FORMAT_ZS_H_ */

View file

@ -118,6 +118,11 @@ __inline double __cdecl atan2(double val)
#endif #endif
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#if _MSC_VER < 1400 && !defined(__cplusplus) || defined(PIPE_SUBSYSTEM_WINDOWS_CE) #if _MSC_VER < 1400 && !defined(__cplusplus) || defined(PIPE_SUBSYSTEM_WINDOWS_CE)

View file

@ -71,6 +71,96 @@ _mm_castps_si128(__m128 a)
#endif /* defined(_MSC_VER) && _MSC_VER < 1500 */ #endif /* defined(_MSC_VER) && _MSC_VER < 1500 */
union m128i {
__m128i m;
ubyte ub[16];
ushort us[8];
uint ui[4];
};
static INLINE void u_print_epi8(const char *name, __m128i r)
{
union { __m128i m; ubyte ub[16]; } u;
u.m = r;
debug_printf("%s: "
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x/"
"%02x\n",
name,
u.ub[0], u.ub[1], u.ub[2], u.ub[3],
u.ub[4], u.ub[5], u.ub[6], u.ub[7],
u.ub[8], u.ub[9], u.ub[10], u.ub[11],
u.ub[12], u.ub[13], u.ub[14], u.ub[15]);
}
static INLINE void u_print_epi16(const char *name, __m128i r)
{
union { __m128i m; ushort us[8]; } u;
u.m = r;
debug_printf("%s: "
"%04x/"
"%04x/"
"%04x/"
"%04x/"
"%04x/"
"%04x/"
"%04x/"
"%04x\n",
name,
u.us[0], u.us[1], u.us[2], u.us[3],
u.us[4], u.us[5], u.us[6], u.us[7]);
}
static INLINE void u_print_epi32(const char *name, __m128i r)
{
union { __m128i m; uint ui[4]; } u;
u.m = r;
debug_printf("%s: "
"%08x/"
"%08x/"
"%08x/"
"%08x\n",
name,
u.ui[0], u.ui[1], u.ui[2], u.ui[3]);
}
static INLINE void u_print_ps(const char *name, __m128 r)
{
union { __m128 m; float f[4]; } u;
u.m = r;
debug_printf("%s: "
"%f/"
"%f/"
"%f/"
"%f\n",
name,
u.f[0], u.f[1], u.f[2], u.f[3]);
}
#define U_DUMP_EPI32(a) u_print_epi32(#a, a)
#define U_DUMP_EPI16(a) u_print_epi16(#a, a)
#define U_DUMP_EPI8(a) u_print_epi8(#a, a)
#define U_DUMP_PS(a) u_print_ps(#a, a)
#if defined(PIPE_ARCH_SSSE3) #if defined(PIPE_ARCH_SSSE3)
@ -98,6 +188,68 @@ _mm_shuffle_epi8(__m128i a, __m128i mask)
#endif /* !PIPE_ARCH_SSSE3 */ #endif /* !PIPE_ARCH_SSSE3 */
#endif /* PIPE_ARCH_X86 || PIPE_ARCH_X86_64 */
/* Provide an SSE2 implementation of _mm_mullo_epi32() in terms of
* _mm_mul_epu32().
*
* I suspect this works fine for us because one of our operands is
* always positive, but not sure that this can be used for general
* signed integer multiplication.
*
* This seems close enough to the speed of SSE4 and the real
* _mm_mullo_epi32() intrinsic as to not justify adding an sse4
* dependency at this point.
*/
static INLINE __m128i mm_mullo_epi32(const __m128i a, const __m128i b)
{
__m128i a4 = _mm_srli_epi64(a, 32); /* shift by one dword */
__m128i b4 = _mm_srli_epi64(b, 32); /* shift by one dword */
__m128i ba = _mm_mul_epu32(b, a); /* multply dwords 0, 2 */
__m128i b4a4 = _mm_mul_epu32(b4, a4); /* multiply dwords 1, 3 */
/* Interleave the results, either with shuffles or (slightly
* faster) direct bit operations:
*/
#if 0
__m128i ba8 = _mm_shuffle_epi32(ba, 8);
__m128i b4a48 = _mm_shuffle_epi32(b4a4, 8);
__m128i result = _mm_unpacklo_epi32(ba8, b4a48);
#else
__m128i mask = _mm_setr_epi32(~0,0,~0,0);
__m128i ba_mask = _mm_and_si128(ba, mask);
__m128i b4a4_mask_shift = _mm_slli_epi64(b4a4, 32);
__m128i result = _mm_or_si128(ba_mask, b4a4_mask_shift);
#endif
return result;
}
static INLINE void
transpose4_epi32(const __m128i * restrict a,
const __m128i * restrict b,
const __m128i * restrict c,
const __m128i * restrict d,
__m128i * restrict o,
__m128i * restrict p,
__m128i * restrict q,
__m128i * restrict r)
{
__m128i t0 = _mm_unpacklo_epi32(*a, *b);
__m128i t1 = _mm_unpacklo_epi32(*c, *d);
__m128i t2 = _mm_unpackhi_epi32(*a, *b);
__m128i t3 = _mm_unpackhi_epi32(*c, *d);
*o = _mm_unpacklo_epi64(t0, t1);
*p = _mm_unpackhi_epi64(t0, t1);
*q = _mm_unpacklo_epi64(t2, t3);
*r = _mm_unpackhi_epi64(t2, t3);
}
#define SCALAR_EPI32(m, i) _mm_shuffle_epi32((m), _MM_SHUFFLE(i,i,i,i))
#endif /* PIPE_ARCH_SSE */
#endif /* U_SSE_H_ */ #endif /* U_SSE_H_ */

View file

@ -217,6 +217,81 @@ z24s8_get_tile_rgba(const unsigned *src,
} }
} }
/*** PIPE_FORMAT_S8X24_USCALED ***/
/**
* Return S component as four uint32_t in [0..255]. Z part ignored.
*/
static void
s8x24_get_tile_rgba(const unsigned *src,
unsigned w, unsigned h,
float *p,
unsigned dst_stride)
{
unsigned i, j;
for (i = 0; i < h; i++) {
float *pRow = p;
for (j = 0; j < w; j++, pRow += 4) {
pRow[0] =
pRow[1] =
pRow[2] =
pRow[3] = (float)((*src++ >> 24) & 0xff);
}
p += dst_stride;
}
}
/*** PIPE_FORMAT_X24S8_USCALED ***/
/**
* Return S component as four uint32_t in [0..255]. Z part ignored.
*/
static void
x24s8_get_tile_rgba(const unsigned *src,
unsigned w, unsigned h,
float *p,
unsigned dst_stride)
{
unsigned i, j;
for (i = 0; i < h; i++) {
float *pRow = p;
for (j = 0; j < w; j++, pRow += 4) {
pRow[0] =
pRow[1] =
pRow[2] =
pRow[3] = (float)(*src++ & 0xff);
}
p += dst_stride;
}
}
/**
* Return S component as four uint32_t in [0..255]. Z part ignored.
*/
static void
s8_get_tile_rgba(const unsigned char *src,
unsigned w, unsigned h,
float *p,
unsigned dst_stride)
{
unsigned i, j;
for (i = 0; i < h; i++) {
float *pRow = p;
for (j = 0; j < w; j++, pRow += 4) {
pRow[0] =
pRow[1] =
pRow[2] =
pRow[3] = (float)(*src++ & 0xff);
}
p += dst_stride;
}
}
/*** PIPE_FORMAT_Z32_FLOAT ***/ /*** PIPE_FORMAT_Z32_FLOAT ***/
@ -261,10 +336,19 @@ pipe_tile_raw_to_rgba(enum pipe_format format,
case PIPE_FORMAT_Z24X8_UNORM: case PIPE_FORMAT_Z24X8_UNORM:
s8z24_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride); s8z24_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
break; break;
case PIPE_FORMAT_S8_USCALED:
s8_get_tile_rgba((unsigned char *) src, w, h, dst, dst_stride);
break;
case PIPE_FORMAT_X24S8_USCALED:
s8x24_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
break;
case PIPE_FORMAT_S8_USCALED_Z24_UNORM: case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
case PIPE_FORMAT_X8Z24_UNORM: case PIPE_FORMAT_X8Z24_UNORM:
z24s8_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride); z24s8_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
break; break;
case PIPE_FORMAT_S8X24_USCALED:
x24s8_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
break;
case PIPE_FORMAT_Z32_FLOAT: case PIPE_FORMAT_Z32_FLOAT:
z32f_get_tile_rgba((float *) src, w, h, dst, dst_stride); z32f_get_tile_rgba((float *) src, w, h, dst, dst_stride);
break; break;

View file

@ -156,6 +156,15 @@ If there is an index buffer bound, and ``indexed`` field is true, all vertex
indices will be looked up in the index buffer. ``min_index``, ``max_index``, indices will be looked up in the index buffer. ``min_index``, ``max_index``,
and ``index_bias`` apply after index lookup. and ``index_bias`` apply after index lookup.
When drawing indexed primitives, the primitive restart index can be
used to draw disjoint primitive strips. For example, several separate
line strips can be drawn by designating a special index value as the
restart index. The ``primitive_restart`` flag enables/disables this
feature. The ``restart_index`` field specifies the restart index value.
When primitive restart is in use, array indexes are compared to the
restart index before adding the index_bias offset.
If a given vertex element has ``instance_divisor`` set to 0, it is said If a given vertex element has ``instance_divisor`` set to 0, it is said
it contains per-vertex data and effective vertex attribute address needs it contains per-vertex data and effective vertex attribute address needs
to be recalculated for every index. to be recalculated for every index.

View file

@ -1415,6 +1415,12 @@ Edge flags are used to control which lines or points are actually
drawn when the polygon mode converts triangles/quads/polygons into drawn when the polygon mode converts triangles/quads/polygons into
points or lines. points or lines.
TGSI_SEMANTIC_STENCIL
""""""""""""""""""""""
For fragment shaders, this semantic label indicates than an output
is a writable stencil reference value. Only the Y component is writable.
This allows the fragment shader to change the fragments stencilref value.
Properties Properties
@ -1493,6 +1499,8 @@ well.
| Z | XXX TBD | (z, z, z, 1) | (0, z, 0, 1) | | Z | XXX TBD | (z, z, z, 1) | (0, z, 0, 1) |
| | | [#depth-tex-mode]_ | | | | | [#depth-tex-mode]_ | |
+--------------------+--------------+--------------------+--------------+ +--------------------+--------------+--------------------+--------------+
| S | (s, s, s, s) | unknown | unknown |
+--------------------+--------------+--------------------+--------------+
.. [#envmap-bumpmap] http://www.opengl.org/registry/specs/ATI/envmap_bumpmap.txt .. [#envmap-bumpmap] http://www.opengl.org/registry/specs/ATI/envmap_bumpmap.txt
.. [#depth-tex-mode] the default is (z, z, z, 1) but may also be (0, 0, 0, z) .. [#depth-tex-mode] the default is (z, z, z, 1) but may also be (0, 0, 0, z)

View file

@ -641,7 +641,7 @@ galahad_set_index_buffer(struct pipe_context *_pipe,
break; break;
default: default:
glhd_warn("index buffer %p has unrecognized index size %d", glhd_warn("index buffer %p has unrecognized index size %d",
_ib->buffer, _ib->index_size); (void *) _ib->buffer, _ib->index_size);
break; break;
} }
} }
@ -1013,7 +1013,7 @@ galahad_context_create(struct pipe_screen *_screen, struct pipe_context *pipe)
glhd_pipe->pipe = pipe; glhd_pipe->pipe = pipe;
glhd_warn("Created context %p", glhd_pipe); glhd_warn("Created context %p", (void *) glhd_pipe);
return &glhd_pipe->base; return &glhd_pipe->base;
} }

View file

@ -370,7 +370,7 @@ galahad_screen_create(struct pipe_screen *screen)
glhd_screen->screen = screen; glhd_screen->screen = screen;
glhd_warn("Created screen %p", glhd_screen); glhd_warn("Created screen %p", (void *) glhd_screen);
return &glhd_screen->base; return &glhd_screen->base;
} }

View file

@ -28,8 +28,6 @@ C_SOURCES = \
lp_scene_queue.c \ lp_scene_queue.c \
lp_screen.c \ lp_screen.c \
lp_setup.c \ lp_setup.c \
lp_setup_coef.c \
lp_setup_coef_intrin.c \
lp_setup_line.c \ lp_setup_line.c \
lp_setup_point.c \ lp_setup_point.c \
lp_setup_tri.c \ lp_setup_tri.c \
@ -38,6 +36,7 @@ C_SOURCES = \
lp_state_clip.c \ lp_state_clip.c \
lp_state_derived.c \ lp_state_derived.c \
lp_state_fs.c \ lp_state_fs.c \
lp_state_setup.c \
lp_state_gs.c \ lp_state_gs.c \
lp_state_rasterizer.c \ lp_state_rasterizer.c \
lp_state_sampler.c \ lp_state_sampler.c \
@ -63,14 +62,14 @@ PROGS := lp_test_format \
# Need this for the lp_test_*.o files # Need this for the lp_test_*.o files
CLEAN_EXTRA = *.o CLEAN_EXTRA = *.o
include ../../Makefile.template
lp_test_sincos.o : sse_mathfun.h lp_test_sincos.o : sse_mathfun.h
PROGS_DEPS := ../../auxiliary/libgallium.a PROGS_DEPS := ../../auxiliary/libgallium.a
include ../../Makefile.template
lp_tile_soa.c: lp_tile_soa.py ../../auxiliary/util/u_format_parse.py ../../auxiliary/util/u_format_pack.py ../../auxiliary/util/u_format.csv lp_tile_soa.c: lp_tile_soa.py ../../auxiliary/util/u_format_parse.py ../../auxiliary/util/u_format_pack.py ../../auxiliary/util/u_format.csv
python lp_tile_soa.py ../../auxiliary/util/u_format.csv > $@ $(PYTHON2) $(PYTHON_FLAGS) lp_tile_soa.py ../../auxiliary/util/u_format.csv > $@
LDFLAGS += $(LLVM_LDFLAGS) LDFLAGS += $(LLVM_LDFLAGS)
LIBS += -L../../auxiliary/ -lgallium libllvmpipe.a $(LLVM_LIBS) $(GL_LIB_DEPS) LIBS += -L../../auxiliary/ -lgallium libllvmpipe.a $(LLVM_LIBS) $(GL_LIB_DEPS)

View file

@ -27,13 +27,7 @@ env.Depends('lp_tile_soa.c', [
]) ])
# Only enable SSSE3 for lp_tile_soa_sse3.c lp_tile_soa_os = env.SharedObject('lp_tile_soa.c')
ssse3_env = env.Clone()
if env['gcc'] \
and distutils.version.LooseVersion(env['CCVERSION']) >= distutils.version.LooseVersion('4.3') \
and env['machine'] in ('x86', 'x86_64') :
ssse3_env.Append(CCFLAGS = ['-mssse3'])
lp_tile_soa_os = ssse3_env.SharedObject('lp_tile_soa.c')
llvmpipe = env.ConvenienceLibrary( llvmpipe = env.ConvenienceLibrary(
@ -64,13 +58,12 @@ llvmpipe = env.ConvenienceLibrary(
'lp_setup_line.c', 'lp_setup_line.c',
'lp_setup_point.c', 'lp_setup_point.c',
'lp_setup_tri.c', 'lp_setup_tri.c',
'lp_setup_coef.c',
'lp_setup_coef_intrin.c',
'lp_setup_vbuf.c', 'lp_setup_vbuf.c',
'lp_state_blend.c', 'lp_state_blend.c',
'lp_state_clip.c', 'lp_state_clip.c',
'lp_state_derived.c', 'lp_state_derived.c',
'lp_state_fs.c', 'lp_state_fs.c',
'lp_state_setup.c',
'lp_state_gs.c', 'lp_state_gs.c',
'lp_state_rasterizer.c', 'lp_state_rasterizer.c',
'lp_state_sampler.c', 'lp_state_sampler.c',

View file

@ -48,7 +48,8 @@ lp_build_alpha_test(LLVMBuilderRef builder,
struct lp_type type, struct lp_type type,
struct lp_build_mask_context *mask, struct lp_build_mask_context *mask,
LLVMValueRef alpha, LLVMValueRef alpha,
LLVMValueRef ref) LLVMValueRef ref,
boolean do_branch)
{ {
struct lp_build_context bld; struct lp_build_context bld;
LLVMValueRef test; LLVMValueRef test;
@ -60,4 +61,7 @@ lp_build_alpha_test(LLVMBuilderRef builder,
lp_build_name(test, "alpha_mask"); lp_build_name(test, "alpha_mask");
lp_build_mask_update(mask, test); lp_build_mask_update(mask, test);
if (do_branch)
lp_build_mask_check(mask);
} }

View file

@ -48,7 +48,8 @@ lp_build_alpha_test(LLVMBuilderRef builder,
struct lp_type type, struct lp_type type,
struct lp_build_mask_context *mask, struct lp_build_mask_context *mask,
LLVMValueRef alpha, LLVMValueRef alpha,
LLVMValueRef ref); LLVMValueRef ref,
boolean do_branch);
#endif /* !LP_BLD_ALPHA_H */ #endif /* !LP_BLD_ALPHA_H */

View file

@ -1,6 +1,6 @@
/************************************************************************** /**************************************************************************
* *
* Copyright 2009 VMware, Inc. * Copyright 2009-2010 VMware, Inc.
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
@ -53,15 +53,8 @@
* ... ... ... ... ... ... ... ... ... * ... ... ... ... ... ... ... ... ...
* *
* *
* Stencil test:
* Two-sided stencil test is supported but probably not as efficient as
* it could be. Currently, we use if/then/else constructs to do the
* operations for front vs. back-facing polygons. We could probably do
* both the front and back arithmetic then use a Select() instruction to
* choose the result depending on polyon orientation. We'd have to
* measure performance both ways and see which is better.
*
* @author Jose Fonseca <jfonseca@vmware.com> * @author Jose Fonseca <jfonseca@vmware.com>
* @author Brian Paul <jfonseca@vmware.com>
*/ */
#include "pipe/p_state.h" #include "pipe/p_state.h"
@ -71,6 +64,7 @@
#include "gallivm/lp_bld_arit.h" #include "gallivm/lp_bld_arit.h"
#include "gallivm/lp_bld_bitarit.h" #include "gallivm/lp_bld_bitarit.h"
#include "gallivm/lp_bld_const.h" #include "gallivm/lp_bld_const.h"
#include "gallivm/lp_bld_conv.h"
#include "gallivm/lp_bld_logic.h" #include "gallivm/lp_bld_logic.h"
#include "gallivm/lp_bld_flow.h" #include "gallivm/lp_bld_flow.h"
#include "gallivm/lp_bld_intr.h" #include "gallivm/lp_bld_intr.h"
@ -310,8 +304,13 @@ lp_depth_type(const struct util_format_description *format_desc,
} }
else if(format_desc->channel[swizzle].type == UTIL_FORMAT_TYPE_UNSIGNED) { else if(format_desc->channel[swizzle].type == UTIL_FORMAT_TYPE_UNSIGNED) {
assert(format_desc->block.bits <= 32); assert(format_desc->block.bits <= 32);
if(format_desc->channel[swizzle].normalized) assert(format_desc->channel[swizzle].normalized);
type.norm = TRUE; if (format_desc->channel[swizzle].size < format_desc->block.bits) {
/* Prefer signed integers when possible, as SSE has less support
* for unsigned comparison;
*/
type.sign = TRUE;
}
} }
else else
assert(0); assert(0);
@ -333,7 +332,7 @@ lp_depth_type(const struct util_format_description *format_desc,
*/ */
static boolean static boolean
get_z_shift_and_mask(const struct util_format_description *format_desc, get_z_shift_and_mask(const struct util_format_description *format_desc,
unsigned *shift, unsigned *mask) unsigned *shift, unsigned *width, unsigned *mask)
{ {
const unsigned total_bits = format_desc->block.bits; const unsigned total_bits = format_desc->block.bits;
unsigned z_swizzle; unsigned z_swizzle;
@ -349,12 +348,14 @@ get_z_shift_and_mask(const struct util_format_description *format_desc,
if (z_swizzle == UTIL_FORMAT_SWIZZLE_NONE) if (z_swizzle == UTIL_FORMAT_SWIZZLE_NONE)
return FALSE; return FALSE;
*width = format_desc->channel[z_swizzle].size;
padding_right = 0; padding_right = 0;
for (chan = 0; chan < z_swizzle; ++chan) for (chan = 0; chan < z_swizzle; ++chan)
padding_right += format_desc->channel[chan].size; padding_right += format_desc->channel[chan].size;
padding_left = padding_left =
total_bits - (padding_right + format_desc->channel[z_swizzle].size); total_bits - (padding_right + *width);
if (padding_left || padding_right) { if (padding_left || padding_right) {
unsigned long long mask_left = (1ULL << (total_bits - padding_left)) - 1; unsigned long long mask_left = (1ULL << (total_bits - padding_left)) - 1;
@ -365,7 +366,7 @@ get_z_shift_and_mask(const struct util_format_description *format_desc,
*mask = 0xffffffff; *mask = 0xffffffff;
} }
*shift = padding_left; *shift = padding_right;
return TRUE; return TRUE;
} }
@ -409,7 +410,7 @@ get_s_shift_and_mask(const struct util_format_description *format_desc,
* \param maskvalue is the depth test mask. * \param maskvalue is the depth test mask.
* \param counter is a pointer of the uint32 counter. * \param counter is a pointer of the uint32 counter.
*/ */
static void void
lp_build_occlusion_count(LLVMBuilderRef builder, lp_build_occlusion_count(LLVMBuilderRef builder,
struct lp_type type, struct lp_type type,
LLVMValueRef maskvalue, LLVMValueRef maskvalue,
@ -446,33 +447,58 @@ lp_build_occlusion_count(LLVMBuilderRef builder,
* \param format_desc description of the depth/stencil surface * \param format_desc description of the depth/stencil surface
* \param mask the alive/dead pixel mask for the quad (vector) * \param mask the alive/dead pixel mask for the quad (vector)
* \param stencil_refs the front/back stencil ref values (scalar) * \param stencil_refs the front/back stencil ref values (scalar)
* \param z_src the incoming depth/stencil values (a 2x2 quad) * \param z_src the incoming depth/stencil values (a 2x2 quad, float32)
* \param zs_dst_ptr pointer to depth/stencil values in framebuffer * \param zs_dst_ptr pointer to depth/stencil values in framebuffer
* \param facing contains float value indicating front/back facing polygon * \param facing contains boolean value indicating front/back facing polygon
*/ */
void void
lp_build_depth_stencil_test(LLVMBuilderRef builder, lp_build_depth_stencil_test(LLVMBuilderRef builder,
const struct pipe_depth_state *depth, const struct pipe_depth_state *depth,
const struct pipe_stencil_state stencil[2], const struct pipe_stencil_state stencil[2],
struct lp_type type, struct lp_type z_src_type,
const struct util_format_description *format_desc, const struct util_format_description *format_desc,
struct lp_build_mask_context *mask, struct lp_build_mask_context *mask,
LLVMValueRef stencil_refs[2], LLVMValueRef stencil_refs[2],
LLVMValueRef z_src, LLVMValueRef z_src,
LLVMValueRef zs_dst_ptr, LLVMValueRef zs_dst_ptr,
LLVMValueRef face, LLVMValueRef face,
LLVMValueRef counter) LLVMValueRef *zs_value,
boolean do_branch)
{ {
struct lp_build_context bld; struct lp_type z_type;
struct lp_build_context sbld; struct lp_build_context z_bld;
struct lp_build_context s_bld;
struct lp_type s_type; struct lp_type s_type;
unsigned z_shift = 0, z_width = 0, z_mask = 0;
LLVMValueRef zs_dst, z_dst = NULL; LLVMValueRef zs_dst, z_dst = NULL;
LLVMValueRef stencil_vals = NULL; LLVMValueRef stencil_vals = NULL;
LLVMValueRef z_bitmask = NULL, stencil_shift = NULL; LLVMValueRef z_bitmask = NULL, stencil_shift = NULL;
LLVMValueRef z_pass = NULL, s_pass_mask = NULL; LLVMValueRef z_pass = NULL, s_pass_mask = NULL;
LLVMValueRef orig_mask = mask->value; LLVMValueRef orig_mask = lp_build_mask_value(mask);
LLVMValueRef front_facing = NULL; LLVMValueRef front_facing = NULL;
/*
* Depths are expected to be between 0 and 1, even if they are stored in
* floats. Setting these bits here will ensure that the lp_build_conv() call
* below won't try to unnecessarily clamp the incoming values.
*/
if(z_src_type.floating) {
z_src_type.sign = FALSE;
z_src_type.norm = TRUE;
}
else {
assert(!z_src_type.sign);
assert(z_src_type.norm);
}
/* Pick the depth type. */
z_type = lp_depth_type(format_desc, z_src_type.width*z_src_type.length);
/* FIXME: Cope with a depth test type with a different bit width. */
assert(z_type.width == z_src_type.width);
assert(z_type.length == z_src_type.length);
/* Sanity checking */ /* Sanity checking */
{ {
const unsigned z_swizzle = format_desc->swizzle[0]; const unsigned z_swizzle = format_desc->swizzle[0];
@ -493,8 +519,8 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
} }
assert(z_swizzle < 4); assert(z_swizzle < 4);
assert(format_desc->block.bits == type.width); assert(format_desc->block.bits == z_type.width);
if (type.floating) { if (z_type.floating) {
assert(z_swizzle == 0); assert(z_swizzle == 0);
assert(format_desc->channel[z_swizzle].type == assert(format_desc->channel[z_swizzle].type ==
UTIL_FORMAT_TYPE_FLOAT); UTIL_FORMAT_TYPE_FLOAT);
@ -505,54 +531,56 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
assert(format_desc->channel[z_swizzle].type == assert(format_desc->channel[z_swizzle].type ==
UTIL_FORMAT_TYPE_UNSIGNED); UTIL_FORMAT_TYPE_UNSIGNED);
assert(format_desc->channel[z_swizzle].normalized); assert(format_desc->channel[z_swizzle].normalized);
assert(!type.fixed); assert(!z_type.fixed);
assert(!type.sign);
assert(type.norm);
} }
} }
/* Setup build context for Z vals */ /* Setup build context for Z vals */
lp_build_context_init(&bld, builder, type); lp_build_context_init(&z_bld, builder, z_type);
/* Setup build context for stencil vals */ /* Setup build context for stencil vals */
s_type = lp_type_int_vec(type.width); s_type = lp_type_int_vec(z_type.width);
lp_build_context_init(&sbld, builder, s_type); lp_build_context_init(&s_bld, builder, s_type);
/* Load current z/stencil value from z/stencil buffer */ /* Load current z/stencil value from z/stencil buffer */
zs_dst_ptr = LLVMBuildBitCast(builder,
zs_dst_ptr,
LLVMPointerType(z_bld.vec_type, 0), "");
zs_dst = LLVMBuildLoad(builder, zs_dst_ptr, ""); zs_dst = LLVMBuildLoad(builder, zs_dst_ptr, "");
lp_build_name(zs_dst, "zsbufval"); lp_build_name(zs_dst, "zs_dst");
/* Compute and apply the Z/stencil bitmasks and shifts. /* Compute and apply the Z/stencil bitmasks and shifts.
*/ */
{ {
unsigned z_shift, z_mask;
unsigned s_shift, s_mask; unsigned s_shift, s_mask;
if (get_z_shift_and_mask(format_desc, &z_shift, &z_mask)) { if (get_z_shift_and_mask(format_desc, &z_shift, &z_width, &z_mask)) {
if (z_shift) {
LLVMValueRef shift = lp_build_const_int_vec(type, z_shift);
z_src = LLVMBuildLShr(builder, z_src, shift, "");
}
if (z_mask != 0xffffffff) { if (z_mask != 0xffffffff) {
LLVMValueRef mask = lp_build_const_int_vec(type, z_mask); z_bitmask = lp_build_const_int_vec(z_type, z_mask);
z_src = LLVMBuildAnd(builder, z_src, mask, "");
z_dst = LLVMBuildAnd(builder, zs_dst, mask, "");
z_bitmask = mask; /* used below */
}
else {
z_dst = zs_dst;
} }
lp_build_name(z_dst, "zsbuf.z"); /*
* Align the framebuffer Z 's LSB to the right.
*/
if (z_shift) {
LLVMValueRef shift = lp_build_const_int_vec(z_type, z_shift);
z_dst = LLVMBuildLShr(builder, zs_dst, shift, "z_dst");
} else if (z_bitmask) {
/* TODO: Instead of loading a mask from memory and ANDing, it's
* probably faster to just shake the bits with two shifts. */
z_dst = LLVMBuildAnd(builder, zs_dst, z_bitmask, "z_dst");
} else {
z_dst = zs_dst;
lp_build_name(z_dst, "z_dst");
}
} }
if (get_s_shift_and_mask(format_desc, &s_shift, &s_mask)) { if (get_s_shift_and_mask(format_desc, &s_shift, &s_mask)) {
if (s_shift) { if (s_shift) {
LLVMValueRef shift = lp_build_const_int_vec(type, s_shift); LLVMValueRef shift = lp_build_const_int_vec(s_type, s_shift);
stencil_vals = LLVMBuildLShr(builder, zs_dst, shift, ""); stencil_vals = LLVMBuildLShr(builder, zs_dst, shift, "");
stencil_shift = shift; /* used below */ stencil_shift = shift; /* used below */
} }
@ -561,48 +589,85 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
} }
if (s_mask != 0xffffffff) { if (s_mask != 0xffffffff) {
LLVMValueRef mask = lp_build_const_int_vec(type, s_mask); LLVMValueRef mask = lp_build_const_int_vec(s_type, s_mask);
stencil_vals = LLVMBuildAnd(builder, stencil_vals, mask, ""); stencil_vals = LLVMBuildAnd(builder, stencil_vals, mask, "");
} }
lp_build_name(stencil_vals, "stencil"); lp_build_name(stencil_vals, "s_dst");
} }
} }
if (stencil[0].enabled) { if (stencil[0].enabled) {
if (face) { if (face) {
LLVMValueRef zero = LLVMConstReal(LLVMFloatType(), 0.0); LLVMValueRef zero = LLVMConstInt(LLVMInt32Type(), 0, 0);
/* front_facing = face > 0.0 ? ~0 : 0 */ /* front_facing = face != 0 ? ~0 : 0 */
front_facing = LLVMBuildFCmp(builder, LLVMRealUGT, face, zero, ""); front_facing = LLVMBuildICmp(builder, LLVMIntNE, face, zero, "");
front_facing = LLVMBuildSExt(builder, front_facing, front_facing = LLVMBuildSExt(builder, front_facing,
LLVMIntType(bld.type.length*bld.type.width), LLVMIntType(s_bld.type.length*s_bld.type.width),
""); "");
front_facing = LLVMBuildBitCast(builder, front_facing, front_facing = LLVMBuildBitCast(builder, front_facing,
bld.int_vec_type, ""); s_bld.int_vec_type, "");
} }
/* convert scalar stencil refs into vectors */ /* convert scalar stencil refs into vectors */
stencil_refs[0] = lp_build_broadcast_scalar(&bld, stencil_refs[0]); stencil_refs[0] = lp_build_broadcast_scalar(&s_bld, stencil_refs[0]);
stencil_refs[1] = lp_build_broadcast_scalar(&bld, stencil_refs[1]); stencil_refs[1] = lp_build_broadcast_scalar(&s_bld, stencil_refs[1]);
s_pass_mask = lp_build_stencil_test(&sbld, stencil, s_pass_mask = lp_build_stencil_test(&s_bld, stencil,
stencil_refs, stencil_vals, stencil_refs, stencil_vals,
front_facing); front_facing);
/* apply stencil-fail operator */ /* apply stencil-fail operator */
{ {
LLVMValueRef s_fail_mask = lp_build_andnot(&bld, orig_mask, s_pass_mask); LLVMValueRef s_fail_mask = lp_build_andnot(&s_bld, orig_mask, s_pass_mask);
stencil_vals = lp_build_stencil_op(&sbld, stencil, S_FAIL_OP, stencil_vals = lp_build_stencil_op(&s_bld, stencil, S_FAIL_OP,
stencil_refs, stencil_vals, stencil_refs, stencil_vals,
s_fail_mask, front_facing); s_fail_mask, front_facing);
} }
} }
if (depth->enabled) { if (depth->enabled) {
/*
* Convert fragment Z to the desired type, aligning the LSB to the right.
*/
assert(z_type.width == z_src_type.width);
assert(z_type.length == z_src_type.length);
assert(lp_check_value(z_src_type, z_src));
if (z_src_type.floating) {
/*
* Convert from floating point values
*/
if (!z_type.floating) {
z_src = lp_build_clamped_float_to_unsigned_norm(builder,
z_src_type,
z_width,
z_src);
}
} else {
/*
* Convert from unsigned normalized values.
*/
assert(!z_src_type.sign);
assert(!z_src_type.fixed);
assert(z_src_type.norm);
assert(!z_type.floating);
if (z_src_type.width > z_width) {
LLVMValueRef shift = lp_build_const_int_vec(z_src_type,
z_src_type.width - z_width);
z_src = LLVMBuildLShr(builder, z_src, shift, "");
}
}
assert(lp_check_value(z_type, z_src));
lp_build_name(z_src, "z_src");
/* compare src Z to dst Z, returning 'pass' mask */ /* compare src Z to dst Z, returning 'pass' mask */
z_pass = lp_build_cmp(&bld, depth->func, z_src, z_dst); z_pass = lp_build_cmp(&z_bld, depth->func, z_src, z_dst);
if (!stencil[0].enabled) { if (!stencil[0].enabled) {
/* We can potentially skip all remaining operations here, but only /* We can potentially skip all remaining operations here, but only
@ -610,28 +675,28 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
* buffer values. Don't need to update Z buffer values. * buffer values. Don't need to update Z buffer values.
*/ */
lp_build_mask_update(mask, z_pass); lp_build_mask_update(mask, z_pass);
if (do_branch) {
lp_build_mask_check(mask);
do_branch = FALSE;
}
} }
if (depth->writemask) { if (depth->writemask) {
LLVMValueRef zselectmask = mask->value; LLVMValueRef zselectmask;
/* mask off bits that failed Z test */ /* mask off bits that failed Z test */
zselectmask = LLVMBuildAnd(builder, zselectmask, z_pass, ""); zselectmask = LLVMBuildAnd(builder, orig_mask, z_pass, "");
/* mask off bits that failed stencil test */ /* mask off bits that failed stencil test */
if (s_pass_mask) { if (s_pass_mask) {
zselectmask = LLVMBuildAnd(builder, zselectmask, s_pass_mask, ""); zselectmask = LLVMBuildAnd(builder, zselectmask, s_pass_mask, "");
} }
/* if combined Z/stencil format, mask off the stencil bits */
if (z_bitmask) {
zselectmask = LLVMBuildAnd(builder, zselectmask, z_bitmask, "");
}
/* Mix the old and new Z buffer values. /* Mix the old and new Z buffer values.
* z_dst[i] = (zselectmask[i] & z_src[i]) | (~zselectmask[i] & z_dst[i]) * z_dst[i] = zselectmask[i] ? z_src[i] : z_dst[i]
*/ */
z_dst = lp_build_select_bitwise(&bld, zselectmask, z_src, z_dst); z_dst = lp_build_select(&z_bld, zselectmask, z_src, z_dst);
} }
if (stencil[0].enabled) { if (stencil[0].enabled) {
@ -639,14 +704,14 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
LLVMValueRef z_fail_mask, z_pass_mask; LLVMValueRef z_fail_mask, z_pass_mask;
/* apply Z-fail operator */ /* apply Z-fail operator */
z_fail_mask = lp_build_andnot(&bld, orig_mask, z_pass); z_fail_mask = lp_build_andnot(&z_bld, orig_mask, z_pass);
stencil_vals = lp_build_stencil_op(&sbld, stencil, Z_FAIL_OP, stencil_vals = lp_build_stencil_op(&s_bld, stencil, Z_FAIL_OP,
stencil_refs, stencil_vals, stencil_refs, stencil_vals,
z_fail_mask, front_facing); z_fail_mask, front_facing);
/* apply Z-pass operator */ /* apply Z-pass operator */
z_pass_mask = LLVMBuildAnd(bld.builder, orig_mask, z_pass, ""); z_pass_mask = LLVMBuildAnd(z_bld.builder, orig_mask, z_pass, "");
stencil_vals = lp_build_stencil_op(&sbld, stencil, Z_PASS_OP, stencil_vals = lp_build_stencil_op(&s_bld, stencil, Z_PASS_OP,
stencil_refs, stencil_vals, stencil_refs, stencil_vals,
z_pass_mask, front_facing); z_pass_mask, front_facing);
} }
@ -655,17 +720,19 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
/* No depth test: apply Z-pass operator to stencil buffer values which /* No depth test: apply Z-pass operator to stencil buffer values which
* passed the stencil test. * passed the stencil test.
*/ */
s_pass_mask = LLVMBuildAnd(bld.builder, orig_mask, s_pass_mask, ""); s_pass_mask = LLVMBuildAnd(s_bld.builder, orig_mask, s_pass_mask, "");
stencil_vals = lp_build_stencil_op(&sbld, stencil, Z_PASS_OP, stencil_vals = lp_build_stencil_op(&s_bld, stencil, Z_PASS_OP,
stencil_refs, stencil_vals, stencil_refs, stencil_vals,
s_pass_mask, front_facing); s_pass_mask, front_facing);
} }
/* The Z bits are already in the right place but we may need to shift the /* Put Z and ztencil bits in the right place */
* stencil bits before ORing Z with Stencil to make the final pixel value. if (z_dst && z_shift) {
*/ LLVMValueRef shift = lp_build_const_int_vec(z_type, z_shift);
z_dst = LLVMBuildShl(builder, z_dst, shift, "");
}
if (stencil_vals && stencil_shift) if (stencil_vals && stencil_shift)
stencil_vals = LLVMBuildShl(bld.builder, stencil_vals, stencil_vals = LLVMBuildShl(s_bld.builder, stencil_vals,
stencil_shift, ""); stencil_shift, "");
/* Finally, merge/store the z/stencil values */ /* Finally, merge/store the z/stencil values */
@ -673,13 +740,13 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
(stencil[0].enabled && stencil[0].writemask)) { (stencil[0].enabled && stencil[0].writemask)) {
if (z_dst && stencil_vals) if (z_dst && stencil_vals)
zs_dst = LLVMBuildOr(bld.builder, z_dst, stencil_vals, ""); zs_dst = LLVMBuildOr(z_bld.builder, z_dst, stencil_vals, "");
else if (z_dst) else if (z_dst)
zs_dst = z_dst; zs_dst = z_dst;
else else
zs_dst = stencil_vals; zs_dst = stencil_vals;
LLVMBuildStore(builder, zs_dst, zs_dst_ptr); *zs_value = zs_dst;
} }
if (s_pass_mask) if (s_pass_mask)
@ -688,6 +755,47 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
if (depth->enabled && stencil[0].enabled) if (depth->enabled && stencil[0].enabled)
lp_build_mask_update(mask, z_pass); lp_build_mask_update(mask, z_pass);
if (counter) if (do_branch)
lp_build_occlusion_count(builder, type, mask->value, counter); lp_build_mask_check(mask);
}
void
lp_build_depth_write(LLVMBuilderRef builder,
const struct util_format_description *format_desc,
LLVMValueRef zs_dst_ptr,
LLVMValueRef zs_value)
{
zs_dst_ptr = LLVMBuildBitCast(builder, zs_dst_ptr,
LLVMPointerType(LLVMTypeOf(zs_value), 0), "");
LLVMBuildStore(builder, zs_value, zs_dst_ptr);
}
void
lp_build_deferred_depth_write(LLVMBuilderRef builder,
struct lp_type z_src_type,
const struct util_format_description *format_desc,
struct lp_build_mask_context *mask,
LLVMValueRef zs_dst_ptr,
LLVMValueRef zs_value)
{
struct lp_type z_type;
struct lp_build_context z_bld;
LLVMValueRef z_dst;
/* XXX: pointlessly redo type logic:
*/
z_type = lp_depth_type(format_desc, z_src_type.width*z_src_type.length);
lp_build_context_init(&z_bld, builder, z_type);
zs_dst_ptr = LLVMBuildBitCast(builder, zs_dst_ptr,
LLVMPointerType(z_bld.vec_type, 0), "");
z_dst = LLVMBuildLoad(builder, zs_dst_ptr, "zsbufval");
z_dst = lp_build_select(&z_bld, lp_build_mask_value(mask), zs_value, z_dst);
LLVMBuildStore(builder, z_dst, zs_dst_ptr);
} }

View file

@ -61,7 +61,27 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
LLVMValueRef zs_src, LLVMValueRef zs_src,
LLVMValueRef zs_dst_ptr, LLVMValueRef zs_dst_ptr,
LLVMValueRef facing, LLVMValueRef facing,
LLVMValueRef *zs_value,
boolean do_branch);
void
lp_build_depth_write(LLVMBuilderRef builder,
const struct util_format_description *format_desc,
LLVMValueRef zs_dst_ptr,
LLVMValueRef zs_value);
void
lp_build_deferred_depth_write(LLVMBuilderRef builder,
struct lp_type z_src_type,
const struct util_format_description *format_desc,
struct lp_build_mask_context *mask,
LLVMValueRef zs_dst_ptr,
LLVMValueRef zs_value);
void
lp_build_occlusion_count(LLVMBuilderRef builder,
struct lp_type type,
LLVMValueRef maskvalue,
LLVMValueRef counter); LLVMValueRef counter);
#endif /* !LP_BLD_DEPTH_H */ #endif /* !LP_BLD_DEPTH_H */

View file

@ -206,7 +206,7 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
dadq2 = LLVMBuildFAdd(builder, dadq, dadq, ""); dadq2 = LLVMBuildFAdd(builder, dadq, dadq, "");
/* /*
* a = a0 + x * dadx + y * dady * a = a0 + (x * dadx + y * dady)
*/ */
if (attrib == 0 && chan == 0) { if (attrib == 0 && chan == 0) {
@ -219,11 +219,11 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
a = a0; a = a0;
if (interp != LP_INTERP_CONSTANT && if (interp != LP_INTERP_CONSTANT &&
interp != LP_INTERP_FACING) { interp != LP_INTERP_FACING) {
LLVMValueRef tmp; LLVMValueRef ax, ay, axy;
tmp = LLVMBuildFMul(builder, bld->x, dadx, ""); ax = LLVMBuildFMul(builder, bld->x, dadx, "");
a = LLVMBuildFAdd(builder, a, tmp, ""); ay = LLVMBuildFMul(builder, bld->y, dady, "");
tmp = LLVMBuildFMul(builder, bld->y, dady, ""); axy = LLVMBuildFAdd(builder, ax, ay, "");
a = LLVMBuildFAdd(builder, a, tmp, ""); a = LLVMBuildFAdd(builder, a, axy, "");
} }
} }
@ -272,7 +272,10 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
* This is called when we move from one quad to the next. * This is called when we move from one quad to the next.
*/ */
static void static void
attribs_update(struct lp_build_interp_soa_context *bld, int quad_index) attribs_update(struct lp_build_interp_soa_context *bld,
int quad_index,
int start,
int end)
{ {
struct lp_build_context *coeff_bld = &bld->coeff_bld; struct lp_build_context *coeff_bld = &bld->coeff_bld;
LLVMValueRef shuffle = lp_build_const_int_vec(coeff_bld->type, quad_index); LLVMValueRef shuffle = lp_build_const_int_vec(coeff_bld->type, quad_index);
@ -282,7 +285,7 @@ attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
assert(quad_index < 4); assert(quad_index < 4);
for(attrib = 0; attrib < bld->num_attribs; ++attrib) { for(attrib = start; attrib < end; ++attrib) {
const unsigned mask = bld->mask[attrib]; const unsigned mask = bld->mask[attrib];
const unsigned interp = bld->interp[attrib]; const unsigned interp = bld->interp[attrib];
for(chan = 0; chan < NUM_CHANNELS; ++chan) { for(chan = 0; chan < NUM_CHANNELS; ++chan) {
@ -350,6 +353,14 @@ attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
} }
#endif #endif
if (attrib == 0 && chan == 2) {
/* FIXME: Depth values can exceed 1.0, due to the fact that
* setup interpolation coefficients refer to (0,0) which causes
* precision loss. So we must clamp to 1.0 here to avoid artifacts
*/
a = lp_build_min(coeff_bld, a, coeff_bld->one);
}
attrib_name(a, attrib, chan, ""); attrib_name(a, attrib, chan, "");
} }
bld->attribs[attrib][chan] = a; bld->attribs[attrib][chan] = a;
@ -434,8 +445,6 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
pos_init(bld, x0, y0); pos_init(bld, x0, y0);
coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr); coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr);
attribs_update(bld, 0);
} }
@ -443,10 +452,20 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
* Advance the position and inputs to the given quad within the block. * Advance the position and inputs to the given quad within the block.
*/ */
void void
lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld, lp_build_interp_soa_update_inputs(struct lp_build_interp_soa_context *bld,
int quad_index) int quad_index)
{ {
assert(quad_index < 4); assert(quad_index < 4);
attribs_update(bld, quad_index); attribs_update(bld, quad_index, 1, bld->num_attribs);
} }
void
lp_build_interp_soa_update_pos(struct lp_build_interp_soa_context *bld,
int quad_index)
{
assert(quad_index < 4);
attribs_update(bld, quad_index, 0, 1);
}

View file

@ -46,7 +46,31 @@
#include "tgsi/tgsi_exec.h" #include "tgsi/tgsi_exec.h"
#include "lp_setup.h" /**
* Describes how to compute the interpolation coefficients (a0, dadx, dady)
* from the vertices passed into our triangle/line/point functions by the
* draw module.
*
* Vertices are treated as an array of float[4] values, indexed by
* src_index.
*
* LP_INTERP_COLOR is translated to either LP_INTERP_CONSTANT or
* LINEAR depending on flatshade state.
*/
enum lp_interp {
LP_INTERP_CONSTANT,
LP_INTERP_COLOR,
LP_INTERP_LINEAR,
LP_INTERP_PERSPECTIVE,
LP_INTERP_POSITION,
LP_INTERP_FACING
};
struct lp_shader_input {
ushort interp:4; /* enum lp_interp */
ushort usage_mask:4; /* bitmask of TGSI_WRITEMASK_x flags */
ushort src_index:8; /* where to find values in incoming vertices */
};
struct lp_build_interp_soa_context struct lp_build_interp_soa_context
@ -89,7 +113,11 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
LLVMValueRef y); LLVMValueRef y);
void void
lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld, lp_build_interp_soa_update_inputs(struct lp_build_interp_soa_context *bld,
int quad_index);
void
lp_build_interp_soa_update_pos(struct lp_build_interp_soa_context *bld,
int quad_index); int quad_index);

View file

@ -82,6 +82,8 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
} }
} }
lp_delete_setup_variants(llvmpipe);
align_free( llvmpipe ); align_free( llvmpipe );
} }
@ -108,6 +110,7 @@ llvmpipe_create_context( struct pipe_screen *screen, void *priv )
memset(llvmpipe, 0, sizeof *llvmpipe); memset(llvmpipe, 0, sizeof *llvmpipe);
make_empty_list(&llvmpipe->fs_variants_list); make_empty_list(&llvmpipe->fs_variants_list);
make_empty_list(&llvmpipe->setup_variants_list);
llvmpipe->pipe.winsys = screen->winsys; llvmpipe->pipe.winsys = screen->winsys;
llvmpipe->pipe.screen = screen; llvmpipe->pipe.screen = screen;

View file

@ -39,6 +39,7 @@
#include "lp_jit.h" #include "lp_jit.h"
#include "lp_setup.h" #include "lp_setup.h"
#include "lp_state_fs.h" #include "lp_state_fs.h"
#include "lp_state_setup.h"
struct llvmpipe_vbuf_render; struct llvmpipe_vbuf_render;
@ -48,6 +49,7 @@ struct lp_fragment_shader;
struct lp_vertex_shader; struct lp_vertex_shader;
struct lp_blend_state; struct lp_blend_state;
struct lp_setup_context; struct lp_setup_context;
struct lp_setup_variant;
struct lp_velems_state; struct lp_velems_state;
struct llvmpipe_context { struct llvmpipe_context {
@ -105,12 +107,9 @@ struct llvmpipe_context {
/** Which vertex shader output slot contains point size */ /** Which vertex shader output slot contains point size */
int psize_slot; int psize_slot;
/** Fragment shader input interpolation info */
unsigned num_inputs;
struct lp_shader_input inputs[PIPE_MAX_SHADER_INPUTS];
/** The tiling engine */ /** The tiling engine */
struct lp_setup_context *setup; struct lp_setup_context *setup;
struct lp_setup_variant setup_variant;
/** The primitive drawing context */ /** The primitive drawing context */
struct draw_context *draw; struct draw_context *draw;
@ -120,6 +119,9 @@ struct llvmpipe_context {
struct lp_fs_variant_list_item fs_variants_list; struct lp_fs_variant_list_item fs_variants_list;
unsigned nr_fs_variants; unsigned nr_fs_variants;
struct lp_setup_variant_list_item setup_variants_list;
unsigned nr_setup_variants;
}; };

View file

@ -32,6 +32,7 @@
struct pipe_context; struct pipe_context;
struct pipe_fence_handle; struct pipe_fence_handle;
struct pipe_resource;
void void
llvmpipe_flush(struct pipe_context *pipe, llvmpipe_flush(struct pipe_context *pipe,

View file

@ -36,7 +36,6 @@
#include <llvm-c/Transforms/Scalar.h> #include <llvm-c/Transforms/Scalar.h>
#include "util/u_memory.h" #include "util/u_memory.h"
#include "util/u_cpu_detect.h"
#include "gallivm/lp_bld_init.h" #include "gallivm/lp_bld_init.h"
#include "gallivm/lp_bld_debug.h" #include "gallivm/lp_bld_debug.h"
#include "lp_screen.h" #include "lp_screen.h"
@ -162,9 +161,6 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
void void
lp_jit_screen_cleanup(struct llvmpipe_screen *screen) lp_jit_screen_cleanup(struct llvmpipe_screen *screen)
{ {
if(screen->engine)
LLVMDisposeExecutionEngine(screen->engine);
if(screen->pass) if(screen->pass)
LLVMDisposePassManager(screen->pass); LLVMDisposePassManager(screen->pass);
} }
@ -190,13 +186,7 @@ lp_jit_screen_init(struct llvmpipe_screen *screen)
LLVMAddCFGSimplificationPass(screen->pass); LLVMAddCFGSimplificationPass(screen->pass);
LLVMAddPromoteMemoryToRegisterPass(screen->pass); LLVMAddPromoteMemoryToRegisterPass(screen->pass);
LLVMAddConstantPropagationPass(screen->pass); LLVMAddConstantPropagationPass(screen->pass);
if(util_cpu_caps.has_sse4_1) {
/* FIXME: There is a bug in this pass, whereby the combination of fptosi
* and sitofp (necessary for trunc/floor/ceil/round implementation)
* somehow becomes invalid code.
*/
LLVMAddInstructionCombiningPass(screen->pass); LLVMAddInstructionCombiningPass(screen->pass);
}
LLVMAddGVNPass(screen->pass); LLVMAddGVNPass(screen->pass);
} else { } else {
/* We need at least this pass to prevent the backends to fail in /* We need at least this pass to prevent the backends to fail in

View file

@ -144,7 +144,7 @@ typedef void
(*lp_jit_frag_func)(const struct lp_jit_context *context, (*lp_jit_frag_func)(const struct lp_jit_context *context,
uint32_t x, uint32_t x,
uint32_t y, uint32_t y,
float facing, uint32_t facing,
const void *a0, const void *a0,
const void *dadx, const void *dadx,
const void *dady, const void *dady,

View file

@ -72,4 +72,14 @@
*/ */
#define LP_MAX_SHADER_VARIANTS 1024 #define LP_MAX_SHADER_VARIANTS 1024
/**
* Max number of setup variants that will be kept around.
*
* These are determined by the combination of the fragment shader
* input signature and a small amount of rasterization state (eg
* flatshading). It is likely that many active fragment shaders will
* share the same setup variant.
*/
#define LP_MAX_SETUP_VARIANTS 64
#endif /* LP_LIMITS_H */ #endif /* LP_LIMITS_H */

View file

@ -334,7 +334,7 @@ lp_rast_shade_tile(struct lp_rasterizer_task *task,
{ {
const struct lp_scene *scene = task->scene; const struct lp_scene *scene = task->scene;
const struct lp_rast_shader_inputs *inputs = arg.shade_tile; const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
const struct lp_rast_state *state = inputs->state; const struct lp_rast_state *state = task->state;
struct lp_fragment_shader_variant *variant = state->variant; struct lp_fragment_shader_variant *variant = state->variant;
const unsigned tile_x = task->x, tile_y = task->y; const unsigned tile_x = task->x, tile_y = task->y;
unsigned x, y; unsigned x, y;
@ -365,10 +365,10 @@ lp_rast_shade_tile(struct lp_rasterizer_task *task,
BEGIN_JIT_CALL(state); BEGIN_JIT_CALL(state);
variant->jit_function[RAST_WHOLE]( &state->jit_context, variant->jit_function[RAST_WHOLE]( &state->jit_context,
tile_x + x, tile_y + y, tile_x + x, tile_y + y,
inputs->facing, inputs->frontfacing,
inputs->a0, GET_A0(inputs),
inputs->dadx, GET_DADX(inputs),
inputs->dady, GET_DADY(inputs),
color, color,
depth, depth,
0xffff, 0xffff,
@ -414,7 +414,7 @@ lp_rast_shade_quads_mask(struct lp_rasterizer_task *task,
unsigned x, unsigned y, unsigned x, unsigned y,
unsigned mask) unsigned mask)
{ {
const struct lp_rast_state *state = inputs->state; const struct lp_rast_state *state = task->state;
struct lp_fragment_shader_variant *variant = state->variant; struct lp_fragment_shader_variant *variant = state->variant;
const struct lp_scene *scene = task->scene; const struct lp_scene *scene = task->scene;
uint8_t *color[PIPE_MAX_COLOR_BUFS]; uint8_t *color[PIPE_MAX_COLOR_BUFS];
@ -446,10 +446,10 @@ lp_rast_shade_quads_mask(struct lp_rasterizer_task *task,
BEGIN_JIT_CALL(state); BEGIN_JIT_CALL(state);
variant->jit_function[RAST_EDGE_TEST](&state->jit_context, variant->jit_function[RAST_EDGE_TEST](&state->jit_context,
x, y, x, y,
inputs->facing, inputs->frontfacing,
inputs->a0, GET_A0(inputs),
inputs->dadx, GET_DADX(inputs),
inputs->dady, GET_DADY(inputs),
color, color,
depth, depth,
mask, mask,
@ -490,6 +490,14 @@ lp_rast_end_query(struct lp_rasterizer_task *task,
} }
void
lp_rast_set_state(struct lp_rasterizer_task *task,
const union lp_rast_cmd_arg arg)
{
task->state = arg.state;
}
/** /**
* Set top row and left column of the tile's pixels to white. For debugging. * Set top row and left column of the tile's pixels to white. For debugging.
@ -602,6 +610,7 @@ static lp_rast_cmd_func dispatch[LP_RAST_OP_MAX] =
lp_rast_shade_tile_opaque, lp_rast_shade_tile_opaque,
lp_rast_begin_query, lp_rast_begin_query,
lp_rast_end_query, lp_rast_end_query,
lp_rast_set_state,
}; };

Some files were not shown because too many files have changed in this diff Show more