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@
# Python and flags (generally only needed by the developers)
PYTHON2 = python
PYTHON2 = @PYTHON2@
PYTHON_FLAGS = -t -O -O
# Library names (base name)

View file

@ -30,6 +30,7 @@ AC_PROG_CPP
AC_PROG_CC
AC_PROG_CXX
AC_CHECK_PROGS([MAKE], [gmake make])
AC_CHECK_PROGS([PYTHON2], [python2 python])
AC_PATH_PROG([MKDEP], [makedepend])
AC_PATH_PROG([SED], [sed])
@ -1720,6 +1721,8 @@ echo ""
echo " CFLAGS: $cflags"
echo " CXXFLAGS: $cxxflags"
echo " Macros: $defines"
echo ""
echo " PYTHON2: $PYTHON2"
echo ""
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
Per-buffer blend and masks (GL_EXT_draw_buffers2) DONE
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
glBindFragDataLocation, glGetFragDataLocation,
glBindBufferRange, glBindBufferBase commands
@ -42,7 +42,7 @@ GL 3.1:
GLSL 1.30 and 1.40 not started
Instanced drawing (GL_ARB_draw_instanced) ~50% 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
Texture buffer objs (GL_ARB_texture_buffer_object) not started
Rectangular textures (GL_ARB_texture_rectangle) DONE

View file

@ -35,6 +35,9 @@ tbd
<h2>New features</h2>
<ul>
<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>

View file

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

View file

@ -248,21 +248,20 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
if (double_buffer)
return NULL;
if (depth > 0 && depth != _eglGetConfigKey(&base, EGL_BUFFER_SIZE))
if (depth > 0 && depth != base.BufferSize)
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)) {
_eglSetConfigKey(&base, EGL_BIND_TO_TEXTURE_RGB, bind_to_texture_rgb);
if (_eglGetConfigKey(&base, EGL_ALPHA_SIZE) > 0)
_eglSetConfigKey(&base,
EGL_BIND_TO_TEXTURE_RGBA, bind_to_texture_rgba);
base.BindToTextureRGB = bind_to_texture_rgb;
if (base.AlphaSize > 0)
base.BindToTextureRGBA = bind_to_texture_rgba;
}
_eglSetConfigKey(&base, EGL_RENDERABLE_TYPE, disp->ClientAPIsMask);
_eglSetConfigKey(&base, EGL_CONFORMANT, disp->ClientAPIsMask);
base.RenderableType = disp->ClientAPIsMask;
base.Conformant = disp->ClientAPIsMask;
if (!_eglValidateConfig(&base, EGL_FALSE)) {
_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) {
memcpy(&conf->base, &base, sizeof base);
conf->dri_config = dri_config;
_eglAddConfig(disp, &conf->base);
_eglLinkConfig(&conf->base);
}
return conf;
@ -1161,7 +1160,7 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
(void) drv;
if (_eglIsSurfaceBound(surf))
if (!_eglPutSurface(surf))
return EGL_TRUE;
(*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_rsurf = dri2_egl_surface(rsurf);
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
_EGLContext *old_ctx;
_EGLSurface *old_dsurf, *old_rsurf;
__DRIdrawable *ddraw, *rdraw;
__DRIcontext *cctx;
/* bind the new context and return the "orphaned" one */
if (!_eglBindContext(&ctx, &dsurf, &rsurf))
/* make new bindings */
if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
return EGL_FALSE;
/* flush before context switch */
if (ctx && dri2_drv->glFlush)
if (old_ctx && dri2_drv->glFlush)
dri2_drv->glFlush();
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) ||
dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
if (dsurf && !_eglIsSurfaceLinked(dsurf))
dri2_destroy_surface(drv, disp, dsurf);
if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(dsurf))
dri2_destroy_surface(drv, disp, rsurf);
if (ctx != NULL && !_eglIsContextLinked(ctx))
dri2_dpy->core->unbindContext(dri2_egl_context(ctx)->dri_context);
dri2_destroy_surface(drv, disp, old_dsurf);
dri2_destroy_surface(drv, disp, old_rsurf);
if (old_ctx) {
dri2_dpy->core->unbindContext(dri2_egl_context(old_ctx)->dri_context);
/* no destroy? */
_eglPutContext(old_ctx);
}
return EGL_TRUE;
} 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;
}
@ -1251,8 +1265,7 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
if (type == EGL_PBUFFER_BIT) {
dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
xcb_create_pixmap(dri2_dpy->conn,
_eglGetConfigKey(conf, EGL_BUFFER_SIZE),
xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
dri2_surf->drawable, s.data->root,
dri2_surf->base.Width, dri2_surf->base.Height);
} else {
@ -1601,7 +1614,7 @@ dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
return EGL_NO_IMAGE_KHR;
}
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) {
if (!_eglInitImage(&dri2_img->base, disp)) {
free(buffers_reply);
free(geometry_reply);
return EGL_NO_IMAGE_KHR;
@ -1644,7 +1657,7 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
return EGL_NO_IMAGE_KHR;
}
if (!_eglInitImage(&dri2_img->base, disp, attr_list))
if (!_eglInitImage(&dri2_img->base, disp))
return EGL_NO_IMAGE_KHR;
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_image *dri2_img;
EGLint width, height, format, name, stride, pitch, i, err;
EGLint format, name, pitch, err;
_EGLImageAttribs attrs;
(void) ctx;
name = (EGLint) buffer;
err = EGL_SUCCESS;
width = 0;
height = 0;
format = 0;
stride = 0;
for (i = 0; attr_list[i] != EGL_NONE; i++) {
EGLint attr = attr_list[i++];
EGLint val = attr_list[i];
switch (attr) {
case EGL_WIDTH:
width = val;
break;
case EGL_HEIGHT:
height = val;
break;
case EGL_DRM_BUFFER_FORMAT_MESA:
format = val;
break;
case EGL_DRM_BUFFER_STRIDE_MESA:
stride = val;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS) {
_eglLog(_EGL_WARNING, "bad image attribute 0x%04x", attr);
err = _eglParseImageAttribList(&attrs, disp, attr_list);
if (err != EGL_SUCCESS)
return NULL;
}
}
if (width <= 0 || height <= 0 || stride <= 0) {
if (attrs.Width <= 0 || attrs.Height <= 0 ||
attrs.DRMBufferStrideMESA <= 0) {
_eglError(EGL_BAD_PARAMETER,
"bad width, height or stride");
return NULL;
}
switch (format) {
switch (attrs.DRMBufferFormatMESA) {
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
format = __DRI_IMAGE_FORMAT_ARGB8888;
pitch = stride;
pitch = attrs.DRMBufferStrideMESA;
break;
default:
_eglError(EGL_BAD_PARAMETER,
@ -1724,15 +1709,15 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
return NULL;
}
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) {
if (!_eglInitImage(&dri2_img->base, disp)) {
free(dri2_img);
return NULL;
}
dri2_img->dri_image =
dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
width,
height,
attrs.Width,
attrs.Height,
format,
name,
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_image *dri2_img;
int width, height, format, i;
unsigned int use, dri_use, valid_mask;
_EGLImageAttribs attrs;
unsigned int dri_use, valid_mask;
int format;
EGLint err = EGL_SUCCESS;
(void) drv;
@ -1803,74 +1789,50 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
goto cleanup_img;
}
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) {
if (!_eglInitImage(&dri2_img->base, disp)) {
err = EGL_BAD_PARAMETER;
goto cleanup_img;
}
width = 0;
height = 0;
format = 0;
use = 0;
for (i = 0; attr_list[i] != EGL_NONE; i++) {
EGLint attr = attr_list[i++];
EGLint val = attr_list[i];
switch (attr) {
case EGL_WIDTH:
width = val;
break;
case EGL_HEIGHT:
height = val;
break;
case EGL_DRM_BUFFER_FORMAT_MESA:
format = val;
break;
case EGL_DRM_BUFFER_USE_MESA:
use = val;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS) {
_eglLog(_EGL_WARNING, "bad image attribute 0x%04x", attr);
err = _eglParseImageAttribList(&attrs, disp, attr_list);
if (err != EGL_SUCCESS)
goto cleanup_img;
}
}
if (width <= 0 || height <= 0) {
_eglLog(_EGL_WARNING, "bad width or height (%dx%d)", width, height);
if (attrs.Width <= 0 || attrs.Height <= 0) {
_eglLog(_EGL_WARNING, "bad width or height (%dx%d)",
attrs.Width, attrs.Height);
goto cleanup_img;
}
switch (format) {
switch (attrs.DRMBufferFormatMESA) {
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
format = __DRI_IMAGE_FORMAT_ARGB8888;
break;
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;
}
valid_mask =
EGL_DRM_BUFFER_USE_SCANOUT_MESA |
EGL_DRM_BUFFER_USE_SHARE_MESA;
if (use & ~valid_mask) {
_eglLog(_EGL_WARNING, "bad image use bit 0x%04x", use & ~valid_mask);
if (attrs.DRMBufferUseMESA & ~valid_mask) {
_eglLog(_EGL_WARNING, "bad image use bit 0x%04x",
attrs.DRMBufferUseMESA & ~valid_mask);
goto cleanup_img;
}
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;
if (use & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
dri_use |= __DRI_IMAGE_USE_SCANOUT;
dri2_img->dri_image =
dri2_dpy->image->createImage(dri2_dpy->dri_screen,
width, height, format, dri_use, dri2_img);
attrs.Width, attrs.Height,
format, dri_use, dri2_img);
if (dri2_img->dri_image == NULL) {
err = EGL_BAD_ALLOC;
goto cleanup_img;

View file

@ -132,29 +132,38 @@ static const struct {
int egl_attr;
} fbconfig_attributes[] = {
/* table 3.1 of GLX 1.4 */
{ GLX_FBCONFIG_ID, 0 },
{ GLX_BUFFER_SIZE, EGL_BUFFER_SIZE },
{ GLX_LEVEL, EGL_LEVEL },
{ GLX_DOUBLEBUFFER, 0 },
{ GLX_STEREO, 0 },
{ GLX_AUX_BUFFERS, 0 },
{ GLX_RED_SIZE, EGL_RED_SIZE },
{ GLX_GREEN_SIZE, EGL_GREEN_SIZE },
{ GLX_BLUE_SIZE, EGL_BLUE_SIZE },
{ GLX_ALPHA_SIZE, EGL_ALPHA_SIZE },
{ GLX_DEPTH_SIZE, EGL_DEPTH_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_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_VISUAL_TYPE, EGL_NATIVE_VISUAL_TYPE },
{ GLX_CONFIG_CAVEAT, EGL_CONFIG_CAVEAT },
{ GLX_TRANSPARENT_TYPE, EGL_TRANSPARENT_TYPE },
{ GLX_TRANSPARENT_INDEX_VALUE, 0 },
{ GLX_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_RED_VALUE },
{ GLX_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_GREEN_VALUE },
{ GLX_TRANSPARENT_BLUE_VALUE, EGL_TRANSPARENT_BLUE_VALUE },
{ GLX_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_WIDTH },
{ GLX_MAX_PBUFFER_HEIGHT, EGL_MAX_PBUFFER_HEIGHT },
{ GLX_MAX_PBUFFER_PIXELS, EGL_MAX_PBUFFER_PIXELS },
{ GLX_VISUAL_ID, EGL_NATIVE_VISUAL_ID },
{ GLX_X_VISUAL_TYPE, EGL_NATIVE_VISUAL_TYPE },
{ GLX_VISUAL_ID, EGL_NATIVE_VISUAL_ID }
};
@ -162,13 +171,31 @@ static EGLBoolean
convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
struct GLX_egl_config *GLX_conf)
{
int err = 0, attr, egl_attr, val;
int err, attr, val;
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++) {
EGLint egl_attr, egl_val;
attr = fbconfig_attributes[i].attr;
egl_attr = fbconfig_attributes[i].egl_attr;
if (!egl_attr)
continue;
err = glXGetFBConfigAttrib(dpy, fbconfig, attr, &val);
if (err) {
if (err == GLX_BAD_ATTRIBUTE) {
@ -178,47 +205,71 @@ convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
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)
return EGL_FALSE;
/* must have rgba bit */
glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &val);
if (!(val & GLX_RGBA_BIT))
if (!GLX_conf->Base.SurfaceType)
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;
}
@ -227,35 +278,69 @@ static const struct {
int egl_attr;
} visual_attributes[] = {
/* table 3.7 of GLX 1.4 */
/* no GLX_USE_GL */
{ GLX_USE_GL, 0 },
{ GLX_BUFFER_SIZE, EGL_BUFFER_SIZE },
{ GLX_LEVEL, EGL_LEVEL },
{ GLX_RGBA, 0 },
{ GLX_DOUBLEBUFFER, 0 },
{ GLX_STEREO, 0 },
{ GLX_AUX_BUFFERS, 0 },
{ GLX_RED_SIZE, EGL_RED_SIZE },
{ GLX_GREEN_SIZE, EGL_GREEN_SIZE },
{ GLX_BLUE_SIZE, EGL_BLUE_SIZE },
{ GLX_ALPHA_SIZE, EGL_ALPHA_SIZE },
{ GLX_DEPTH_SIZE, EGL_DEPTH_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_SAMPLES, EGL_SAMPLES },
{ GLX_FBCONFIG_ID, 0 },
/* GLX_EXT_visual_rating */
{ GLX_VISUAL_CAVEAT_EXT, EGL_CONFIG_CAVEAT }
};
static EGLBoolean
convert_visual(Display *dpy, XVisualInfo *vinfo,
struct GLX_egl_config *GLX_conf)
{
int err, attr, egl_attr, val;
int err, attr, val;
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);
if (!err && val)
err = glXGetConfig(dpy, vinfo, GLX_RGBA, &val);
if (err || !val)
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++) {
EGLint egl_attr, egl_val;
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);
if (err) {
if (err == GLX_BAD_ATTRIBUTE) {
@ -265,41 +350,26 @@ convert_visual(Display *dpy, XVisualInfo *vinfo,
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);
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;
return (err) ? EGL_FALSE : EGL_TRUE;
}
@ -307,30 +377,31 @@ static void
fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf)
{
_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) {
/* 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 */
if (GLX_dpy->have_pbuffer)
surface_type |= EGL_PBUFFER_BIT;
SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type);
conf->SurfaceType |= EGL_PBUFFER_BIT;
}
/* no visual attribs unless window bit is set */
if (!(surface_type & EGL_WINDOW_BIT)) {
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, 0);
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_NONE);
if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
conf->NativeVisualID = 0;
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 */
r = GET_CONFIG_ATTRIB(conf, EGL_RED_SIZE);
g = GET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE);
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);
conf->BufferSize =
conf->RedSize + conf->GreenSize + conf->BlueSize + conf->AlphaSize;
}
@ -381,7 +452,7 @@ create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy,
memcpy(GLX_conf, &template, sizeof(template));
GLX_conf->index = i;
_eglAddConfig(dpy, &GLX_conf->Base);
_eglLinkConfig(&GLX_conf->Base);
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_rsurf = GLX_egl_surface(rsurf);
struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
_EGLContext *old_ctx;
_EGLSurface *old_dsurf, *old_rsurf;
GLXDrawable ddraw, rdraw;
GLXContext cctx;
EGLBoolean ret = EGL_FALSE;
(void) drv;
/* bind the new context and return the "orphaned" one */
if (!_eglBindContext(&ctx, &dsurf, &rsurf))
/* make new bindings */
if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
return EGL_FALSE;
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);
if (ret) {
if (dsurf && !_eglIsSurfaceLinked(dsurf))
destroy_surface(disp, dsurf);
if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(rsurf))
destroy_surface(disp, rsurf);
if (_eglPutSurface(old_dsurf))
destroy_surface(disp, old_dsurf);
if (_eglPutSurface(old_rsurf))
destroy_surface(disp, old_rsurf);
/* no destroy? */
_eglPutContext(old_ctx);
}
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;
@ -836,7 +923,7 @@ GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
{
(void) drv;
if (!_eglIsSurfaceBound(surf))
if (_eglPutSurface(surf))
destroy_surface(disp, surf);
return EGL_TRUE;

View file

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

View file

@ -28,6 +28,7 @@ if env['platform'] != 'winddk':
'eglcurrent.c',
'egldisplay.c',
'egldriver.c',
'eglfallbacks.c',
'eglglobals.c',
'eglimage.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);
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);
}
@ -515,7 +515,7 @@ eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
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);
}
@ -536,7 +536,7 @@ eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
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);
}
@ -555,7 +555,7 @@ eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
_EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
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);
}
@ -648,11 +648,12 @@ eglSwapInterval(EGLDisplay dpy, EGLint interval)
_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);
surf = ctx->DrawSurface;
if (!_eglIsSurfaceLinked(surf))
if (_eglGetSurfaceHandle(surf) == EGL_NO_SURFACE)
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
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);
/* 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);
ret = drv->API.SwapBuffers(drv, disp, surf);
@ -714,7 +716,8 @@ eglWaitClient(void)
_eglLockMutex(&disp->Mutex);
/* 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);
/* a valid current context implies an initialized current display */
@ -763,7 +766,8 @@ eglWaitNative(EGLint engine)
_eglLockMutex(&disp->Mutex);
/* 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);
/* 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);
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);
}
@ -1235,7 +1239,7 @@ eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype,
surf = drv->API.CreatePbufferFromClientBuffer(drv, disp, buftype, buffer,
conf, attrib_list);
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE;
ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
RETURN_EGL_EVAL(disp, ret);
}
@ -1298,7 +1302,7 @@ eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
img = drv->API.CreateImageKHR(drv,
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);
}
@ -1344,7 +1348,7 @@ eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
RETURN_EGL_EVAL(disp, EGL_NO_SYNC_KHR);
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);
}
@ -1437,7 +1441,8 @@ eglSwapBuffersRegionNOK(EGLDisplay dpy, EGLSurface surface,
RETURN_EGL_EVAL(disp, EGL_FALSE);
/* 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);
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);
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);
}

View file

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

View file

@ -6,69 +6,103 @@
#include "egltypedefs.h"
#define _EGL_CONFIG_FIRST_ATTRIB EGL_BUFFER_SIZE
#define _EGL_CONFIG_LAST_ATTRIB EGL_CONFORMANT
#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
/* update _eglValidationTable and _eglOffsetOfConfig before updating this
* struct */
struct _egl_config
{
_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.
*/
#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.
* Map an EGL attribute enum to the offset of the member in _EGLConfig.
*/
static INLINE EGLint
_eglIndexConfig(const _EGLConfig *conf, EGLint key)
_eglOffsetOfConfig(EGLint attr)
{
(void) conf;
if (key >= _EGL_CONFIG_FIRST_ATTRIB &&
key < _EGL_CONFIG_FIRST_ATTRIB + _EGL_CONFIG_NUM_CONTIGUOUS_ATTRIBS)
return key - _EGL_CONFIG_FIRST_ATTRIB;
switch (key) {
case EGL_Y_INVERTED_NOK:
return _EGL_CONFIG_FIRST_EXTRA_ATTRIB;
switch (attr) {
#define ATTRIB_MAP(attr, memb) case attr: return offsetof(_EGLConfig, memb)
/* core */
ATTRIB_MAP(EGL_BUFFER_SIZE, BufferSize);
ATTRIB_MAP(EGL_ALPHA_SIZE, AlphaSize);
ATTRIB_MAP(EGL_BLUE_SIZE, BlueSize);
ATTRIB_MAP(EGL_GREEN_SIZE, GreenSize);
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:
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.
*
@ -79,9 +113,9 @@ _eglResetConfigKeys(_EGLConfig *conf, EGLint val)
static INLINE void
_eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val)
{
EGLint idx = _eglIndexConfig(conf, key);
assert(idx >= 0);
conf->Storage[idx] = val;
EGLint offset = _eglOffsetOfConfig(key);
assert(offset >= 0);
*((EGLint *) ((char *) conf + offset)) = val;
}
@ -91,9 +125,9 @@ _eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val)
static INLINE EGLint
_eglGetConfigKey(const _EGLConfig *conf, EGLint key)
{
EGLint idx = _eglIndexConfig(conf, key);
assert(idx >= 0);
return conf->Storage[idx];
EGLint offset = _eglOffsetOfConfig(key);
assert(offset >= 0);
return *((EGLint *) ((char *) conf + offset));
}
@ -102,34 +136,20 @@ _eglInitConfig(_EGLConfig *config, _EGLDisplay *dpy, EGLint id);
PUBLIC EGLConfig
_eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf);
_eglLinkConfig(_EGLConfig *conf);
extern EGLBoolean
_eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy);
extern _EGLConfig *
_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy);
/**
* Lookup a handle to find the 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.
* Return the handle of a linked config.
*/
static INLINE EGLConfig
_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
_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list);
_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
const EGLint *attrib_list);
PUBLIC EGLint

View file

@ -103,8 +103,7 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
return EGL_FALSE;
}
memset(ctx, 0, sizeof(_EGLContext));
ctx->Resource.Display = dpy;
_eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
ctx->ClientAPI = api;
ctx->Config = conf;
ctx->WindowRenderBuffer = EGL_NONE;
@ -113,13 +112,12 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
err = _eglParseContextAttribList(ctx, attrib_list);
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);
if (!(renderable_type & api_bit)) {
if (!(ctx->Config->RenderableType & api_bit)) {
_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;
}
}
@ -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
static EGLint
_eglQueryContextRenderBuffer(_EGLContext *ctx)
@ -183,7 +158,9 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
switch (attribute) {
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;
case EGL_CONTEXT_CLIENT_VERSION:
*value = c->ClientVersion;
@ -272,10 +249,6 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
if (!surfaceless && (draw == NULL || read == NULL))
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
*
@ -283,16 +256,23 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
* bound to contexts in another thread, an EGL_BAD_ACCESS error is
* generated."
*
* But it also says
* and
*
* "at most one context may be bound to a particular surface at a given
* time"
*
* The latter is more restrictive so we can check only the latter case.
*/
if ((draw && draw->CurrentContext && draw->CurrentContext != ctx) ||
(read && read->CurrentContext && read->CurrentContext != ctx))
if (ctx->Binding && ctx->Binding != t)
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 */
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
* "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
_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();
_EGLContext *newCtx = *ctx, *oldCtx;
_EGLSurface *newDraw = *draw, *newRead = *read;
_EGLContext *prev_ctx;
_EGLSurface *prev_draw, *prev_read;
if (!_eglCheckMakeCurrent(newCtx, newDraw, newRead))
if (!_eglCheckMakeCurrent(ctx, draw, read))
return EGL_FALSE;
/* increment refcounts before binding */
_eglGetContext(ctx);
_eglGetSurface(draw);
_eglGetSurface(read);
/* bind the new context */
oldCtx = _eglBindContextToThread(newCtx, t);
prev_ctx = _eglBindContextToThread(ctx, t);
/* break old bindings */
if (oldCtx) {
*ctx = oldCtx;
*draw = oldCtx->DrawSurface;
*read = oldCtx->ReadSurface;
/* break previous bindings */
if (prev_ctx) {
prev_draw = prev_ctx->DrawSurface;
prev_read = prev_ctx->ReadSurface;
if (*draw)
(*draw)->CurrentContext = NULL;
if (*read)
(*read)->CurrentContext = NULL;
if (prev_draw)
prev_draw->CurrentContext = NULL;
if (prev_read)
prev_read->CurrentContext = NULL;
oldCtx->DrawSurface = NULL;
oldCtx->ReadSurface = NULL;
prev_ctx->DrawSurface = NULL;
prev_ctx->ReadSurface = NULL;
}
else {
prev_draw = prev_read = NULL;
}
/* establish new bindings */
if (newCtx) {
if (newDraw)
newDraw->CurrentContext = newCtx;
if (newRead)
newRead->CurrentContext = newCtx;
if (ctx) {
if (draw)
draw->CurrentContext = ctx;
if (read)
read->CurrentContext = ctx;
newCtx->DrawSurface = newDraw;
newCtx->ReadSurface = newRead;
ctx->DrawSurface = draw;
ctx->ReadSurface = read;
}
/* an old context or surface is not orphaned if it is still bound */
if (*ctx == newCtx)
*ctx = NULL;
if (*draw == newDraw || *draw == newRead)
*draw = NULL;
if (*read == newDraw || *read == newRead)
*read = NULL;
assert(old_ctx && old_draw && old_read);
*old_ctx = prev_ctx;
*old_draw = prev_draw;
*old_read = prev_read;
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);
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
_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLint attribute, EGLint *value);
PUBLIC EGLBoolean
_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **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);
_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
_EGLContext **old_ctx,
_EGLSurface **old_draw, _EGLSurface **old_read);
/**
* Return true if the context is bound to a thread.
*
* The binding is considered a reference to the context. Drivers should not
* destroy a context when it is bound.
* Increment reference count for the context.
*/
static INLINE EGLBoolean
_eglIsContextBound(_EGLContext *ctx)
static INLINE _EGLContext *
_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.
*/
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;
}
@ -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 */

View file

@ -233,17 +233,53 @@ _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
/**
* Link a resource to a display.
* Initialize a display resource.
*/
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->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->Next = dpy->ResourceLists[type];
dpy->ResourceLists[type] = res;
res->Next = res->Display->ResourceLists[type];
res->Display->ResourceLists[type] = res;
_eglGetResource(res);
}
@ -270,6 +306,9 @@ _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
}
res->Next = NULL;
/* do not reset res->Display */
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 */
_EGLDisplay *Display;
EGLBoolean IsLinked;
EGLint RefCount;
/* used to link resources of the same type */
_EGLResource *Next;
@ -162,7 +163,19 @@ _eglGetDisplayHandle(_EGLDisplay *dpy)
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

View file

@ -9,18 +9,10 @@
#include <stdlib.h>
#include "eglstring.h"
#include "eglconfig.h"
#include "eglcontext.h"
#include "egldefines.h"
#include "egldisplay.h"
#include "egldriver.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"
#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.
*

View file

@ -80,6 +80,7 @@ extern void
_eglUnloadDrivers(void);
/* defined in eglfallbacks.c */
PUBLIC void
_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 "eglimage.h"
#include "eglcurrent.h"
#include "egllog.h"
@ -12,28 +11,57 @@
/**
* Parse the list of image attributes and return the proper error code.
*/
static EGLint
_eglParseImageAttribList(_EGLImage *img, const EGLint *attrib_list)
EGLint
_eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *dpy,
const EGLint *attrib_list)
{
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)
return EGL_SUCCESS;
return err;
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
EGLint attr = attrib_list[i++];
EGLint val = attrib_list[i];
switch (attr) {
/* EGL_KHR_image_base */
case EGL_IMAGE_PRESERVED_KHR:
img->Preserved = val;
attrs->ImagePreserved = val;
break;
/* EGL_KHR_gl_image */
case EGL_GL_TEXTURE_LEVEL_KHR:
img->GLTextureLevel = val;
attrs->GLTextureLevel = val;
break;
case EGL_GL_TEXTURE_ZOFFSET_KHR:
img->GLTextureZOffset = val;
attrs->GLTextureZOffset = val;
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:
/* unknown attrs are ignored */
break;
@ -50,41 +78,12 @@ _eglParseImageAttribList(_EGLImage *img, const EGLint *attrib_list)
EGLBoolean
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy, const EGLint *attrib_list)
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy)
{
EGLint err;
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");
_eglInitResource(&img->Resource, sizeof(*img), dpy);
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 */

View file

@ -6,6 +6,23 @@
#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.
*/
@ -13,34 +30,48 @@ struct _egl_image
{
/* An image is a display resource */
_EGLResource Resource;
EGLBoolean Preserved;
EGLint GLTextureLevel;
EGLint GLTextureZOffset;
};
PUBLIC EGLint
_eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *dpy,
const EGLint *attrib_list);
PUBLIC EGLBoolean
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy, const EGLint *attrib_list);
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);
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy);
/**
* 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.
*/
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;
}
@ -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 */

View file

@ -158,32 +158,3 @@ _eglQueryString(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name)
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);
extern EGLBoolean
_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx);
extern EGLBoolean
_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine);
#endif /* EGLMISC_INCLUDED */

View file

@ -3,11 +3,9 @@
#include <string.h>
#include "egldisplay.h"
#include "egldriver.h"
#include "eglmode.h"
#include "eglcurrent.h"
#include "eglscreen.h"
#include "eglstring.h"
#ifdef EGL_MESA_screen_surface
@ -31,56 +29,24 @@ _eglLookupMode(EGLModeMESA mode, _EGLDisplay *disp)
/* loop over all screens on the display */
for (scrnum = 0; scrnum < disp->Screens->Size; scrnum++) {
const _EGLScreen *scrn = disp->Screens->Elements[scrnum];
EGLint i;
/* search list of modes for handle */
for (i = 0; i < scrn->NumModes; i++) {
if (scrn->Modes[i].Handle == mode) {
return scrn->Modes + i;
}
}
}
EGLint idx;
return NULL;
}
/**
* 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
/*
* the mode ids of a screen ranges from scrn->Handle to scrn->Handle +
* scrn->NumModes
*/
_EGLMode *
_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height,
EGLint refreshRate, const char *name)
{
EGLint n;
_EGLMode *newModes;
if (mode >= scrn->Handle &&
mode < scrn->Handle + _EGL_SCREEN_MAX_MODES) {
idx = mode - scrn->Handle;
assert(screen);
assert(width > 0);
assert(height > 0);
assert(refreshRate > 0);
assert(idx < scrn->NumModes && scrn->Modes[idx].Handle == mode);
n = screen->NumModes;
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;
return &scrn->Modes[idx];
}
else {
}
return NULL;
}
}
/**

View file

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

View file

@ -18,7 +18,6 @@
#include "egldisplay.h"
#include "eglcurrent.h"
#include "eglmode.h"
#include "eglconfig.h"
#include "eglsurface.h"
#include "eglscreen.h"
#include "eglmutex.h"
@ -42,7 +41,8 @@ _eglAllocScreenHandle(void)
EGLScreenMESA s;
_eglLockMutex(&_eglNextScreenHandleMutex);
s = _eglNextScreenHandle++;
s = _eglNextScreenHandle;
_eglNextScreenHandle += _EGL_SCREEN_MAX_MODES;
_eglUnlockMutex(&_eglNextScreenHandleMutex);
return s;
@ -53,16 +53,54 @@ _eglAllocScreenHandle(void)
* Initialize an _EGLScreen object to default values.
*/
void
_eglInitScreen(_EGLScreen *screen)
_eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes)
{
memset(screen, 0, sizeof(_EGLScreen));
screen->Display = dpy;
screen->NumModes = num_modes;
screen->StepX = 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 *
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
@ -74,39 +112,21 @@ _eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
for (i = 0; i < display->Screens->Size; i++) {
_EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i];
if (scr->Handle == screen)
if (scr->Handle == screen) {
assert(scr->Display == display);
return scr;
}
}
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
_eglFlattenScreen(void *elem, void *buffer)
{
_EGLScreen *scr = (_EGLScreen *) elem;
EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
*handle = scr->Handle;
*handle = _eglGetScreenHandle(scr);
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.
*/
@ -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 */

View file

@ -8,6 +8,9 @@
#ifdef EGL_MESA_screen_surface
#define _EGL_SCREEN_MAX_MODES 16
/**
* Per-screen information.
* Note that an EGL screen doesn't have a size. A screen may be set to
@ -19,6 +22,8 @@
*/
struct _egl_screen
{
_EGLDisplay *Display;
EGLScreenMESA Handle; /* The public/opaque handle which names this object */
_EGLMode *CurrentMode;
@ -33,41 +38,35 @@ struct _egl_screen
PUBLIC void
_eglInitScreen(_EGLScreen *screen);
_eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes);
PUBLIC EGLScreenMESA
_eglLinkScreen(_EGLScreen *screen);
extern _EGLScreen *
_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
_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
_eglScreenPositionMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, EGLint x, EGLint y);
extern EGLBoolean
_eglQueryDisplayMESA(_EGLDriver *drv, _EGLDisplay *dpy, EGLint attribute, EGLint *value);
extern EGLBoolean
_eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
_EGLScreen *scrn, _EGLSurface **surface);
@ -81,14 +80,6 @@ extern EGLBoolean
_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 */

View file

@ -17,12 +17,12 @@
static void
_eglClampSwapInterval(_EGLSurface *surf, EGLint interval)
{
EGLint bound = GET_CONFIG_ATTRIB(surf->Config, EGL_MAX_SWAP_INTERVAL);
EGLint bound = surf->Config->MaxSwapInterval;
if (interval >= bound) {
interval = bound;
}
else {
bound = GET_CONFIG_ATTRIB(surf->Config, EGL_MIN_SWAP_INTERVAL);
bound = surf->Config->MinSwapInterval;
if (interval < bound)
interval = bound;
}
@ -263,14 +263,13 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
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 */
_eglError(EGL_BAD_CONFIG, func);
return EGL_FALSE;
}
memset(surf, 0, sizeof(_EGLSurface));
surf->Resource.Display = dpy;
_eglInitResource(&surf->Resource, sizeof(*surf), dpy);
surf->Type = type;
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
_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
EGLint attribute, EGLint *value)
@ -333,7 +314,7 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
*value = surface->Height;
break;
case EGL_CONFIG_ID:
*value = GET_CONFIG_ATTRIB(surface->Config, EGL_CONFIG_ID);
*value = surface->Config->ConfigID;
break;
case EGL_LARGEST_PBUFFER:
*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.
*/
@ -445,7 +381,7 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
switch (attribute) {
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))) {
err = EGL_BAD_PARAMETER;
break;
@ -457,7 +393,7 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
break;
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))
err = EGL_BAD_MATCH;
break;
@ -474,7 +410,7 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
case EGL_BUFFER_DESTROYED:
break;
case EGL_BUFFER_PRESERVED:
confval = GET_CONFIG_ATTRIB(surface->Config, EGL_SURFACE_TYPE);
confval = surface->Config->SurfaceType;
if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
err = EGL_BAD_MATCH;
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
_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
EGLint interval)
@ -577,24 +479,3 @@ _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
_eglClampSwapInterval(surf, interval);
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);
extern EGLBoolean
_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf);
extern EGLBoolean
_eglCopyBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLNativePixmapType target);
extern EGLBoolean
_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
_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);
extern EGLBoolean
_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint buffer);
extern EGLBoolean
_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.
*
* The binding is considered a reference to the surface. Drivers should not
* destroy a surface when it is bound.
* Increment reference count for the surface.
*/
static INLINE EGLBoolean
_eglIsSurfaceBound(_EGLSurface *surf)
static INLINE _EGLSurface *
_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.
*/
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;
}
@ -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 */

View file

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

View file

@ -28,38 +28,41 @@ _eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type,
const EGLint *attrib_list);
extern _EGLSync *
_eglCreateSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy,
EGLenum type, const EGLint *attrib_list);
extern EGLBoolean
_eglDestroySyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync);
extern EGLint
_eglClientWaitSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
EGLint flags, EGLTimeKHR timeout);
extern EGLBoolean
_eglSignalSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
EGLenum mode);
extern EGLBoolean
_eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
EGLint attribute, EGLint *value);
/**
* Link a sync to a display and return the handle of the link.
* 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.
*/
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;
}
@ -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 */

View file

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

View file

@ -173,6 +173,7 @@ GALLIVM_SOURCES = \
gallivm/lp_bld_struct.c \
gallivm/lp_bld_swizzle.c \
gallivm/lp_bld_tgsi_aos.c \
gallivm/lp_bld_tgsi_info.c \
gallivm/lp_bld_tgsi_soa.c \
gallivm/lp_bld_type.c \
draw/draw_llvm.c \
@ -207,16 +208,16 @@ include ../Makefile.template
indices/u_indices_gen.c: indices/u_indices_gen.py
python $< > $@
$(PYTHON2) $< > $@
indices/u_unfilled_gen.c: indices/u_unfilled_gen.py
python $< > $@
$(PYTHON2) $< > $@
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
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
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_swizzle.c',
'gallivm/lp_bld_tgsi_aos.c',
'gallivm/lp_bld_tgsi_info.c',
'gallivm/lp_bld_tgsi_soa.c',
'gallivm/lp_bld_type.c',
'draw/draw_llvm.c',

View file

@ -335,6 +335,7 @@ draw_set_mapped_constant_buffer(struct draw_context *draw,
case PIPE_SHADER_VERTEX:
draw->pt.user.vs_constants[slot] = buffer;
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);
break;
case PIPE_SHADER_GEOMETRY:
@ -721,9 +722,9 @@ draw_set_mapped_texture(struct draw_context *draw,
unsigned sampler_idx,
uint32_t width, uint32_t height, uint32_t depth,
uint32_t last_level,
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
const void *data[DRAW_MAX_TEXTURE_LEVELS])
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
const void *data[PIPE_MAX_TEXTURE_LEVELS])
{
#ifdef HAVE_LLVM
if(draw->llvm)

View file

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

View file

@ -31,6 +31,9 @@
#include "draw_vs.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_type.h"
#include "gallivm/lp_bld_flow.h"
@ -43,7 +46,6 @@
#include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_dump.h"
#include "util/u_cpu_detect.h"
#include "util/u_math.h"
#include "util/u_pointer.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_LAST_LEVEL] = LLVMInt32Type();
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] =
LLVMArrayType(LLVMInt32Type(), DRAW_MAX_TEXTURE_LEVELS);
LLVMArrayType(LLVMInt32Type(), PIPE_MAX_TEXTURE_LEVELS);
elem_types[DRAW_JIT_TEXTURE_DATA] =
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_MAX_LOD] = LLVMFloatType();
elem_types[DRAW_JIT_TEXTURE_LOD_BIAS] = LLVMFloatType();
@ -128,12 +130,14 @@ init_globals(struct draw_llvm *llvm)
/* struct draw_jit_context */
{
LLVMTypeRef elem_types[3];
LLVMTypeRef elem_types[5];
LLVMTypeRef context_type;
elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */
elem_types[1] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */
elem_types[2] = LLVMArrayType(texture_type,
elem_types[1] = LLVMPointerType(LLVMFloatType(), 0); /* gs_constants */
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 */
context_type = LLVMStructType(elem_types, Elements(elem_types), 0);
@ -142,6 +146,8 @@ init_globals(struct draw_llvm *llvm)
llvm->target, context_type, 0);
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, gs_constants,
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,
llvm->target, context_type,
DRAW_JIT_CTX_TEXTURES);
@ -267,13 +273,7 @@ draw_llvm_create(struct draw_context *draw)
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);
}
LLVMAddGVNPass(llvm->pass);
} else {
/* We need at least this pass to prevent the backends to fail in
@ -421,7 +421,7 @@ generate_fetch(LLVMBuilderRef builder,
"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, "");
index = LLVMBuildSelect(builder, cond, index, vb_max_index, "");
@ -550,19 +550,28 @@ static void
store_aos(LLVMBuilderRef builder,
LLVMValueRef io_ptr,
LLVMValueRef index,
LLVMValueRef value)
LLVMValueRef value,
LLVMValueRef clipmask)
{
LLVMValueRef id_ptr = draw_jit_header_id(builder, io_ptr);
LLVMValueRef data_ptr = draw_jit_header_data(builder, io_ptr);
LLVMValueRef indices[3];
LLVMValueRef val, shift;
indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
indices[1] = index;
indices[2] = LLVMConstInt(LLVMInt32Type(), 0, 0);
/* undefined vertex */
LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(),
0xffff, 0), id_ptr);
/* initialize vertex id:16 = 0xffff, pad:3 = 0, edgeflag:1 = 1 */
val = LLVMConstInt(LLVMInt32Type(), 0xffff1, 0);
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
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 aos[NUM_CHANNELS],
int attrib,
int num_outputs)
int num_outputs,
LLVMValueRef clipmask)
{
LLVMValueRef attr_index = LLVMConstInt(LLVMInt32Type(), attrib, 0);
LLVMValueRef ind0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
@ -625,6 +635,7 @@ store_aos_array(LLVMBuilderRef builder,
LLVMValueRef ind2 = LLVMConstInt(LLVMInt32Type(), 2, 0);
LLVMValueRef ind3 = LLVMConstInt(LLVMInt32Type(), 3, 0);
LLVMValueRef io0_ptr, io1_ptr, io2_ptr, io3_ptr;
LLVMValueRef clipmask0, clipmask1, clipmask2, clipmask3;
debug_assert(NUM_CHANNELS == 4);
@ -637,21 +648,31 @@ store_aos_array(LLVMBuilderRef builder,
io3_ptr = LLVMBuildGEP(builder, io_ptr,
&ind3, 1, "");
#if DEBUG_STORE
lp_build_printf(builder, " io = %p, indexes[%d, %d, %d, %d]\n",
io_ptr, ind0, ind1, ind2, ind3);
#endif
clipmask0 = LLVMBuildExtractElement(builder, clipmask,
ind0, "");
clipmask1 = LLVMBuildExtractElement(builder, clipmask,
ind1, "");
clipmask2 = LLVMBuildExtractElement(builder, clipmask,
ind2, "");
clipmask3 = LLVMBuildExtractElement(builder, clipmask,
ind3, "");
store_aos(builder, io0_ptr, attr_index, aos[0]);
store_aos(builder, io1_ptr, attr_index, aos[1]);
store_aos(builder, io2_ptr, attr_index, aos[2]);
store_aos(builder, io3_ptr, attr_index, aos[3]);
#if DEBUG_STORE
lp_build_printf(builder, "io = %p, indexes[%d, %d, %d, %d]\n, clipmask0 = %x, clipmask1 = %x, clipmask2 = %x, clipmask3 = %x\n",
io_ptr, ind0, ind1, ind2, ind3, clipmask0, clipmask1, clipmask2, clipmask3);
#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
convert_to_aos(LLVMBuilderRef builder,
LLVMValueRef io,
LLVMValueRef (*outputs)[NUM_CHANNELS],
LLVMValueRef clipmask,
int num_outputs,
int max_vertices)
{
@ -680,13 +701,305 @@ convert_to_aos(LLVMBuilderRef builder,
io,
aos,
attrib,
num_outputs);
num_outputs,
clipmask);
}
#if DEBUG_STORE
lp_build_printf(builder, " # storing end\n");
#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
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];
void *code;
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[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[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);
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);
/* 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 */
sampler = draw_llvm_sampler_soa_create(
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 aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } };
LLVMValueRef io;
LLVMValueRef clipmask; /* holds the clipmask value */
const LLVMValueRef (*ptr_aos)[NUM_CHANNELS];
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,
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,
max_vertices);
}
lp_build_loop_end_cond(builder, end, step, LLVMIntUGE, &lp_loop);
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);
#endif
LLVMBuildRetVoid(builder);
ret = LLVMBuildLoad(builder, ret_ptr,"");
LLVMBuildRet(builder, ret);
LLVMDisposeBuilder(builder);
@ -870,6 +1221,11 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
LLVMValueRef fetch_max;
void *code;
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[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[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",
func_type);
variant->function_elts = LLVMAddFunction(llvm->module, "draw_llvm_shader_elts", func_type);
LLVMSetFunctionCallConv(variant->function_elts, LLVMCCallConv);
for(i = 0; i < Elements(arg_types); ++i)
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),
"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);
{
LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
LLVMValueRef aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } };
LLVMValueRef io;
LLVMValueRef clipmask; /* holds the clipmask value */
const LLVMValueRef (*ptr_aos)[NUM_CHANNELS];
io_itr = lp_loop.counter;
@ -980,10 +1340,40 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
context_ptr,
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,
max_vertices);
}
lp_build_loop_end_cond(builder, fetch_count, step, LLVMIntUGE, &lp_loop);
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);
#endif
LLVMBuildRetVoid(builder);
ret = LLVMBuildLoad(builder, ret_ptr,"");
LLVMBuildRet(builder, ret);
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;
/* 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
* nr_samplers. Not yet trying to compact away holes in the
* sampler array.
@ -1066,9 +1467,9 @@ draw_llvm_set_mapped_texture(struct draw_context *draw,
unsigned sampler_idx,
uint32_t width, uint32_t height, uint32_t depth,
uint32_t last_level,
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
const void *data[DRAW_MAX_TEXTURE_LEVELS])
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
const void *data[PIPE_MAX_TEXTURE_LEVELS])
{
unsigned j;
struct draw_jit_texture *jit_tex;

View file

@ -41,7 +41,6 @@
#include <llvm-c/Target.h>
#include <llvm-c/ExecutionEngine.h>
#define DRAW_MAX_TEXTURE_LEVELS 13 /* 4K x 4K for now */
struct draw_llvm;
struct llvm_vertex_shader;
@ -52,9 +51,9 @@ struct draw_jit_texture
uint32_t height;
uint32_t depth;
uint32_t last_level;
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS];
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS];
const void *data[DRAW_MAX_TEXTURE_LEVELS];
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS];
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS];
const void *data[PIPE_MAX_TEXTURE_LEVELS];
float min_lod;
float max_lod;
float lod_bias;
@ -97,7 +96,8 @@ struct draw_jit_context
{
const float *vs_constants;
const float *gs_constants;
float (*planes) [12][4];
float *viewport;
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) \
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) \
lp_build_struct_get_ptr(_builder, _ptr, DRAW_JIT_CTX_TEXTURES, "textures")
#define draw_jit_header_id(_builder, _ptr) \
lp_build_struct_get_ptr(_builder, _ptr, 0, "id")
#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) \
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")
typedef void
typedef int
(*draw_jit_vert_func)(struct draw_jit_context *context,
struct vertex_header *io,
const char *vbuffers[PIPE_MAX_ATTRIBS],
@ -147,7 +151,7 @@ typedef void
unsigned instance_id);
typedef void
typedef int
(*draw_jit_vert_func_elts)(struct draw_jit_context *context,
struct vertex_header *io,
const char *vbuffers[PIPE_MAX_ATTRIBS],
@ -159,8 +163,16 @@ typedef void
struct draw_llvm_variant_key
{
unsigned nr_vertex_elements:16;
unsigned nr_samplers:16;
unsigned nr_vertex_elements:8;
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:
*/
@ -290,8 +302,8 @@ draw_llvm_set_mapped_texture(struct draw_context *draw,
unsigned sampler_idx,
uint32_t width, uint32_t height, uint32_t depth,
uint32_t last_level,
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
const void *data[DRAW_MAX_TEXTURE_LEVELS]);
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
const void *data[PIPE_MAX_TEXTURE_LEVELS]);
#endif

View file

@ -169,6 +169,9 @@ struct draw_context
unsigned vs_constants_size[PIPE_MAX_CONSTANT_BUFFERS];
const void *gs_constants[PIPE_MAX_CONSTANT_BUFFERS];
unsigned gs_constants_size[PIPE_MAX_CONSTANT_BUFFERS];
/* pointer to planes */
float (*planes)[12][4];
} user;
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.
* \sa draw_arrays_instanced
@ -395,6 +473,12 @@ draw_vbo(struct draw_context *draw,
for (instance = 0; instance < info->instance_count; 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);
}
}
}

View file

@ -175,6 +175,11 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
draw->pt.user.vs_constants[0];
fpme->llvm->jit_context.gs_constants =
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 *vert_info;
unsigned opt = fpme->opt;
unsigned clipped = 0;
llvm_vert_info.count = fetch_info->count;
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)
fpme->current_variant->jit_func( &fpme->llvm->jit_context,
clipped = fpme->current_variant->jit_func( &fpme->llvm->jit_context,
llvm_vert_info.verts,
(const char **)draw->pt.user.vbuffer,
fetch_info->start,
@ -239,7 +245,7 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
draw->pt.vertex_buffer,
draw->instance_id);
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,
(const char **)draw->pt.user.vbuffer,
fetch_info->elts,
@ -266,6 +272,9 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
FREE(vert_info->verts);
vert_info = &gs_vert_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 */
@ -273,11 +282,11 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
vert_info,
prim_info );
if (draw_pt_post_vs_run( fpme->post_vs, vert_info )) {
if (clipped) {
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) {
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
lp_build_round_sse41(struct lp_build_context *bld,
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
* a float (vector).
* Ex: trunc(-1.5) = 1.0
* Return the integer part of a float (vector) value (== round toward zero).
* The returned value is a float (vector).
* Ex: trunc(-1.5) = -1.0
*/
LLVMValueRef
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
* an integer (vector).
* Ex: itrunc(-1.5) = 1
* Return the integer part of a float (vector) value (== round toward zero).
* The returned value is an integer (vector).
* Ex: itrunc(-1.5) = -1
*/
LLVMValueRef
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));
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)) {
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_fpart)
{
const struct lp_type type = bld->type;
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[
* These coefficients can be generate with
@ -2333,7 +2454,10 @@ lp_build_log2(struct lp_build_context *bld,
/**
* 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
*/
@ -2341,35 +2465,21 @@ LLVMValueRef
lp_build_fast_log2(struct lp_build_context *bld,
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 fpart;
assert(lp_check_value(bld->type, x));
assert(type.floating);
x = LLVMBuildBitCast(bld->builder, x, int_vec_type, "");
assert(bld->type.floating);
/* ipart = floor(log2(x)) - 1 */
ipart = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
ipart = LLVMBuildAnd(bld->builder, ipart, lp_build_const_int_vec(type, 255), "");
ipart = LLVMBuildSub(bld->builder, ipart, lp_build_const_int_vec(type, 128), "");
ipart = LLVMBuildSIToFP(bld->builder, ipart, vec_type, "");
ipart = lp_build_extract_exponent(bld, x, -1);
ipart = LLVMBuildSIToFP(bld->builder, ipart, bld->vec_type, "");
/* fpart = 1.0 + frac(x) */
fpart = LLVMBuildAnd(bld->builder, x, mantmask, "");
fpart = LLVMBuildOr(bld->builder, fpart, one, "");
fpart = LLVMBuildBitCast(bld->builder, fpart, vec_type, "");
/* fpart = x / 2**ipart */
fpart = lp_build_extract_mantissa(bld, x);
/* floor(log2(x)) + frac(x) */
/* ipart + fpart */
return LLVMBuildFAdd(bld->builder, ipart, fpart, "");
}
@ -2383,27 +2493,18 @@ LLVMValueRef
lp_build_ilog2(struct lp_build_context *bld,
LLVMValueRef x)
{
const struct lp_type type = bld->type;
LLVMTypeRef int_vec_type = bld->int_vec_type;
unsigned mantissa = lp_mantissa(type);
LLVMValueRef sqrt2 = lp_build_const_vec(type, 1.4142135623730951);
LLVMValueRef sqrt2 = lp_build_const_vec(bld->type, M_SQRT2);
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 = LLVMBuildFMul(bld->builder, x, sqrt2, "");
x = LLVMBuildBitCast(bld->builder, x, int_vec_type, "");
/* ipart = floor(log2(x) + 0.5) */
ipart = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
ipart = LLVMBuildAnd(bld->builder, ipart, lp_build_const_int_vec(type, 255), "");
ipart = LLVMBuildSub(bld->builder, ipart, lp_build_const_int_vec(type, 127), "");
ipart = lp_build_extract_exponent(bld, x, 0);
return ipart;
}

View file

@ -214,6 +214,15 @@ LLVMValueRef
lp_build_exp2(struct lp_build_context *bld,
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
lp_build_log2(struct lp_build_context *bld,
LLVMValueRef a);
@ -226,7 +235,6 @@ LLVMValueRef
lp_build_ilog2(struct lp_build_context *bld,
LLVMValueRef x);
void
lp_build_exp2_approx(struct lp_build_context *bld,
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);
LLVMValueRef res;
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 mask;
double scale;
double bias;
assert(src_type.floating);
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);
ubound = (1ULL << dst_width);
mask = ubound - 1;
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 = LLVMBuildFAdd(builder, res, lp_build_const_vec(src_type, bias), "");
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), "");
}
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;
}
@ -178,6 +224,16 @@ lp_build_unsigned_norm_to_float(LLVMBuilderRef builder,
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);
n = MIN2(mantissa, src_width);
@ -257,7 +313,9 @@ lp_build_conv(LLVMBuilderRef builder,
dst_type.sign == 0 &&
dst_type.norm == 1 &&
dst_type.width == 8 &&
dst_type.length == 16)
dst_type.length == 16 &&
util_cpu_caps.has_sse2)
{
int i;
@ -296,23 +354,7 @@ lp_build_conv(LLVMBuilderRef builder,
c = LLVMBuildFMul(builder, src[2], 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;
bld.builder = builder;
@ -329,7 +371,7 @@ lp_build_conv(LLVMBuilderRef builder,
src_int2 = lp_build_iround(&bld, c);
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);
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);

View file

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

View file

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

View file

@ -38,273 +38,15 @@
#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.
*/
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.
* Insert a new block, right where builder is pointing to.
*
* Besides keeping track of the control flow construct themselves we also
* need to keep track of variables in order to generate SSA Phi values.
*/
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.
* This is useful important not only for aesthetic reasons, but also for
* performance reasons, as frequently run blocks should be laid out next to
* each other and fall-throughs maximized.
*
* 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
* 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
* skip to the end of the block if the condition is false.
*/
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;
LLVMBuilderRef builder;
unsigned i;
skip = &lp_build_flow_push(flow, LP_BUILD_FLOW_SKIP)->skip;
if(!skip)
return;
skip->builder = builder;
/* create new basic block */
skip->block = lp_build_flow_insert_block(flow);
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);
skip->block = lp_build_insert_new_block(skip->builder, "skip");
}
@ -388,83 +96,50 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
* skip block if the condition is true.
*/
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)
{
struct lp_build_flow_skip *skip;
LLVMBasicBlockRef current_block;
LLVMBasicBlockRef new_block;
unsigned i;
skip = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SKIP)->skip;
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);
}
new_block = lp_build_insert_new_block(skip->builder, "");
/* 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
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 */
LLVMBuildBr(flow->builder, skip->block);
LLVMPositionBuilderAtEnd(flow->builder, skip->block);
FREE(skip->phi);
LLVMBuildBr(skip->builder, skip->block);
LLVMPositionBuilderAtEnd(skip->builder, skip->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)
{
LLVMBuilderRef builder = mask->flow->builder;
LLVMBuilderRef builder = mask->skip.builder;
LLVMValueRef value;
LLVMValueRef cond;
value = lp_build_mask_value(mask);
/* cond = (mask == 0) */
cond = LLVMBuildICmp(builder,
LLVMIntEQ,
LLVMBuildBitCast(builder, mask->value, mask->reg_type, ""),
LLVMBuildBitCast(builder, value, mask->reg_type, ""),
LLVMConstNull(mask->reg_type),
"");
/* 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
lp_build_mask_begin(struct lp_build_mask_context *mask,
struct lp_build_flow_context *flow,
LLVMBuilderRef builder,
struct lp_type type,
LLVMValueRef value)
{
memset(mask, 0, sizeof *mask);
mask->flow = flow;
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);
lp_build_flow_scope_declare(flow, &mask->value);
lp_build_flow_skip_begin(flow);
LLVMBuildStore(builder, value, mask->var);
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,
LLVMValueRef value)
{
mask->value = LLVMBuildAnd( mask->flow->builder, mask->value, value, "");
lp_build_mask_check(mask);
value = LLVMBuildAnd(mask->skip.builder,
lp_build_mask_value(mask),
value, "");
LLVMBuildStore(mask->skip.builder, value, mask->var);
}
@ -516,9 +198,8 @@ lp_build_mask_update(struct lp_build_mask_context *mask,
LLVMValueRef
lp_build_mask_end(struct lp_build_mask_context *mask)
{
lp_build_flow_skip_end(mask->flow);
lp_build_flow_scope_end(mask->flow);
return mask->value;
lp_build_flow_skip_end(&mask->skip);
return lp_build_mask_value(mask);
}
@ -528,19 +209,47 @@ lp_build_loop_begin(LLVMBuilderRef builder,
LLVMValueRef start,
struct lp_build_loop_state *state)
{
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
LLVMValueRef function = LLVMGetBasicBlockParent(block);
state->block = lp_build_insert_new_block(builder, "loop_begin");
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);
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,
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, 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);
lp_build_loop_end_cond(builder, end, step, LLVMIntNE, state);
}
@ -616,24 +277,16 @@ lp_build_loop_end_cond(LLVMBuilderRef builder,
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);
// 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_if(ctx, builder, cond);
LLVMBuildStore(LLVMBuildAdd(1, 2), x);
lp_build_else(ctx);
x = LLVMAdd(2, 3);
LLVMBuildStore(LLVMBuildAdd(2, 3). x);
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.
*/
void
lp_build_if(struct lp_build_if_state *ctx,
struct lp_build_flow_context *flow,
lp_build_if(struct lp_build_if_state *ifthen,
LLVMBuilderRef builder,
LLVMValueRef condition)
{
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
struct lp_build_flow_if *ifthen;
unsigned i;
memset(ctx, 0, sizeof(*ctx));
ctx->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;
memset(ifthen, 0, sizeof *ifthen);
ifthen->builder = builder;
ifthen->condition = condition;
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 */
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 */
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
*/
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;
struct lp_build_flow_if *ifthen;
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);
}
/* Append an unconditional Br(anch) instruction on the true_block */
LLVMBuildBr(ifthen->builder, ifthen->merge_block);
/* create/insert false_block before the merge block */
ifthen->false_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-false-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.
*/
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 */
LLVMBuildBr(ctx->builder, ifthen->merge_block);
LLVMBuildBr(ifthen->builder, ifthen->merge_block);
if (ifthen->false_block) {
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
/* 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.
***/
/*
* Now patch in the various branch instructions.
*/
/* 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) {
/* we have an else clause */
LLVMBuildCondBr(ctx->builder, ifthen->condition,
LLVMBuildCondBr(ifthen->builder, ifthen->condition,
ifthen->true_block, ifthen->false_block);
}
else {
/* no else clause */
LLVMBuildCondBr(ctx->builder, ifthen->condition,
LLVMBuildCondBr(ifthen->builder, ifthen->condition,
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 */
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);
LLVMBuildStore(builder, LLVMConstNull(type), res);
LLVMDisposeBuilder(first_builder);

View file

@ -41,52 +41,49 @@
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;
struct lp_build_flow_context *
lp_build_flow_create(LLVMBuilderRef builder);
/** Block to skip to */
LLVMBasicBlockRef block;
};
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
lp_build_flow_scope_begin(struct lp_build_flow_context *flow);
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,
lp_build_flow_skip_cond_break(struct lp_build_skip_context *ctx,
LLVMValueRef cond);
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_flow_context *flow;
struct lp_build_skip_context skip;
LLVMTypeRef reg_type;
LLVMValueRef value;
LLVMValueRef var;
};
void
lp_build_mask_begin(struct lp_build_mask_context *mask,
struct lp_build_flow_context *flow,
LLVMBuilderRef builder,
struct lp_type type,
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.
*/
@ -94,6 +91,9 @@ void
lp_build_mask_update(struct lp_build_mask_context *mask,
LLVMValueRef value);
void
lp_build_mask_check(struct lp_build_mask_context *mask);
LLVMValueRef
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
{
LLVMBasicBlockRef block;
LLVMValueRef counter_var;
LLVMValueRef counter;
};
@ -128,22 +129,28 @@ void
lp_build_loop_end_cond(LLVMBuilderRef builder,
LLVMValueRef end,
LLVMValueRef step,
int cond, /* LLVM condition */
LLVMIntPredicate cond,
struct lp_build_loop_state *state);
/**
* if/else/endif.
*/
struct lp_build_if_state
{
LLVMBuilderRef builder;
struct lp_build_flow_context *flow;
LLVMValueRef condition;
LLVMBasicBlockRef entry_block;
LLVMBasicBlockRef true_block;
LLVMBasicBlockRef false_block;
LLVMBasicBlockRef merge_block;
};
void
lp_build_if(struct lp_build_if_state *ctx,
struct lp_build_flow_context *flow,
LLVMBuilderRef builder,
LLVMValueRef condition);

View file

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

View file

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

View file

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

View file

@ -178,3 +178,13 @@ lp_func_delete_body(LLVMValueRef FF)
llvm::Function *func = llvm::unwrap<llvm::Function>(FF);
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_memory.h"
#include "util/u_string.h"
#include "lp_bld_const.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, "");
}
/**
* 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_printf(LLVMBuilderRef builder, const char *fmt, ...);
LLVMValueRef
lp_build_print_vec4(LLVMBuilderRef builder, const char *msg, LLVMValueRef vec);
#endif

View file

@ -81,11 +81,15 @@ LLVMValueRef
lp_build_scalar_ddx(struct lp_build_context *bld,
LLVMValueRef a)
{
LLVMValueRef idx_left = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_TOP_LEFT, 0);
LLVMValueRef idx_right = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_TOP_RIGHT, 0);
LLVMValueRef a_left = LLVMBuildExtractElement(bld->builder, a, idx_left, "");
LLVMValueRef a_right = LLVMBuildExtractElement(bld->builder, a, idx_right, "");
return lp_build_sub(bld, a_right, a_left);
LLVMTypeRef i32t = LLVMInt32Type();
LLVMValueRef idx_left = LLVMConstInt(i32t, LP_BLD_QUAD_TOP_LEFT, 0);
LLVMValueRef idx_right = LLVMConstInt(i32t, LP_BLD_QUAD_TOP_RIGHT, 0);
LLVMValueRef a_left = LLVMBuildExtractElement(bld->builder, a, idx_left, "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,
LLVMValueRef a)
{
LLVMValueRef idx_top = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_TOP_LEFT, 0);
LLVMValueRef idx_bottom = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_BOTTOM_LEFT, 0);
LLVMValueRef a_top = LLVMBuildExtractElement(bld->builder, a, idx_top, "");
LLVMValueRef a_bottom = LLVMBuildExtractElement(bld->builder, a, idx_bottom, "");
return lp_build_sub(bld, a_bottom, a_top);
LLVMTypeRef i32t = LLVMInt32Type();
LLVMValueRef idx_top = LLVMConstInt(i32t, LP_BLD_QUAD_TOP_LEFT, 0);
LLVMValueRef idx_bottom = LLVMConstInt(i32t, LP_BLD_QUAD_BOTTOM_LEFT, 0);
LLVMValueRef a_top = LLVMBuildExtractElement(bld->builder, a, idx_top, "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
* tri-linear filtering.
* Bri-linear factor. Should be greater than one.
*/
#define BRILINEAR_FACTOR 2
@ -201,8 +200,8 @@ lp_build_rho(struct lp_build_sample_context *bld,
LLVMValueRef float_size;
LLVMValueRef rho;
dsdx = LLVMBuildExtractElement(bld->builder, ddx[0], index0, "dsdx");
dsdy = LLVMBuildExtractElement(bld->builder, ddy[0], index0, "dsdy");
dsdx = ddx[0];
dsdy = ddy[0];
if (dims <= 1) {
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_y = LLVMBuildInsertElement(bld->builder, rho_y, dsdy, index0, "");
dtdx = LLVMBuildExtractElement(bld->builder, ddx[1], index0, "dtdx");
dtdy = LLVMBuildExtractElement(bld->builder, ddy[1], index0, "dtdy");
dtdx = ddx[1];
dtdy = ddy[1];
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, dtdx, index1, "");
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, dtdy, index1, "");
if (dims >= 3) {
drdx = LLVMBuildExtractElement(bld->builder, ddx[2], index0, "drdx");
drdy = LLVMBuildExtractElement(bld->builder, ddy[2], index0, "drdy");
drdx = ddx[2];
drdy = ddy[2];
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, drdx, 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.
*/
static void
lp_build_brilinear_lod(struct lp_build_sample_context *bld,
lp_build_brilinear_lod(struct lp_build_context *bld,
LLVMValueRef lod,
double factor,
LLVMValueRef *out_lod_ipart,
LLVMValueRef *out_lod_fpart)
{
struct lp_build_context *float_bld = &bld->float_bld;
LLVMValueRef lod_fpart;
float pre_offset = (factor - 0.5)/factor - 0.5;
float post_offset = 1 - factor;
double pre_offset = (factor - 0.5)/factor - 0.5;
double post_offset = 1 - factor;
if (0) {
lp_build_printf(bld->builder, "lod = %f\n", lod);
}
lod = lp_build_add(float_bld, lod,
lp_build_const_vec(float_bld->type, pre_offset));
lod = lp_build_add(bld, lod,
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,
lp_build_const_vec(float_bld->type, factor));
lod_fpart = lp_build_mul(bld, lod_fpart,
lp_build_const_vec(bld->type, factor));
lod_fpart = lp_build_add(float_bld, lod_fpart,
lp_build_const_vec(float_bld->type, post_offset));
lod_fpart = lp_build_add(bld, lod_fpart,
lp_build_const_vec(bld->type, post_offset));
/*
* 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).
* \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);
/* compute lod = log2(rho) */
if ((mip_filter == PIPE_TEX_MIPFILTER_NONE ||
mip_filter == PIPE_TEX_MIPFILTER_NEAREST) &&
!lod_bias &&
/*
* Compute lod = log2(rho)
*/
if (!lod_bias &&
!bld->static_state->lod_bias_non_zero &&
!bld->static_state->apply_max_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_fpart = bld->float_bld.zero;
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) {
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 (BRILINEAR_FACTOR > 1.0) {
lp_build_brilinear_lod(bld, lod, BRILINEAR_FACTOR,
if (!(gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR)) {
lp_build_brilinear_lod(float_bld, lod, BRILINEAR_FACTOR,
out_lod_ipart, out_lod_fpart);
}
else {
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");
}
else {
*out_lod_ipart = lp_build_iround(float_bld, lod);
}
lp_build_name(*out_lod_ipart, "lod_ipart");
return;
}
@ -630,37 +700,21 @@ lp_build_get_level_stride_vec(struct lp_build_sample_context *bld,
void
lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
LLVMValueRef ilevel,
LLVMValueRef *out_width_vec,
LLVMValueRef *out_height_vec,
LLVMValueRef *out_depth_vec,
LLVMValueRef *out_size,
LLVMValueRef *row_stride_vec,
LLVMValueRef *img_stride_vec)
{
const unsigned dims = bld->dims;
LLVMValueRef ilevel_vec;
LLVMValueRef size_vec;
LLVMTypeRef i32t = LLVMInt32Type();
ilevel_vec = lp_build_broadcast_scalar(&bld->int_size_bld, 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) {
*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,
bld->row_stride_array,
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,
bld->img_stride_array,
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() */
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, "");
{
struct lp_build_flow_context *flow_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);
lp_build_flow_scope_begin(flow_ctx);
face_s_var = lp_build_alloca(bld->builder, bld->coord_bld.vec_type, "face_s_var");
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;
*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);
lp_build_if(&if_ctx, bld->builder, arx_ge_ary_arz);
{
/* +/- X face */
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,
PIPE_TEX_FACE_POS_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);
{
struct lp_build_flow_context *flow_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, "");
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 */
LLVMValueRef sign = lp_build_sgn(float_bld, ry);
LLVMValueRef ima = lp_build_cube_ima(coord_bld, t);
face_s2 = lp_build_cube_coord(coord_bld, NULL, -1, s, ima);
face_t2 = lp_build_cube_coord(coord_bld, sign, -1, r, ima);
face2 = lp_build_cube_face(bld, ry,
*face_s = lp_build_cube_coord(coord_bld, NULL, -1, s, ima);
*face_t = lp_build_cube_coord(coord_bld, sign, -1, r, ima);
*face = lp_build_cube_face(bld, ry,
PIPE_TEX_FACE_POS_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);
{
/* +/- Z face */
LLVMValueRef sign = lp_build_sgn(float_bld, rz);
LLVMValueRef ima = lp_build_cube_ima(coord_bld, r);
face_s2 = lp_build_cube_coord(coord_bld, sign, -1, s, ima);
face_t2 = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
face2 = lp_build_cube_face(bld, rz,
*face_s = lp_build_cube_coord(coord_bld, sign, -1, s, ima);
*face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
*face = lp_build_cube_face(bld, rz,
PIPE_TEX_FACE_POS_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_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_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_build_context coord_bld;
/** Unsigned integer coordinates */
struct lp_type uint_coord_type;
struct lp_build_context uint_coord_bld;
/** Signed integer coordinates */
struct lp_type int_coord_type;
struct lp_build_context int_coord_bld;
@ -333,13 +329,29 @@ lp_build_get_const_mipmap_level(struct lp_build_sample_context *bld,
void
lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
LLVMValueRef ilevel,
LLVMValueRef *out_width_vec,
LLVMValueRef *out_height_vec,
LLVMValueRef *out_depth_vec,
LLVMValueRef *out_size_vec,
LLVMValueRef *row_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
lp_build_cube_lookup(struct lp_build_sample_context *bld,
LLVMValueRef s,

View file

@ -45,6 +45,7 @@
#include "lp_bld_const.h"
#include "lp_bld_conv.h"
#include "lp_bld_arit.h"
#include "lp_bld_bitarit.h"
#include "lp_bld_logic.h"
#include "lp_bld_swizzle.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_i)
{
struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
LLVMValueRef length_minus_one;
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) {
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, "");
else {
/* 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 = LLVMBuildURem(bld->builder, coord, length, "");
}
@ -113,7 +113,7 @@ lp_build_sample_wrap_nearest_int(struct lp_build_sample_context *bld,
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);
}
@ -146,7 +146,6 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
LLVMValueRef *i0,
LLVMValueRef *i1)
{
struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
LLVMValueRef length_minus_one;
LLVMValueRef lmask, umask, mask;
@ -188,8 +187,8 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
* multiplication.
*/
*i0 = uint_coord_bld->zero;
*i1 = uint_coord_bld->zero;
*i0 = int_coord_bld->zero;
*i1 = int_coord_bld->zero;
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 {
/* 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 = 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,
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,
lp_build_add(uint_coord_bld, *offset0, stride),
lp_build_add(int_coord_bld, *offset0, stride),
mask, "");
break;
@ -225,8 +224,8 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
mask = LLVMBuildAnd(bld->builder, lmask, umask, "");
*offset0 = lp_build_mul(uint_coord_bld, coord0, stride);
*offset1 = lp_build_add(uint_coord_bld,
*offset0 = lp_build_mul(int_coord_bld, coord0, stride);
*offset1 = lp_build_add(int_coord_bld,
*offset0,
LLVMBuildAnd(bld->builder, stride, mask, ""));
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:
default:
assert(0);
*offset0 = uint_coord_bld->zero;
*offset1 = uint_coord_bld->zero;
*offset0 = int_coord_bld->zero;
*offset1 = int_coord_bld->zero;
break;
}
}
@ -253,9 +252,7 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
*/
static void
lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
LLVMValueRef width_vec,
LLVMValueRef height_vec,
LLVMValueRef depth_vec,
LLVMValueRef int_size,
LLVMValueRef row_stride_vec,
LLVMValueRef img_stride_vec,
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;
LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type;
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_offset, offset;
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);
u8n_vec_type = lp_build_vec_type(u8n.type);
if (bld->static_state->normalized_coords) {
/* s = s * width, t = t * height */
LLVMTypeRef coord_vec_type = lp_build_vec_type(bld->coord_type);
LLVMValueRef fp_width = LLVMBuildSIToFP(bld->builder, width_vec,
coord_vec_type, "");
s = lp_build_mul(&bld->coord_bld, s, fp_width);
if (dims >= 2) {
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);
}
}
}
lp_build_extract_image_sizes(bld,
bld->int_size_type,
bld->int_coord_type,
int_size,
&width_vec,
&height_vec,
&depth_vec);
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) */
s = lp_build_mul_imm(&bld->coord_bld, s, 256);
if (dims >= 2)
t = lp_build_mul_imm(&bld->coord_bld, t, 256);
if (dims >= 3)
r = lp_build_mul_imm(&bld->coord_bld, r, 256);
}
/* convert float to int */
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, "");
/* 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);
/* 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->wrap_t,
&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) {
LLVMValueRef z_offset;
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->wrap_r,
&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) {
LLVMValueRef z_offset;
/* The r coord is the cube face in [0,5] */
z_offset = lp_build_mul(&bld->uint_coord_bld, r, img_stride_vec);
offset = lp_build_add(&bld->uint_coord_bld, offset, z_offset);
z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
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
lp_build_sample_image_linear(struct lp_build_sample_context *bld,
LLVMValueRef width_vec,
LLVMValueRef height_vec,
LLVMValueRef depth_vec,
LLVMValueRef int_size,
LLVMValueRef row_stride_vec,
LLVMValueRef img_stride_vec,
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;
LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type;
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 t_ipart, t_fpart, t_fpart_lo, t_fpart_hi;
LLVMValueRef r_ipart, r_fpart, r_fpart_lo, r_fpart_hi;
LLVMValueRef t_ipart = NULL, t_fpart = NULL, t_fpart_lo = NULL, t_fpart_hi = NULL;
LLVMValueRef r_ipart = NULL, r_fpart = NULL, r_fpart_lo = NULL, r_fpart_hi = NULL;
LLVMValueRef x_stride, y_stride, z_stride;
LLVMValueRef x_offset0, x_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);
u8n_vec_type = lp_build_vec_type(u8n.type);
if (bld->static_state->normalized_coords) {
/* s = s * width, t = t * height */
LLVMTypeRef coord_vec_type = lp_build_vec_type(bld->coord_type);
LLVMValueRef fp_width = LLVMBuildSIToFP(bld->builder, width_vec,
coord_vec_type, "");
s = lp_build_mul(&bld->coord_bld, s, fp_width);
if (dims >= 2) {
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);
}
}
lp_build_extract_image_sizes(bld,
bld->int_size_type,
bld->int_coord_type,
int_size,
&width_vec,
&height_vec,
&depth_vec);
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) */
s = lp_build_mul_imm(&bld->coord_bld, s, 256);
if (dims >= 2)
t = lp_build_mul_imm(&bld->coord_bld, t, 256);
if (dims >= 3)
r = lp_build_mul_imm(&bld->coord_bld, r, 256);
}
/* convert float to int */
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, "");
/* 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);
y_stride = row_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 (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][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);
}
}
@ -566,20 +569,20 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
&z_subcoord[0], &z_subcoord[1]);
for (y = 0; y < 2; y++) {
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[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);
}
}
}
else if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
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 (x = 0; x < 2; x++) {
/* 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);
}
}
@ -788,12 +791,8 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
LLVMValueRef colors_hi_var)
{
LLVMBuilderRef builder = bld->builder;
LLVMValueRef width0_vec;
LLVMValueRef width1_vec;
LLVMValueRef height0_vec;
LLVMValueRef height1_vec;
LLVMValueRef depth0_vec;
LLVMValueRef depth1_vec;
LLVMValueRef size0;
LLVMValueRef size1;
LLVMValueRef row_stride0_vec;
LLVMValueRef row_stride1_vec;
LLVMValueRef img_stride0_vec;
@ -806,12 +805,12 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
/* sample the first mipmap level */
lp_build_mipmap_level_sizes(bld, ilevel0,
&width0_vec, &height0_vec, &depth0_vec,
&size0,
&row_stride0_vec, &img_stride0_vec);
data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
lp_build_sample_image_nearest(bld,
width0_vec, height0_vec, depth0_vec,
size0,
row_stride0_vec, img_stride0_vec,
data_ptr0, s, t, r,
&colors0_lo, &colors0_hi);
@ -819,7 +818,7 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
else {
assert(img_filter == PIPE_TEX_FILTER_LINEAR);
lp_build_sample_image_linear(bld,
width0_vec, height0_vec, depth0_vec,
size0,
row_stride0_vec, img_stride0_vec,
data_ptr0, s, t, r,
&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) {
LLVMValueRef h16_scale = LLVMConstReal(LLVMFloatType(), 256.0);
LLVMTypeRef i32_type = LLVMIntType(32);
struct lp_build_flow_context *flow_ctx;
struct lp_build_if_state if_ctx;
LLVMValueRef need_lerp;
flow_ctx = lp_build_flow_create(builder);
lod_fpart = LLVMBuildFMul(builder, lod_fpart, h16_scale, "");
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),
"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;
@ -854,19 +850,19 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
/* sample the second mipmap level */
lp_build_mipmap_level_sizes(bld, ilevel1,
&width1_vec, &height1_vec, &depth1_vec,
&size1,
&row_stride1_vec, &img_stride1_vec);
data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
lp_build_sample_image_nearest(bld,
width1_vec, height1_vec, depth1_vec,
size1,
row_stride1_vec, img_stride1_vec,
data_ptr1, s, t, r,
&colors1_lo, &colors1_hi);
}
else {
lp_build_sample_image_linear(bld,
width1_vec, height1_vec, depth1_vec,
size1,
row_stride1_vec, img_stride1_vec,
data_ptr1, s, t, r,
&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 = 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, colors1_lo);
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);
}
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 */
/* recompute ddx, ddy using the new (s,t) face texcoords */
face_ddx[0] = lp_build_ddx(&bld->coord_bld, s);
face_ddx[1] = lp_build_ddx(&bld->coord_bld, t);
face_ddx[0] = lp_build_scalar_ddx(&bld->coord_bld, s);
face_ddx[1] = lp_build_scalar_ddx(&bld->coord_bld, t);
face_ddx[2] = NULL;
face_ddx[3] = NULL;
face_ddy[0] = lp_build_ddy(&bld->coord_bld, s);
face_ddy[1] = lp_build_ddy(&bld->coord_bld, t);
face_ddy[0] = lp_build_scalar_ddy(&bld->coord_bld, s);
face_ddy[1] = lp_build_scalar_ddy(&bld->coord_bld, t);
face_ddy[2] = NULL;
face_ddy[3] = NULL;
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
* depending on the lod being > 0 or <= 0, respectively.
*/
struct lp_build_flow_context *flow_ctx;
struct lp_build_if_state if_ctx;
LLVMValueRef minify;
flow_ctx = lp_build_flow_create(builder);
/* minify = lod >= 0.0 */
minify = LLVMBuildICmp(builder, LLVMIntSGE,
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 */
lp_build_sample_mipmap(bld,
@ -1056,8 +1067,6 @@ lp_build_sample_aos(struct lp_build_sample_context *bld,
packed_lo, packed_hi);
}
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 */
lp_build_sample_offset(&bld->uint_coord_bld,
lp_build_sample_offset(&bld->int_coord_bld,
bld->format_desc,
x, y, z, y_stride, z_stride,
&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
* 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,
@ -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;
LLVMValueRef fract, flr, isOdd;
/* fract = coord - floor(coord) */
fract = lp_build_sub(coord_bld, coord, lp_build_floor(coord_bld, coord));
/* flr = ifloor(coord); */
flr = lp_build_ifloor(coord_bld, coord);
lp_build_ifloor_fract(coord_bld, coord, &flr, &fract);
/* isOdd = flr & 1 */
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,
LLVMValueRef coord,
LLVMValueRef length,
LLVMValueRef length_f,
boolean is_pot,
unsigned wrap_mode,
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 *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 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 length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
LLVMValueRef coord0, coord1, weight;
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);
/* convert to int, compute lerp weight */
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
coord1 = lp_build_add(uint_coord_bld, coord0, uint_coord_bld->one);
/* repeat wrap */
if (is_pot) {
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
coord0 = LLVMBuildAnd(bld->builder, coord0, length_minus_one, "");
coord1 = LLVMBuildAnd(bld->builder, coord1, length_minus_one, "");
}
else {
/* 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, "");
coord1 = LLVMBuildAdd(bld->builder, coord1, bias, "");
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;
@ -288,41 +287,39 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
break;
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) {
/* clamp to [0,1] */
coord = lp_build_clamp(coord_bld, coord, coord_bld->zero, coord_bld->one);
/* mul by tex size and subtract 0.5 */
/* mul by tex size */
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);
}
else {
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);
}
/* clamp to [0, length - 0.5] */
coord = lp_build_max(coord_bld, coord, coord_bld->zero);
/* 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);
/* coord0 = max(coord0, 0) */
coord0 = lp_build_max(int_coord_bld, coord0, int_coord_bld->zero);
/* coord1 = min(coord1, length-1) */
coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
break;
}
case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
{
LLVMValueRef min, max;
LLVMValueRef min;
if (bld->static_state->normalized_coords) {
/* scale coord to length */
coord = lp_build_mul(coord_bld, coord, length_f);
}
/* clamp to [-0.5, length + 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);
/* was: clamp to [-0.5, length + 0.5], then sub 0.5 */
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 */
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
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:
{
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);
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);
/* 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);
}
break;
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
{
LLVMValueRef min, max;
coord = lp_build_abs(coord_bld, coord);
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);
}
/* clamp to [-0.5, length + 0.5] */
min = lp_build_negate(coord_bld, half);
max = lp_build_sub(coord_bld, length_f, min);
coord = lp_build_clamp(coord_bld, coord, min, max);
/* was: clamp to [-0.5, length + 0.5] then sub 0.5 */
/* skip -0.5 clamp (always positive), do sub first */
coord = lp_build_sub(coord_bld, coord, half);
coord = lp_build_min(coord_bld, coord, length_f);
/* convert to int, compute lerp 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,
LLVMValueRef coord,
LLVMValueRef length,
LLVMValueRef length_f,
boolean is_pot,
unsigned wrap_mode)
{
struct lp_build_context *coord_bld = &bld->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_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 length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
LLVMValueRef icoord;
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, "");
else {
/* 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 = LLVMBuildURem(bld->builder, icoord, length, "");
}
@ -469,7 +462,8 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
}
/* 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]. */
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);
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] */
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);
}
icoord = lp_build_ifloor(coord_bld, coord);
/* itrunc == ifloor here */
icoord = lp_build_itrunc(coord_bld, coord);
/* clamp to [0, length - 1] */
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);
}
icoord = lp_build_ifloor(coord_bld, coord);
/* itrunc == ifloor here */
icoord = lp_build_itrunc(coord_bld, coord);
/* clamp to [0, 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
lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
unsigned unit,
LLVMValueRef width_vec,
LLVMValueRef height_vec,
LLVMValueRef depth_vec,
LLVMValueRef size,
LLVMValueRef row_stride_vec,
LLVMValueRef img_stride_vec,
LLVMValueRef data_ptr,
@ -566,24 +561,45 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
LLVMValueRef colors_out[4])
{
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;
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.
*/
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->wrap_s);
lp_build_name(x, "tex.x.wrapped");
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->wrap_t);
lp_build_name(y, "tex.y.wrapped");
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->wrap_r);
lp_build_name(z, "tex.z.wrapped");
@ -617,9 +633,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
static void
lp_build_sample_image_linear(struct lp_build_sample_context *bld,
unsigned unit,
LLVMValueRef width_vec,
LLVMValueRef height_vec,
LLVMValueRef depth_vec,
LLVMValueRef size,
LLVMValueRef row_stride_vec,
LLVMValueRef img_stride_vec,
LLVMValueRef data_ptr,
@ -629,15 +643,36 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
LLVMValueRef colors_out[4])
{
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 s_fpart, t_fpart, r_fpart;
LLVMValueRef neighbors[2][2][4];
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.
*/
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->wrap_s,
&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");
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->wrap_t,
&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");
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->wrap_r,
&z0, &z1, &r_fpart);
@ -796,12 +831,8 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
LLVMValueRef *colors_out)
{
LLVMBuilderRef builder = bld->builder;
LLVMValueRef width0_vec;
LLVMValueRef width1_vec;
LLVMValueRef height0_vec;
LLVMValueRef height1_vec;
LLVMValueRef depth0_vec;
LLVMValueRef depth1_vec;
LLVMValueRef size0;
LLVMValueRef size1;
LLVMValueRef row_stride0_vec;
LLVMValueRef row_stride1_vec;
LLVMValueRef img_stride0_vec;
@ -813,12 +844,12 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
/* sample the first mipmap level */
lp_build_mipmap_level_sizes(bld, ilevel0,
&width0_vec, &height0_vec, &depth0_vec,
&size0,
&row_stride0_vec, &img_stride0_vec);
data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
lp_build_sample_image_nearest(bld, unit,
width0_vec, height0_vec, depth0_vec,
size0,
row_stride0_vec, img_stride0_vec,
data_ptr0, s, t, r,
colors0);
@ -826,7 +857,7 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
else {
assert(img_filter == PIPE_TEX_FILTER_LINEAR);
lp_build_sample_image_linear(bld, unit,
width0_vec, height0_vec, depth0_vec,
size0,
row_stride0_vec, img_stride0_vec,
data_ptr0, s, t, r,
colors0);
@ -838,35 +869,32 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
}
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
struct lp_build_flow_context *flow_ctx;
struct lp_build_if_state if_ctx;
LLVMValueRef need_lerp;
flow_ctx = lp_build_flow_create(builder);
/* need_lerp = lod_fpart > 0 */
need_lerp = LLVMBuildFCmp(builder, LLVMRealUGT,
lod_fpart,
bld->float_bld.zero,
"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 */
lp_build_mipmap_level_sizes(bld, ilevel1,
&width1_vec, &height1_vec, &depth1_vec,
&size1,
&row_stride1_vec, &img_stride1_vec);
data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
lp_build_sample_image_nearest(bld, unit,
width1_vec, height1_vec, depth1_vec,
size1,
row_stride1_vec, img_stride1_vec,
data_ptr1, s, t, r,
colors1);
}
else {
lp_build_sample_image_linear(bld, unit,
width1_vec, height1_vec, depth1_vec,
size1,
row_stride1_vec, img_stride1_vec,
data_ptr1, s, t, r,
colors1);
@ -883,8 +911,6 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
}
}
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 */
/* recompute ddx, ddy using the new (s,t) face texcoords */
face_ddx[0] = lp_build_ddx(&bld->coord_bld, s);
face_ddx[1] = lp_build_ddx(&bld->coord_bld, t);
face_ddx[0] = lp_build_scalar_ddx(&bld->coord_bld, s);
face_ddx[1] = lp_build_scalar_ddx(&bld->coord_bld, t);
face_ddx[2] = NULL;
face_ddx[3] = NULL;
face_ddy[0] = lp_build_ddy(&bld->coord_bld, s);
face_ddy[1] = lp_build_ddy(&bld->coord_bld, t);
face_ddy[0] = lp_build_scalar_ddy(&bld->coord_bld, s);
face_ddy[1] = lp_build_scalar_ddy(&bld->coord_bld, t);
face_ddy[2] = NULL;
face_ddy[3] = NULL;
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
* depending on the lod being > 0 or <= 0, respectively.
*/
struct lp_build_flow_context *flow_ctx;
struct lp_build_if_state if_ctx;
LLVMValueRef minify;
flow_ctx = lp_build_flow_create(builder);
/* minify = lod >= 0.0 */
minify = LLVMBuildICmp(builder, LLVMIntSGE,
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 */
lp_build_sample_mipmap(bld, unit,
@ -1049,8 +1072,6 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
texels);
}
lp_build_endif(&if_ctx);
lp_build_flow_destroy(flow_ctx);
}
for (chan = 0; chan < 4; ++chan) {
@ -1166,7 +1187,6 @@ lp_build_sample_soa(LLVMBuilderRef builder,
bld.float_type = lp_type_float(32);
bld.int_type = lp_type_int(32);
bld.coord_type = type;
bld.uint_coord_type = lp_uint_type(type);
bld.int_coord_type = lp_int_type(type);
bld.float_size_type = lp_type_float(32);
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.int_bld, builder, bld.int_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_size_bld, builder, bld.int_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
#include "gallivm/lp_bld.h"
#include "pipe/p_compiler.h"
#include "pipe/p_state.h"
#include "tgsi/tgsi_scan.h"
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.
*
@ -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
lp_build_tgsi_soa(LLVMBuilderRef builder,
const struct tgsi_token *tokens,

View file

@ -513,7 +513,7 @@ emit_instruction(
{
LLVMValueRef src0, src1, src2;
LLVMValueRef tmp0, tmp1;
LLVMValueRef dst0;
LLVMValueRef dst0 = NULL;
/*
* 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) {
LLVMTypeRef i32t = LLVMInt32Type();
LLVMValueRef index0 = LLVMConstInt(i32t, 0, 0);
for (i = 0; i < num_coords; i++) {
ddx[i] = emit_fetch( bld, inst, 1, i );
ddy[i] = emit_fetch( bld, inst, 2, i );
LLVMValueRef src1 = emit_fetch( bld, inst, 1, 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;
} else {
for (i = 0; i < num_coords; i++) {
ddx[i] = lp_build_ddx( &bld->base, coords[i] );
ddy[i] = lp_build_ddy( &bld->base, coords[i] );
ddx[i] = lp_build_scalar_ddx( &bld->base, coords[i] );
ddy[i] = lp_build_scalar_ddy( &bld->base, coords[i] );
}
unit = inst->Src[1].Register.Index;
}
for (i = num_coords; i < 3; i++) {
ddx[i] = bld->base.undef;
ddy[i] = bld->base.undef;
ddx[i] = LLVMGetUndef(bld->base.elem_type);
ddy[i] = LLVMGetUndef(bld->base.elem_type);
}
bld->sampler->emit_fetch_texel(bld->sampler,
@ -913,6 +917,43 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
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.
@ -920,7 +961,8 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
static void
emit_kil(
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];
LLVMValueRef terms[NUM_CHANNELS];
@ -959,8 +1001,12 @@ emit_kil(
}
}
if(mask)
if(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
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;
@ -983,10 +1030,14 @@ emit_kilp(struct lp_build_tgsi_soa_context *bld,
mask = LLVMBuildNot(bld->base.builder, bld->exec_mask.exec_mask, "kilp");
}
else {
mask = bld->base.zero;
LLVMValueRef zero = LLVMConstNull(bld->base.int_vec_type);
mask = zero;
}
lp_build_mask_update(bld->mask, mask);
if (!near_end_of_shader(bld, pc))
lp_build_mask_check(bld->mask);
}
static void
@ -1535,12 +1586,12 @@ emit_instruction(
case TGSI_OPCODE_KILP:
/* predicated kill */
emit_kilp( bld, inst );
emit_kilp( bld, inst, (*pc)-1 );
break;
case TGSI_OPCODE_KIL:
/* conditional kill */
emit_kil( bld, inst );
emit_kil( bld, inst, (*pc)-1 );
break;
case TGSI_OPCODE_PK2H:

View file

@ -97,7 +97,7 @@ void (*ppc_get_func(struct ppc_function *p))(void)
return (void (*)(void)) NULL;
else
#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"
#endif
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;
#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 (screen == NULL && strcmp(driver, "cell") == 0)
screen = cell_create_screen(winsys);
@ -60,4 +47,26 @@ sw_screen_create(struct sw_winsys *winsys)
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

View file

@ -13,20 +13,26 @@ static INLINE struct pipe_screen *
sw_screen_wrap(struct pipe_screen *screen)
{
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)
goto err;
sw_screen = sw_screen_create(sws);
if (sw_screen == screen)
sw_screen = sw_screen_create_named(sws, driver);
if (!sw_screen)
goto err_winsys;
return sw_screen;
err_winsys:
sws->destroy(sws);
return wrapper_sw_winsys_dewrap_pipe_screen(sws);
err:
return screen;
}

View file

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

View file

@ -35,6 +35,15 @@
extern "C" {
#endif
extern const char *
tgsi_file_names[TGSI_FILE_COUNT];
extern const char *
tgsi_swizzle_names[];
extern const char *
tgsi_texture_names[];
void
tgsi_dump_str(
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_index[reg] = (ubyte)fulldecl->Semantic.Index;
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->num_inputs++;
}
@ -157,9 +158,11 @@ tgsi_scan_shader(const struct tgsi_token *tokens,
/* extra info for special outputs */
if (procType == TGSI_PROCESSOR_FRAGMENT &&
fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION) {
fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION)
info->writes_z = TRUE;
}
if (procType == TGSI_PROCESSOR_FRAGMENT &&
fulldecl->Semantic.Name == TGSI_SEMANTIC_STENCIL)
info->writes_stencil = TRUE;
if (procType == TGSI_PROCESSOR_VERTEX &&
fulldecl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG) {
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_index[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_cylindrical_wrap[PIPE_MAX_SHADER_INPUTS];
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 */
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 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_key key;
@ -79,42 +106,14 @@ struct translate {
unsigned stride,
unsigned max_index );
void (PIPE_CDECL *run_elts)( struct translate *,
const unsigned *elts,
unsigned count,
unsigned instance_id,
void *output_buffer);
void (PIPE_CDECL *run_elts16)( struct translate *,
const uint16_t *elts,
unsigned count,
unsigned instance_id,
void *output_buffer);
void (PIPE_CDECL *run_elts8)( struct translate *,
const uint8_t *elts,
unsigned count,
unsigned instance_id,
void *output_buffer);
void (PIPE_CDECL *run)( struct translate *,
unsigned start,
unsigned count,
unsigned instance_id,
void *output_buffer);
run_elts_func run_elts;
run_elts16_func run_elts16;
run_elts8_func run_elts8;
run_func run;
};
#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 );
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))
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)
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)
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)
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)
goto fail;

View file

@ -38,6 +38,7 @@
#endif
#include "u_dl.h"
#include "u_pointer.h"
struct util_dl_library *
@ -58,7 +59,7 @@ util_dl_get_proc_address(struct util_dl_library *library,
const char *procname)
{
#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)
return (util_dl_proc)GetProcAddress((HMODULE)library, procname);
#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_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_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_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_X32_S8X24_USCALED , plain, 1, 1, x32, u8 , x24 , , _y__, zs
# YUV formats
# 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
'''
CopyRight = '''
/**************************************************************************
*
* 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 will print the copyright message on the top of this file
print __doc__.strip()
print CopyRight.strip()
print
print '#include "u_format_srgb.h"'
print

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
CopyRight = '''
/**************************************************************************
*
* 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 will print the copyright message on the top of this file
print __doc__.strip()
print CopyRight.strip()
print
print '#include "u_format.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
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_ */

View file

@ -118,6 +118,11 @@ __inline double __cdecl atan2(double val)
#endif
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#endif
#if defined(_MSC_VER)
#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 */
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)
@ -98,6 +188,68 @@ _mm_shuffle_epi8(__m128i a, __m128i mask)
#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_ */

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 ***/
@ -261,10 +336,19 @@ pipe_tile_raw_to_rgba(enum pipe_format format,
case PIPE_FORMAT_Z24X8_UNORM:
s8z24_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
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_X8Z24_UNORM:
z24s8_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
break;
case PIPE_FORMAT_S8X24_USCALED:
x24s8_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
break;
case PIPE_FORMAT_Z32_FLOAT:
z32f_get_tile_rgba((float *) src, w, h, dst, dst_stride);
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``,
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
it contains per-vertex data and effective vertex attribute address needs
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
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
@ -1493,6 +1499,8 @@ well.
| Z | XXX TBD | (z, z, z, 1) | (0, z, 0, 1) |
| | | [#depth-tex-mode]_ | |
+--------------------+--------------+--------------------+--------------+
| S | (s, s, s, s) | unknown | unknown |
+--------------------+--------------+--------------------+--------------+
.. [#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)

View file

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

View file

@ -370,7 +370,7 @@ galahad_screen_create(struct pipe_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;
}

View file

@ -28,8 +28,6 @@ C_SOURCES = \
lp_scene_queue.c \
lp_screen.c \
lp_setup.c \
lp_setup_coef.c \
lp_setup_coef_intrin.c \
lp_setup_line.c \
lp_setup_point.c \
lp_setup_tri.c \
@ -38,6 +36,7 @@ C_SOURCES = \
lp_state_clip.c \
lp_state_derived.c \
lp_state_fs.c \
lp_state_setup.c \
lp_state_gs.c \
lp_state_rasterizer.c \
lp_state_sampler.c \
@ -63,14 +62,14 @@ PROGS := lp_test_format \
# Need this for the lp_test_*.o files
CLEAN_EXTRA = *.o
include ../../Makefile.template
lp_test_sincos.o : sse_mathfun.h
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
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)
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
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')
lp_tile_soa_os = env.SharedObject('lp_tile_soa.c')
llvmpipe = env.ConvenienceLibrary(
@ -64,13 +58,12 @@ llvmpipe = env.ConvenienceLibrary(
'lp_setup_line.c',
'lp_setup_point.c',
'lp_setup_tri.c',
'lp_setup_coef.c',
'lp_setup_coef_intrin.c',
'lp_setup_vbuf.c',
'lp_state_blend.c',
'lp_state_clip.c',
'lp_state_derived.c',
'lp_state_fs.c',
'lp_state_setup.c',
'lp_state_gs.c',
'lp_state_rasterizer.c',
'lp_state_sampler.c',

View file

@ -48,7 +48,8 @@ lp_build_alpha_test(LLVMBuilderRef builder,
struct lp_type type,
struct lp_build_mask_context *mask,
LLVMValueRef alpha,
LLVMValueRef ref)
LLVMValueRef ref,
boolean do_branch)
{
struct lp_build_context bld;
LLVMValueRef test;
@ -60,4 +61,7 @@ lp_build_alpha_test(LLVMBuilderRef builder,
lp_build_name(test, "alpha_mask");
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_build_mask_context *mask,
LLVMValueRef alpha,
LLVMValueRef ref);
LLVMValueRef ref,
boolean do_branch);
#endif /* !LP_BLD_ALPHA_H */

View file

@ -1,6 +1,6 @@
/**************************************************************************
*
* Copyright 2009 VMware, Inc.
* Copyright 2009-2010 VMware, Inc.
* All Rights Reserved.
*
* 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 Brian Paul <jfonseca@vmware.com>
*/
#include "pipe/p_state.h"
@ -71,6 +64,7 @@
#include "gallivm/lp_bld_arit.h"
#include "gallivm/lp_bld_bitarit.h"
#include "gallivm/lp_bld_const.h"
#include "gallivm/lp_bld_conv.h"
#include "gallivm/lp_bld_logic.h"
#include "gallivm/lp_bld_flow.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) {
assert(format_desc->block.bits <= 32);
if(format_desc->channel[swizzle].normalized)
type.norm = TRUE;
assert(format_desc->channel[swizzle].normalized);
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
assert(0);
@ -333,7 +332,7 @@ lp_depth_type(const struct util_format_description *format_desc,
*/
static boolean
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;
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)
return FALSE;
*width = format_desc->channel[z_swizzle].size;
padding_right = 0;
for (chan = 0; chan < z_swizzle; ++chan)
padding_right += format_desc->channel[chan].size;
padding_left =
total_bits - (padding_right + format_desc->channel[z_swizzle].size);
total_bits - (padding_right + *width);
if (padding_left || padding_right) {
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;
}
*shift = padding_left;
*shift = padding_right;
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 counter is a pointer of the uint32 counter.
*/
static void
void
lp_build_occlusion_count(LLVMBuilderRef builder,
struct lp_type type,
LLVMValueRef maskvalue,
@ -446,33 +447,58 @@ lp_build_occlusion_count(LLVMBuilderRef builder,
* \param format_desc description of the depth/stencil surface
* \param mask the alive/dead pixel mask for the quad (vector)
* \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 facing contains float value indicating front/back facing polygon
* \param facing contains boolean value indicating front/back facing polygon
*/
void
lp_build_depth_stencil_test(LLVMBuilderRef builder,
const struct pipe_depth_state *depth,
const struct pipe_stencil_state stencil[2],
struct lp_type type,
struct lp_type z_src_type,
const struct util_format_description *format_desc,
struct lp_build_mask_context *mask,
LLVMValueRef stencil_refs[2],
LLVMValueRef z_src,
LLVMValueRef zs_dst_ptr,
LLVMValueRef face,
LLVMValueRef counter)
LLVMValueRef *zs_value,
boolean do_branch)
{
struct lp_build_context bld;
struct lp_build_context sbld;
struct lp_type z_type;
struct lp_build_context z_bld;
struct lp_build_context s_bld;
struct lp_type s_type;
unsigned z_shift = 0, z_width = 0, z_mask = 0;
LLVMValueRef zs_dst, z_dst = NULL;
LLVMValueRef stencil_vals = NULL;
LLVMValueRef z_bitmask = NULL, stencil_shift = 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;
/*
* 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 */
{
const unsigned z_swizzle = format_desc->swizzle[0];
@ -493,8 +519,8 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
}
assert(z_swizzle < 4);
assert(format_desc->block.bits == type.width);
if (type.floating) {
assert(format_desc->block.bits == z_type.width);
if (z_type.floating) {
assert(z_swizzle == 0);
assert(format_desc->channel[z_swizzle].type ==
UTIL_FORMAT_TYPE_FLOAT);
@ -505,54 +531,56 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
assert(format_desc->channel[z_swizzle].type ==
UTIL_FORMAT_TYPE_UNSIGNED);
assert(format_desc->channel[z_swizzle].normalized);
assert(!type.fixed);
assert(!type.sign);
assert(type.norm);
assert(!z_type.fixed);
}
}
/* 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 */
s_type = lp_type_int_vec(type.width);
lp_build_context_init(&sbld, builder, s_type);
s_type = lp_type_int_vec(z_type.width);
lp_build_context_init(&s_bld, builder, s_type);
/* 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, "");
lp_build_name(zs_dst, "zsbufval");
lp_build_name(zs_dst, "zs_dst");
/* Compute and apply the Z/stencil bitmasks and shifts.
*/
{
unsigned z_shift, z_mask;
unsigned s_shift, s_mask;
if (get_z_shift_and_mask(format_desc, &z_shift, &z_mask)) {
if (z_shift) {
LLVMValueRef shift = lp_build_const_int_vec(type, z_shift);
z_src = LLVMBuildLShr(builder, z_src, shift, "");
}
if (get_z_shift_and_mask(format_desc, &z_shift, &z_width, &z_mask)) {
if (z_mask != 0xffffffff) {
LLVMValueRef mask = lp_build_const_int_vec(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;
z_bitmask = lp_build_const_int_vec(z_type, z_mask);
}
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 (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_shift = shift; /* used below */
}
@ -561,48 +589,85 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
}
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, "");
}
lp_build_name(stencil_vals, "stencil");
lp_build_name(stencil_vals, "s_dst");
}
}
if (stencil[0].enabled) {
if (face) {
LLVMValueRef zero = LLVMConstReal(LLVMFloatType(), 0.0);
LLVMValueRef zero = LLVMConstInt(LLVMInt32Type(), 0, 0);
/* front_facing = face > 0.0 ? ~0 : 0 */
front_facing = LLVMBuildFCmp(builder, LLVMRealUGT, face, zero, "");
/* front_facing = face != 0 ? ~0 : 0 */
front_facing = LLVMBuildICmp(builder, LLVMIntNE, face, zero, "");
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,
bld.int_vec_type, "");
s_bld.int_vec_type, "");
}
/* convert scalar stencil refs into vectors */
stencil_refs[0] = lp_build_broadcast_scalar(&bld, stencil_refs[0]);
stencil_refs[1] = lp_build_broadcast_scalar(&bld, stencil_refs[1]);
stencil_refs[0] = lp_build_broadcast_scalar(&s_bld, stencil_refs[0]);
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,
front_facing);
/* apply stencil-fail operator */
{
LLVMValueRef s_fail_mask = lp_build_andnot(&bld, orig_mask, s_pass_mask);
stencil_vals = lp_build_stencil_op(&sbld, stencil, S_FAIL_OP,
LLVMValueRef s_fail_mask = lp_build_andnot(&s_bld, orig_mask, s_pass_mask);
stencil_vals = lp_build_stencil_op(&s_bld, stencil, S_FAIL_OP,
stencil_refs, stencil_vals,
s_fail_mask, front_facing);
}
}
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 */
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) {
/* 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.
*/
lp_build_mask_update(mask, z_pass);
if (do_branch) {
lp_build_mask_check(mask);
do_branch = FALSE;
}
}
if (depth->writemask) {
LLVMValueRef zselectmask = mask->value;
LLVMValueRef zselectmask;
/* 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 */
if (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.
* 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) {
@ -639,14 +704,14 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
LLVMValueRef z_fail_mask, z_pass_mask;
/* apply Z-fail operator */
z_fail_mask = lp_build_andnot(&bld, orig_mask, z_pass);
stencil_vals = lp_build_stencil_op(&sbld, stencil, Z_FAIL_OP,
z_fail_mask = lp_build_andnot(&z_bld, orig_mask, z_pass);
stencil_vals = lp_build_stencil_op(&s_bld, stencil, Z_FAIL_OP,
stencil_refs, stencil_vals,
z_fail_mask, front_facing);
/* apply Z-pass operator */
z_pass_mask = LLVMBuildAnd(bld.builder, orig_mask, z_pass, "");
stencil_vals = lp_build_stencil_op(&sbld, stencil, Z_PASS_OP,
z_pass_mask = LLVMBuildAnd(z_bld.builder, orig_mask, z_pass, "");
stencil_vals = lp_build_stencil_op(&s_bld, stencil, Z_PASS_OP,
stencil_refs, stencil_vals,
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
* passed the stencil test.
*/
s_pass_mask = LLVMBuildAnd(bld.builder, orig_mask, s_pass_mask, "");
stencil_vals = lp_build_stencil_op(&sbld, stencil, Z_PASS_OP,
s_pass_mask = LLVMBuildAnd(s_bld.builder, orig_mask, s_pass_mask, "");
stencil_vals = lp_build_stencil_op(&s_bld, stencil, Z_PASS_OP,
stencil_refs, stencil_vals,
s_pass_mask, front_facing);
}
/* The Z bits are already in the right place but we may need to shift the
* stencil bits before ORing Z with Stencil to make the final pixel value.
*/
/* Put Z and ztencil bits in the right place */
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)
stencil_vals = LLVMBuildShl(bld.builder, stencil_vals,
stencil_vals = LLVMBuildShl(s_bld.builder, stencil_vals,
stencil_shift, "");
/* Finally, merge/store the z/stencil values */
@ -673,13 +740,13 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
(stencil[0].enabled && stencil[0].writemask)) {
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)
zs_dst = z_dst;
else
zs_dst = stencil_vals;
LLVMBuildStore(builder, zs_dst, zs_dst_ptr);
*zs_value = zs_dst;
}
if (s_pass_mask)
@ -688,6 +755,47 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
if (depth->enabled && stencil[0].enabled)
lp_build_mask_update(mask, z_pass);
if (counter)
lp_build_occlusion_count(builder, type, mask->value, counter);
if (do_branch)
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_dst_ptr,
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);
#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, "");
/*
* a = a0 + x * dadx + y * dady
* a = a0 + (x * dadx + y * dady)
*/
if (attrib == 0 && chan == 0) {
@ -219,11 +219,11 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
a = a0;
if (interp != LP_INTERP_CONSTANT &&
interp != LP_INTERP_FACING) {
LLVMValueRef tmp;
tmp = LLVMBuildFMul(builder, bld->x, dadx, "");
a = LLVMBuildFAdd(builder, a, tmp, "");
tmp = LLVMBuildFMul(builder, bld->y, dady, "");
a = LLVMBuildFAdd(builder, a, tmp, "");
LLVMValueRef ax, ay, axy;
ax = LLVMBuildFMul(builder, bld->x, dadx, "");
ay = LLVMBuildFMul(builder, bld->y, dady, "");
axy = LLVMBuildFAdd(builder, ax, ay, "");
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.
*/
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;
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);
for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
for(attrib = start; attrib < end; ++attrib) {
const unsigned mask = bld->mask[attrib];
const unsigned interp = bld->interp[attrib];
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
@ -350,6 +353,14 @@ attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
}
#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, "");
}
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);
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.
*/
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)
{
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 "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
@ -89,7 +113,11 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
LLVMValueRef y);
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);

View file

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

View file

@ -39,6 +39,7 @@
#include "lp_jit.h"
#include "lp_setup.h"
#include "lp_state_fs.h"
#include "lp_state_setup.h"
struct llvmpipe_vbuf_render;
@ -48,6 +49,7 @@ struct lp_fragment_shader;
struct lp_vertex_shader;
struct lp_blend_state;
struct lp_setup_context;
struct lp_setup_variant;
struct lp_velems_state;
struct llvmpipe_context {
@ -105,12 +107,9 @@ struct llvmpipe_context {
/** Which vertex shader output slot contains point size */
int psize_slot;
/** Fragment shader input interpolation info */
unsigned num_inputs;
struct lp_shader_input inputs[PIPE_MAX_SHADER_INPUTS];
/** The tiling engine */
struct lp_setup_context *setup;
struct lp_setup_variant setup_variant;
/** The primitive drawing context */
struct draw_context *draw;
@ -120,6 +119,9 @@ struct llvmpipe_context {
struct lp_fs_variant_list_item fs_variants_list;
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_fence_handle;
struct pipe_resource;
void
llvmpipe_flush(struct pipe_context *pipe,

View file

@ -36,7 +36,6 @@
#include <llvm-c/Transforms/Scalar.h>
#include "util/u_memory.h"
#include "util/u_cpu_detect.h"
#include "gallivm/lp_bld_init.h"
#include "gallivm/lp_bld_debug.h"
#include "lp_screen.h"
@ -162,9 +161,6 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
void
lp_jit_screen_cleanup(struct llvmpipe_screen *screen)
{
if(screen->engine)
LLVMDisposeExecutionEngine(screen->engine);
if(screen->pass)
LLVMDisposePassManager(screen->pass);
}
@ -190,13 +186,7 @@ lp_jit_screen_init(struct llvmpipe_screen *screen)
LLVMAddCFGSimplificationPass(screen->pass);
LLVMAddPromoteMemoryToRegisterPass(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);
}
LLVMAddGVNPass(screen->pass);
} else {
/* 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,
uint32_t x,
uint32_t y,
float facing,
uint32_t facing,
const void *a0,
const void *dadx,
const void *dady,

View file

@ -72,4 +72,14 @@
*/
#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 */

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_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;
const unsigned tile_x = task->x, tile_y = task->y;
unsigned x, y;
@ -365,10 +365,10 @@ lp_rast_shade_tile(struct lp_rasterizer_task *task,
BEGIN_JIT_CALL(state);
variant->jit_function[RAST_WHOLE]( &state->jit_context,
tile_x + x, tile_y + y,
inputs->facing,
inputs->a0,
inputs->dadx,
inputs->dady,
inputs->frontfacing,
GET_A0(inputs),
GET_DADX(inputs),
GET_DADY(inputs),
color,
depth,
0xffff,
@ -414,7 +414,7 @@ lp_rast_shade_quads_mask(struct lp_rasterizer_task *task,
unsigned x, unsigned y,
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;
const struct lp_scene *scene = task->scene;
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);
variant->jit_function[RAST_EDGE_TEST](&state->jit_context,
x, y,
inputs->facing,
inputs->a0,
inputs->dadx,
inputs->dady,
inputs->frontfacing,
GET_A0(inputs),
GET_DADX(inputs),
GET_DADY(inputs),
color,
depth,
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.
@ -602,6 +610,7 @@ static lp_rast_cmd_func dispatch[LP_RAST_OP_MAX] =
lp_rast_shade_tile_opaque,
lp_rast_begin_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