mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-23 15:30:14 +01:00
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:
commit
41ed47d6b8
1126 changed files with 34370 additions and 29084 deletions
|
|
@ -53,7 +53,7 @@ MKDEP_OPTIONS = @MKDEP_OPTIONS@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
|
|
||||||
# Python and flags (generally only needed by the developers)
|
# Python and flags (generally only needed by the developers)
|
||||||
PYTHON2 = python
|
PYTHON2 = @PYTHON2@
|
||||||
PYTHON_FLAGS = -t -O -O
|
PYTHON_FLAGS = -t -O -O
|
||||||
|
|
||||||
# Library names (base name)
|
# Library names (base name)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ AC_PROG_CPP
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
AC_CHECK_PROGS([MAKE], [gmake make])
|
AC_CHECK_PROGS([MAKE], [gmake make])
|
||||||
|
AC_CHECK_PROGS([PYTHON2], [python2 python])
|
||||||
AC_PATH_PROG([MKDEP], [makedepend])
|
AC_PATH_PROG([MKDEP], [makedepend])
|
||||||
AC_PATH_PROG([SED], [sed])
|
AC_PATH_PROG([SED], [sed])
|
||||||
|
|
||||||
|
|
@ -1720,6 +1721,8 @@ echo ""
|
||||||
echo " CFLAGS: $cflags"
|
echo " CFLAGS: $cflags"
|
||||||
echo " CXXFLAGS: $cxxflags"
|
echo " CXXFLAGS: $cxxflags"
|
||||||
echo " Macros: $defines"
|
echo " Macros: $defines"
|
||||||
|
echo ""
|
||||||
|
echo " PYTHON2: $PYTHON2"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo " Run '${MAKE-make}' to build Mesa"
|
echo " Run '${MAKE-make}' to build Mesa"
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ Non-normalized Integer texture/framebuffer formats not started
|
||||||
Packed depth/stencil formats DONE
|
Packed depth/stencil formats DONE
|
||||||
Per-buffer blend and masks (GL_EXT_draw_buffers2) DONE
|
Per-buffer blend and masks (GL_EXT_draw_buffers2) DONE
|
||||||
GL_EXT_texture_compression_rgtc not started
|
GL_EXT_texture_compression_rgtc not started
|
||||||
Red and red/green texture formats DONE (swrast, i965)
|
Red and red/green texture formats DONE (swrast, i965, gallium)
|
||||||
Transform feedback (GL_EXT_transform_feedback) ~50% done
|
Transform feedback (GL_EXT_transform_feedback) ~50% done
|
||||||
glBindFragDataLocation, glGetFragDataLocation,
|
glBindFragDataLocation, glGetFragDataLocation,
|
||||||
glBindBufferRange, glBindBufferBase commands
|
glBindBufferRange, glBindBufferBase commands
|
||||||
|
|
@ -42,7 +42,7 @@ GL 3.1:
|
||||||
GLSL 1.30 and 1.40 not started
|
GLSL 1.30 and 1.40 not started
|
||||||
Instanced drawing (GL_ARB_draw_instanced) ~50% done
|
Instanced drawing (GL_ARB_draw_instanced) ~50% done
|
||||||
Buffer copying (GL_ARB_copy_buffer) DONE
|
Buffer copying (GL_ARB_copy_buffer) DONE
|
||||||
Primitive restart (GL_NV_primitive_restart) not started
|
Primitive restart (GL_NV_primitive_restart) DONE (gallium)
|
||||||
16 vertex texture image units not started
|
16 vertex texture image units not started
|
||||||
Texture buffer objs (GL_ARB_texture_buffer_object) not started
|
Texture buffer objs (GL_ARB_texture_buffer_object) not started
|
||||||
Rectangular textures (GL_ARB_texture_rectangle) DONE
|
Rectangular textures (GL_ARB_texture_rectangle) DONE
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@ tbd
|
||||||
<h2>New features</h2>
|
<h2>New features</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>GL_ARB_explicit_attrib_location extension (Intel and software drivers).
|
<li>GL_ARB_explicit_attrib_location extension (Intel and software drivers).
|
||||||
|
<li>GL_ARB_texture_rg (Intel, software drivers, gallium drivers).
|
||||||
|
<li>GL_EXT_separate_shader_objects extension (Intel and software drivers).
|
||||||
|
<li>GL_NV_primitive_restart extension (Gallium softpipe, llvmpipe).
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ $(EGL_DRIVER_PATH): $(EGL_DRIVER)
|
||||||
|
|
||||||
$(EGL_DRIVER): $(EGL_OBJECTS) Makefile $(TOP)/src/egl/drivers/Makefile.template
|
$(EGL_DRIVER): $(EGL_OBJECTS) Makefile $(TOP)/src/egl/drivers/Makefile.template
|
||||||
@$(MKLIB) -o $(EGL_DRIVER) -noprefix \
|
@$(MKLIB) -o $(EGL_DRIVER) -noprefix \
|
||||||
-linker '$(CC)' -ldflags '$(LDFLAGS)' \
|
-linker '$(CC)' -ldflags '-L$(TOP)/$(LIB_DIR) $(LDFLAGS)' \
|
||||||
-L$(TOP)/$(LIB_DIR) $(MKLIB_OPTIONS) \
|
$(MKLIB_OPTIONS) \
|
||||||
$(EGL_OBJECTS) $(EGL_LIBS) -l$(EGL_LIB)
|
$(EGL_OBJECTS) $(EGL_LIBS) -l$(EGL_LIB)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
|
|
|
||||||
|
|
@ -248,21 +248,20 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
|
||||||
if (double_buffer)
|
if (double_buffer)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (depth > 0 && depth != _eglGetConfigKey(&base, EGL_BUFFER_SIZE))
|
if (depth > 0 && depth != base.BufferSize)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
_eglSetConfigKey(&base, EGL_NATIVE_RENDERABLE, EGL_TRUE);
|
base.NativeRenderable = EGL_TRUE;
|
||||||
|
|
||||||
_eglSetConfigKey(&base, EGL_SURFACE_TYPE, surface_type);
|
base.SurfaceType = surface_type;
|
||||||
if (surface_type & (EGL_PIXMAP_BIT | EGL_PBUFFER_BIT)) {
|
if (surface_type & (EGL_PIXMAP_BIT | EGL_PBUFFER_BIT)) {
|
||||||
_eglSetConfigKey(&base, EGL_BIND_TO_TEXTURE_RGB, bind_to_texture_rgb);
|
base.BindToTextureRGB = bind_to_texture_rgb;
|
||||||
if (_eglGetConfigKey(&base, EGL_ALPHA_SIZE) > 0)
|
if (base.AlphaSize > 0)
|
||||||
_eglSetConfigKey(&base,
|
base.BindToTextureRGBA = bind_to_texture_rgba;
|
||||||
EGL_BIND_TO_TEXTURE_RGBA, bind_to_texture_rgba);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_eglSetConfigKey(&base, EGL_RENDERABLE_TYPE, disp->ClientAPIsMask);
|
base.RenderableType = disp->ClientAPIsMask;
|
||||||
_eglSetConfigKey(&base, EGL_CONFORMANT, disp->ClientAPIsMask);
|
base.Conformant = disp->ClientAPIsMask;
|
||||||
|
|
||||||
if (!_eglValidateConfig(&base, EGL_FALSE)) {
|
if (!_eglValidateConfig(&base, EGL_FALSE)) {
|
||||||
_eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
|
_eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
|
||||||
|
|
@ -273,7 +272,7 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
|
||||||
if (conf != NULL) {
|
if (conf != NULL) {
|
||||||
memcpy(&conf->base, &base, sizeof base);
|
memcpy(&conf->base, &base, sizeof base);
|
||||||
conf->dri_config = dri_config;
|
conf->dri_config = dri_config;
|
||||||
_eglAddConfig(disp, &conf->base);
|
_eglLinkConfig(&conf->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
return conf;
|
return conf;
|
||||||
|
|
@ -1161,7 +1160,7 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
|
||||||
|
|
||||||
(void) drv;
|
(void) drv;
|
||||||
|
|
||||||
if (_eglIsSurfaceBound(surf))
|
if (!_eglPutSurface(surf))
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
|
|
||||||
(*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
|
(*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
|
||||||
|
|
@ -1188,15 +1187,17 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
|
||||||
struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
|
struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
|
||||||
struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
|
struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
|
||||||
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
||||||
|
_EGLContext *old_ctx;
|
||||||
|
_EGLSurface *old_dsurf, *old_rsurf;
|
||||||
__DRIdrawable *ddraw, *rdraw;
|
__DRIdrawable *ddraw, *rdraw;
|
||||||
__DRIcontext *cctx;
|
__DRIcontext *cctx;
|
||||||
|
|
||||||
/* bind the new context and return the "orphaned" one */
|
/* make new bindings */
|
||||||
if (!_eglBindContext(&ctx, &dsurf, &rsurf))
|
if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
/* flush before context switch */
|
/* flush before context switch */
|
||||||
if (ctx && dri2_drv->glFlush)
|
if (old_ctx && dri2_drv->glFlush)
|
||||||
dri2_drv->glFlush();
|
dri2_drv->glFlush();
|
||||||
|
|
||||||
ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
|
ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
|
||||||
|
|
@ -1205,16 +1206,29 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
|
||||||
|
|
||||||
if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
|
if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
|
||||||
dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
|
dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
|
||||||
if (dsurf && !_eglIsSurfaceLinked(dsurf))
|
dri2_destroy_surface(drv, disp, old_dsurf);
|
||||||
dri2_destroy_surface(drv, disp, dsurf);
|
dri2_destroy_surface(drv, disp, old_rsurf);
|
||||||
if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(dsurf))
|
if (old_ctx) {
|
||||||
dri2_destroy_surface(drv, disp, rsurf);
|
dri2_dpy->core->unbindContext(dri2_egl_context(old_ctx)->dri_context);
|
||||||
if (ctx != NULL && !_eglIsContextLinked(ctx))
|
/* no destroy? */
|
||||||
dri2_dpy->core->unbindContext(dri2_egl_context(ctx)->dri_context);
|
_eglPutContext(old_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
} else {
|
} else {
|
||||||
_eglBindContext(&ctx, &dsurf, &rsurf);
|
/* undo the previous _eglBindContext */
|
||||||
|
_eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
|
||||||
|
assert(&dri2_ctx->base == ctx &&
|
||||||
|
&dri2_dsurf->base == dsurf &&
|
||||||
|
&dri2_rsurf->base == rsurf);
|
||||||
|
|
||||||
|
_eglPutSurface(dsurf);
|
||||||
|
_eglPutSurface(rsurf);
|
||||||
|
_eglPutContext(ctx);
|
||||||
|
|
||||||
|
_eglPutSurface(old_dsurf);
|
||||||
|
_eglPutSurface(old_rsurf);
|
||||||
|
_eglPutContext(old_ctx);
|
||||||
|
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
@ -1251,8 +1265,7 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
|
||||||
if (type == EGL_PBUFFER_BIT) {
|
if (type == EGL_PBUFFER_BIT) {
|
||||||
dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
|
dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
|
||||||
s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
|
s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
|
||||||
xcb_create_pixmap(dri2_dpy->conn,
|
xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
|
||||||
_eglGetConfigKey(conf, EGL_BUFFER_SIZE),
|
|
||||||
dri2_surf->drawable, s.data->root,
|
dri2_surf->drawable, s.data->root,
|
||||||
dri2_surf->base.Width, dri2_surf->base.Height);
|
dri2_surf->base.Width, dri2_surf->base.Height);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1601,7 +1614,7 @@ dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
|
||||||
return EGL_NO_IMAGE_KHR;
|
return EGL_NO_IMAGE_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) {
|
if (!_eglInitImage(&dri2_img->base, disp)) {
|
||||||
free(buffers_reply);
|
free(buffers_reply);
|
||||||
free(geometry_reply);
|
free(geometry_reply);
|
||||||
return EGL_NO_IMAGE_KHR;
|
return EGL_NO_IMAGE_KHR;
|
||||||
|
|
@ -1644,7 +1657,7 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
|
||||||
return EGL_NO_IMAGE_KHR;
|
return EGL_NO_IMAGE_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_eglInitImage(&dri2_img->base, disp, attr_list))
|
if (!_eglInitImage(&dri2_img->base, disp))
|
||||||
return EGL_NO_IMAGE_KHR;
|
return EGL_NO_IMAGE_KHR;
|
||||||
|
|
||||||
dri2_img->dri_image =
|
dri2_img->dri_image =
|
||||||
|
|
@ -1661,56 +1674,28 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
|
||||||
{
|
{
|
||||||
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
||||||
struct dri2_egl_image *dri2_img;
|
struct dri2_egl_image *dri2_img;
|
||||||
EGLint width, height, format, name, stride, pitch, i, err;
|
EGLint format, name, pitch, err;
|
||||||
|
_EGLImageAttribs attrs;
|
||||||
|
|
||||||
(void) ctx;
|
(void) ctx;
|
||||||
|
|
||||||
name = (EGLint) buffer;
|
name = (EGLint) buffer;
|
||||||
|
|
||||||
err = EGL_SUCCESS;
|
err = _eglParseImageAttribList(&attrs, disp, attr_list);
|
||||||
width = 0;
|
if (err != EGL_SUCCESS)
|
||||||
height = 0;
|
|
||||||
format = 0;
|
|
||||||
stride = 0;
|
|
||||||
|
|
||||||
for (i = 0; attr_list[i] != EGL_NONE; i++) {
|
|
||||||
EGLint attr = attr_list[i++];
|
|
||||||
EGLint val = attr_list[i];
|
|
||||||
|
|
||||||
switch (attr) {
|
|
||||||
case EGL_WIDTH:
|
|
||||||
width = val;
|
|
||||||
break;
|
|
||||||
case EGL_HEIGHT:
|
|
||||||
height = val;
|
|
||||||
break;
|
|
||||||
case EGL_DRM_BUFFER_FORMAT_MESA:
|
|
||||||
format = val;
|
|
||||||
break;
|
|
||||||
case EGL_DRM_BUFFER_STRIDE_MESA:
|
|
||||||
stride = val;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
err = EGL_BAD_ATTRIBUTE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err != EGL_SUCCESS) {
|
|
||||||
_eglLog(_EGL_WARNING, "bad image attribute 0x%04x", attr);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width <= 0 || height <= 0 || stride <= 0) {
|
if (attrs.Width <= 0 || attrs.Height <= 0 ||
|
||||||
|
attrs.DRMBufferStrideMESA <= 0) {
|
||||||
_eglError(EGL_BAD_PARAMETER,
|
_eglError(EGL_BAD_PARAMETER,
|
||||||
"bad width, height or stride");
|
"bad width, height or stride");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (format) {
|
switch (attrs.DRMBufferFormatMESA) {
|
||||||
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
|
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
|
||||||
format = __DRI_IMAGE_FORMAT_ARGB8888;
|
format = __DRI_IMAGE_FORMAT_ARGB8888;
|
||||||
pitch = stride;
|
pitch = attrs.DRMBufferStrideMESA;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_eglError(EGL_BAD_PARAMETER,
|
_eglError(EGL_BAD_PARAMETER,
|
||||||
|
|
@ -1724,15 +1709,15 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) {
|
if (!_eglInitImage(&dri2_img->base, disp)) {
|
||||||
free(dri2_img);
|
free(dri2_img);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dri2_img->dri_image =
|
dri2_img->dri_image =
|
||||||
dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
|
dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
|
||||||
width,
|
attrs.Width,
|
||||||
height,
|
attrs.Height,
|
||||||
format,
|
format,
|
||||||
name,
|
name,
|
||||||
pitch,
|
pitch,
|
||||||
|
|
@ -1786,8 +1771,9 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
|
||||||
{
|
{
|
||||||
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
||||||
struct dri2_egl_image *dri2_img;
|
struct dri2_egl_image *dri2_img;
|
||||||
int width, height, format, i;
|
_EGLImageAttribs attrs;
|
||||||
unsigned int use, dri_use, valid_mask;
|
unsigned int dri_use, valid_mask;
|
||||||
|
int format;
|
||||||
EGLint err = EGL_SUCCESS;
|
EGLint err = EGL_SUCCESS;
|
||||||
|
|
||||||
(void) drv;
|
(void) drv;
|
||||||
|
|
@ -1803,74 +1789,50 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
|
||||||
goto cleanup_img;
|
goto cleanup_img;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_eglInitImage(&dri2_img->base, disp, attr_list)) {
|
if (!_eglInitImage(&dri2_img->base, disp)) {
|
||||||
err = EGL_BAD_PARAMETER;
|
err = EGL_BAD_PARAMETER;
|
||||||
goto cleanup_img;
|
goto cleanup_img;
|
||||||
}
|
}
|
||||||
|
|
||||||
width = 0;
|
err = _eglParseImageAttribList(&attrs, disp, attr_list);
|
||||||
height = 0;
|
if (err != EGL_SUCCESS)
|
||||||
format = 0;
|
|
||||||
use = 0;
|
|
||||||
for (i = 0; attr_list[i] != EGL_NONE; i++) {
|
|
||||||
EGLint attr = attr_list[i++];
|
|
||||||
EGLint val = attr_list[i];
|
|
||||||
|
|
||||||
switch (attr) {
|
|
||||||
case EGL_WIDTH:
|
|
||||||
width = val;
|
|
||||||
break;
|
|
||||||
case EGL_HEIGHT:
|
|
||||||
height = val;
|
|
||||||
break;
|
|
||||||
case EGL_DRM_BUFFER_FORMAT_MESA:
|
|
||||||
format = val;
|
|
||||||
break;
|
|
||||||
case EGL_DRM_BUFFER_USE_MESA:
|
|
||||||
use = val;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
err = EGL_BAD_ATTRIBUTE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err != EGL_SUCCESS) {
|
|
||||||
_eglLog(_EGL_WARNING, "bad image attribute 0x%04x", attr);
|
|
||||||
goto cleanup_img;
|
goto cleanup_img;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width <= 0 || height <= 0) {
|
if (attrs.Width <= 0 || attrs.Height <= 0) {
|
||||||
_eglLog(_EGL_WARNING, "bad width or height (%dx%d)", width, height);
|
_eglLog(_EGL_WARNING, "bad width or height (%dx%d)",
|
||||||
|
attrs.Width, attrs.Height);
|
||||||
goto cleanup_img;
|
goto cleanup_img;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (format) {
|
switch (attrs.DRMBufferFormatMESA) {
|
||||||
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
|
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
|
||||||
format = __DRI_IMAGE_FORMAT_ARGB8888;
|
format = __DRI_IMAGE_FORMAT_ARGB8888;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_eglLog(_EGL_WARNING, "bad image format value 0x%04x", format);
|
_eglLog(_EGL_WARNING, "bad image format value 0x%04x",
|
||||||
|
attrs.DRMBufferFormatMESA);
|
||||||
goto cleanup_img;
|
goto cleanup_img;
|
||||||
}
|
}
|
||||||
|
|
||||||
valid_mask =
|
valid_mask =
|
||||||
EGL_DRM_BUFFER_USE_SCANOUT_MESA |
|
EGL_DRM_BUFFER_USE_SCANOUT_MESA |
|
||||||
EGL_DRM_BUFFER_USE_SHARE_MESA;
|
EGL_DRM_BUFFER_USE_SHARE_MESA;
|
||||||
if (use & ~valid_mask) {
|
if (attrs.DRMBufferUseMESA & ~valid_mask) {
|
||||||
_eglLog(_EGL_WARNING, "bad image use bit 0x%04x", use & ~valid_mask);
|
_eglLog(_EGL_WARNING, "bad image use bit 0x%04x",
|
||||||
|
attrs.DRMBufferUseMESA & ~valid_mask);
|
||||||
goto cleanup_img;
|
goto cleanup_img;
|
||||||
}
|
}
|
||||||
|
|
||||||
dri_use = 0;
|
dri_use = 0;
|
||||||
if (use & EGL_DRM_BUFFER_USE_SHARE_MESA)
|
if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SHARE_MESA)
|
||||||
dri_use |= __DRI_IMAGE_USE_SHARE;
|
dri_use |= __DRI_IMAGE_USE_SHARE;
|
||||||
if (use & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
|
if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
|
||||||
dri_use |= __DRI_IMAGE_USE_SCANOUT;
|
dri_use |= __DRI_IMAGE_USE_SCANOUT;
|
||||||
|
|
||||||
dri2_img->dri_image =
|
dri2_img->dri_image =
|
||||||
dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
||||||
width, height, format, dri_use, dri2_img);
|
attrs.Width, attrs.Height,
|
||||||
|
format, dri_use, dri2_img);
|
||||||
if (dri2_img->dri_image == NULL) {
|
if (dri2_img->dri_image == NULL) {
|
||||||
err = EGL_BAD_ALLOC;
|
err = EGL_BAD_ALLOC;
|
||||||
goto cleanup_img;
|
goto cleanup_img;
|
||||||
|
|
|
||||||
|
|
@ -132,29 +132,38 @@ static const struct {
|
||||||
int egl_attr;
|
int egl_attr;
|
||||||
} fbconfig_attributes[] = {
|
} fbconfig_attributes[] = {
|
||||||
/* table 3.1 of GLX 1.4 */
|
/* table 3.1 of GLX 1.4 */
|
||||||
|
{ GLX_FBCONFIG_ID, 0 },
|
||||||
{ GLX_BUFFER_SIZE, EGL_BUFFER_SIZE },
|
{ GLX_BUFFER_SIZE, EGL_BUFFER_SIZE },
|
||||||
{ GLX_LEVEL, EGL_LEVEL },
|
{ GLX_LEVEL, EGL_LEVEL },
|
||||||
|
{ GLX_DOUBLEBUFFER, 0 },
|
||||||
|
{ GLX_STEREO, 0 },
|
||||||
|
{ GLX_AUX_BUFFERS, 0 },
|
||||||
{ GLX_RED_SIZE, EGL_RED_SIZE },
|
{ GLX_RED_SIZE, EGL_RED_SIZE },
|
||||||
{ GLX_GREEN_SIZE, EGL_GREEN_SIZE },
|
{ GLX_GREEN_SIZE, EGL_GREEN_SIZE },
|
||||||
{ GLX_BLUE_SIZE, EGL_BLUE_SIZE },
|
{ GLX_BLUE_SIZE, EGL_BLUE_SIZE },
|
||||||
{ GLX_ALPHA_SIZE, EGL_ALPHA_SIZE },
|
{ GLX_ALPHA_SIZE, EGL_ALPHA_SIZE },
|
||||||
{ GLX_DEPTH_SIZE, EGL_DEPTH_SIZE },
|
{ GLX_DEPTH_SIZE, EGL_DEPTH_SIZE },
|
||||||
{ GLX_STENCIL_SIZE, EGL_STENCIL_SIZE },
|
{ GLX_STENCIL_SIZE, EGL_STENCIL_SIZE },
|
||||||
|
{ GLX_ACCUM_RED_SIZE, 0 },
|
||||||
|
{ GLX_ACCUM_GREEN_SIZE, 0 },
|
||||||
|
{ GLX_ACCUM_BLUE_SIZE, 0 },
|
||||||
|
{ GLX_ACCUM_ALPHA_SIZE, 0 },
|
||||||
{ GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS },
|
{ GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS },
|
||||||
{ GLX_SAMPLES, EGL_SAMPLES },
|
{ GLX_SAMPLES, EGL_SAMPLES },
|
||||||
{ GLX_RENDER_TYPE, EGL_RENDERABLE_TYPE },
|
{ GLX_RENDER_TYPE, 0 },
|
||||||
|
{ GLX_DRAWABLE_TYPE, EGL_SURFACE_TYPE },
|
||||||
{ GLX_X_RENDERABLE, EGL_NATIVE_RENDERABLE },
|
{ GLX_X_RENDERABLE, EGL_NATIVE_RENDERABLE },
|
||||||
{ GLX_X_VISUAL_TYPE, EGL_NATIVE_VISUAL_TYPE },
|
{ GLX_X_VISUAL_TYPE, EGL_NATIVE_VISUAL_TYPE },
|
||||||
{ GLX_CONFIG_CAVEAT, EGL_CONFIG_CAVEAT },
|
{ GLX_CONFIG_CAVEAT, EGL_CONFIG_CAVEAT },
|
||||||
{ GLX_TRANSPARENT_TYPE, EGL_TRANSPARENT_TYPE },
|
{ GLX_TRANSPARENT_TYPE, EGL_TRANSPARENT_TYPE },
|
||||||
|
{ GLX_TRANSPARENT_INDEX_VALUE, 0 },
|
||||||
{ GLX_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_RED_VALUE },
|
{ GLX_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_RED_VALUE },
|
||||||
{ GLX_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_GREEN_VALUE },
|
{ GLX_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_GREEN_VALUE },
|
||||||
{ GLX_TRANSPARENT_BLUE_VALUE, EGL_TRANSPARENT_BLUE_VALUE },
|
{ GLX_TRANSPARENT_BLUE_VALUE, EGL_TRANSPARENT_BLUE_VALUE },
|
||||||
{ GLX_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_WIDTH },
|
{ GLX_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_WIDTH },
|
||||||
{ GLX_MAX_PBUFFER_HEIGHT, EGL_MAX_PBUFFER_HEIGHT },
|
{ GLX_MAX_PBUFFER_HEIGHT, EGL_MAX_PBUFFER_HEIGHT },
|
||||||
{ GLX_MAX_PBUFFER_PIXELS, EGL_MAX_PBUFFER_PIXELS },
|
{ GLX_MAX_PBUFFER_PIXELS, EGL_MAX_PBUFFER_PIXELS },
|
||||||
{ GLX_VISUAL_ID, EGL_NATIVE_VISUAL_ID },
|
{ GLX_VISUAL_ID, EGL_NATIVE_VISUAL_ID }
|
||||||
{ GLX_X_VISUAL_TYPE, EGL_NATIVE_VISUAL_TYPE },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -162,13 +171,31 @@ static EGLBoolean
|
||||||
convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
|
convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
|
||||||
struct GLX_egl_config *GLX_conf)
|
struct GLX_egl_config *GLX_conf)
|
||||||
{
|
{
|
||||||
int err = 0, attr, egl_attr, val;
|
int err, attr, val;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
EGLint conformant, config_caveat, surface_type;
|
|
||||||
|
/* must have rgba bit */
|
||||||
|
err = glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &val);
|
||||||
|
if (err || !(val & GLX_RGBA_BIT))
|
||||||
|
return EGL_FALSE;
|
||||||
|
|
||||||
|
/* must know whether it is double-buffered */
|
||||||
|
err = glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &val);
|
||||||
|
if (err)
|
||||||
|
return EGL_FALSE;
|
||||||
|
GLX_conf->double_buffered = val;
|
||||||
|
|
||||||
|
GLX_conf->Base.RenderableType = EGL_OPENGL_BIT;
|
||||||
|
GLX_conf->Base.Conformant = EGL_OPENGL_BIT;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) {
|
for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) {
|
||||||
|
EGLint egl_attr, egl_val;
|
||||||
|
|
||||||
attr = fbconfig_attributes[i].attr;
|
attr = fbconfig_attributes[i].attr;
|
||||||
egl_attr = fbconfig_attributes[i].egl_attr;
|
egl_attr = fbconfig_attributes[i].egl_attr;
|
||||||
|
if (!egl_attr)
|
||||||
|
continue;
|
||||||
|
|
||||||
err = glXGetFBConfigAttrib(dpy, fbconfig, attr, &val);
|
err = glXGetFBConfigAttrib(dpy, fbconfig, attr, &val);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err == GLX_BAD_ATTRIBUTE) {
|
if (err == GLX_BAD_ATTRIBUTE) {
|
||||||
|
|
@ -178,47 +205,71 @@ convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_eglSetConfigKey(&GLX_conf->Base, egl_attr, val);
|
switch (egl_attr) {
|
||||||
|
case EGL_SURFACE_TYPE:
|
||||||
|
egl_val = 0;
|
||||||
|
if (val & GLX_WINDOW_BIT)
|
||||||
|
egl_val |= EGL_WINDOW_BIT;
|
||||||
|
/* pixmap and pbuffer surfaces must be single-buffered in EGL */
|
||||||
|
if (!GLX_conf->double_buffered) {
|
||||||
|
if (val & GLX_PIXMAP_BIT)
|
||||||
|
egl_val |= EGL_PIXMAP_BIT;
|
||||||
|
if (val & GLX_PBUFFER_BIT)
|
||||||
|
egl_val |= EGL_PBUFFER_BIT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EGL_NATIVE_VISUAL_TYPE:
|
||||||
|
switch (val) {
|
||||||
|
case GLX_TRUE_COLOR:
|
||||||
|
egl_val = TrueColor;
|
||||||
|
break;
|
||||||
|
case GLX_DIRECT_COLOR:
|
||||||
|
egl_val = DirectColor;
|
||||||
|
break;
|
||||||
|
case GLX_PSEUDO_COLOR:
|
||||||
|
egl_val = PseudoColor;
|
||||||
|
break;
|
||||||
|
case GLX_STATIC_COLOR:
|
||||||
|
egl_val = StaticColor;
|
||||||
|
break;
|
||||||
|
case GLX_GRAY_SCALE:
|
||||||
|
egl_val = GrayScale;
|
||||||
|
break;
|
||||||
|
case GLX_STATIC_GRAY:
|
||||||
|
egl_val = StaticGray;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
egl_val = EGL_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EGL_CONFIG_CAVEAT:
|
||||||
|
egl_val = EGL_NONE;
|
||||||
|
if (val == GLX_SLOW_CONFIG) {
|
||||||
|
egl_val = EGL_SLOW_CONFIG;
|
||||||
|
}
|
||||||
|
else if (val == GLX_NON_CONFORMANT_CONFIG) {
|
||||||
|
GLX_conf->Base.Conformant &= ~EGL_OPENGL_BIT;
|
||||||
|
egl_val = EGL_NONE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EGL_TRANSPARENT_TYPE:
|
||||||
|
egl_val = (val == GLX_TRANSPARENT_RGB) ?
|
||||||
|
EGL_TRANSPARENT_RGB : EGL_NONE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
egl_val = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_eglSetConfigKey(&GLX_conf->Base, egl_attr, egl_val);
|
||||||
}
|
}
|
||||||
if (err)
|
if (err)
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
/* must have rgba bit */
|
if (!GLX_conf->Base.SurfaceType)
|
||||||
glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &val);
|
|
||||||
if (!(val & GLX_RGBA_BIT))
|
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
conformant = EGL_OPENGL_BIT;
|
|
||||||
glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &val);
|
|
||||||
if (val == GLX_SLOW_CONFIG)
|
|
||||||
config_caveat = EGL_SLOW_CONFIG;
|
|
||||||
if (val == GLX_NON_CONFORMANT_CONFIG)
|
|
||||||
conformant &= ~EGL_OPENGL_BIT;
|
|
||||||
if (!(conformant & EGL_OPENGL_ES_BIT))
|
|
||||||
config_caveat = EGL_NON_CONFORMANT_CONFIG;
|
|
||||||
|
|
||||||
_eglSetConfigKey(&GLX_conf->Base, EGL_CONFIG_CAVEAT, config_caveat);
|
|
||||||
|
|
||||||
surface_type = 0;
|
|
||||||
glXGetFBConfigAttrib(dpy, fbconfig, GLX_DRAWABLE_TYPE, &val);
|
|
||||||
if (val & GLX_WINDOW_BIT)
|
|
||||||
surface_type |= EGL_WINDOW_BIT;
|
|
||||||
if (val & GLX_PIXMAP_BIT)
|
|
||||||
surface_type |= EGL_PIXMAP_BIT;
|
|
||||||
if (val & GLX_PBUFFER_BIT)
|
|
||||||
surface_type |= EGL_PBUFFER_BIT;
|
|
||||||
|
|
||||||
/* pixmap and pbuffer surfaces must be single-buffered in EGL */
|
|
||||||
glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &val);
|
|
||||||
GLX_conf->double_buffered = val;
|
|
||||||
if (GLX_conf->double_buffered) {
|
|
||||||
surface_type &= ~(EGL_PIXMAP_BIT | EGL_PBUFFER_BIT);
|
|
||||||
if (!surface_type)
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
_eglSetConfigKey(&GLX_conf->Base, EGL_SURFACE_TYPE, surface_type);
|
|
||||||
|
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,35 +278,69 @@ static const struct {
|
||||||
int egl_attr;
|
int egl_attr;
|
||||||
} visual_attributes[] = {
|
} visual_attributes[] = {
|
||||||
/* table 3.7 of GLX 1.4 */
|
/* table 3.7 of GLX 1.4 */
|
||||||
/* no GLX_USE_GL */
|
{ GLX_USE_GL, 0 },
|
||||||
{ GLX_BUFFER_SIZE, EGL_BUFFER_SIZE },
|
{ GLX_BUFFER_SIZE, EGL_BUFFER_SIZE },
|
||||||
{ GLX_LEVEL, EGL_LEVEL },
|
{ GLX_LEVEL, EGL_LEVEL },
|
||||||
|
{ GLX_RGBA, 0 },
|
||||||
|
{ GLX_DOUBLEBUFFER, 0 },
|
||||||
|
{ GLX_STEREO, 0 },
|
||||||
|
{ GLX_AUX_BUFFERS, 0 },
|
||||||
{ GLX_RED_SIZE, EGL_RED_SIZE },
|
{ GLX_RED_SIZE, EGL_RED_SIZE },
|
||||||
{ GLX_GREEN_SIZE, EGL_GREEN_SIZE },
|
{ GLX_GREEN_SIZE, EGL_GREEN_SIZE },
|
||||||
{ GLX_BLUE_SIZE, EGL_BLUE_SIZE },
|
{ GLX_BLUE_SIZE, EGL_BLUE_SIZE },
|
||||||
{ GLX_ALPHA_SIZE, EGL_ALPHA_SIZE },
|
{ GLX_ALPHA_SIZE, EGL_ALPHA_SIZE },
|
||||||
{ GLX_DEPTH_SIZE, EGL_DEPTH_SIZE },
|
{ GLX_DEPTH_SIZE, EGL_DEPTH_SIZE },
|
||||||
{ GLX_STENCIL_SIZE, EGL_STENCIL_SIZE },
|
{ GLX_STENCIL_SIZE, EGL_STENCIL_SIZE },
|
||||||
|
{ GLX_ACCUM_RED_SIZE, 0 },
|
||||||
|
{ GLX_ACCUM_GREEN_SIZE, 0 },
|
||||||
|
{ GLX_ACCUM_BLUE_SIZE, 0 },
|
||||||
|
{ GLX_ACCUM_ALPHA_SIZE, 0 },
|
||||||
{ GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS },
|
{ GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS },
|
||||||
{ GLX_SAMPLES, EGL_SAMPLES },
|
{ GLX_SAMPLES, EGL_SAMPLES },
|
||||||
|
{ GLX_FBCONFIG_ID, 0 },
|
||||||
|
/* GLX_EXT_visual_rating */
|
||||||
|
{ GLX_VISUAL_CAVEAT_EXT, EGL_CONFIG_CAVEAT }
|
||||||
};
|
};
|
||||||
|
|
||||||
static EGLBoolean
|
static EGLBoolean
|
||||||
convert_visual(Display *dpy, XVisualInfo *vinfo,
|
convert_visual(Display *dpy, XVisualInfo *vinfo,
|
||||||
struct GLX_egl_config *GLX_conf)
|
struct GLX_egl_config *GLX_conf)
|
||||||
{
|
{
|
||||||
int err, attr, egl_attr, val;
|
int err, attr, val;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
EGLint conformant, config_caveat, surface_type;
|
|
||||||
|
|
||||||
/* the visual must support OpenGL */
|
/* the visual must support OpenGL and RGBA buffer */
|
||||||
err = glXGetConfig(dpy, vinfo, GLX_USE_GL, &val);
|
err = glXGetConfig(dpy, vinfo, GLX_USE_GL, &val);
|
||||||
|
if (!err && val)
|
||||||
|
err = glXGetConfig(dpy, vinfo, GLX_RGBA, &val);
|
||||||
if (err || !val)
|
if (err || !val)
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
|
/* must know whether it is double-buffered */
|
||||||
|
err = glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &val);
|
||||||
|
if (err)
|
||||||
|
return EGL_FALSE;
|
||||||
|
GLX_conf->double_buffered = val;
|
||||||
|
|
||||||
|
GLX_conf->Base.RenderableType = EGL_OPENGL_BIT;
|
||||||
|
GLX_conf->Base.Conformant = EGL_OPENGL_BIT;
|
||||||
|
GLX_conf->Base.SurfaceType = EGL_WINDOW_BIT;
|
||||||
|
/* pixmap surfaces must be single-buffered in EGL */
|
||||||
|
if (!GLX_conf->double_buffered)
|
||||||
|
GLX_conf->Base.SurfaceType |= EGL_PIXMAP_BIT;
|
||||||
|
|
||||||
|
GLX_conf->Base.NativeVisualID = vinfo->visualid;
|
||||||
|
GLX_conf->Base.NativeVisualType = vinfo->class;
|
||||||
|
GLX_conf->Base.NativeRenderable = EGL_TRUE;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) {
|
for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) {
|
||||||
|
EGLint egl_attr, egl_val;
|
||||||
|
|
||||||
attr = visual_attributes[i].attr;
|
attr = visual_attributes[i].attr;
|
||||||
egl_attr = fbconfig_attributes[i].egl_attr;
|
egl_attr = visual_attributes[i].egl_attr;
|
||||||
|
if (!egl_attr)
|
||||||
|
continue;
|
||||||
|
|
||||||
err = glXGetConfig(dpy, vinfo, attr, &val);
|
err = glXGetConfig(dpy, vinfo, attr, &val);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err == GLX_BAD_ATTRIBUTE) {
|
if (err == GLX_BAD_ATTRIBUTE) {
|
||||||
|
|
@ -265,41 +350,26 @@ convert_visual(Display *dpy, XVisualInfo *vinfo,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_eglSetConfigKey(&GLX_conf->Base, egl_attr, val);
|
switch (egl_attr) {
|
||||||
|
case EGL_CONFIG_CAVEAT:
|
||||||
|
egl_val = EGL_NONE;
|
||||||
|
if (val == GLX_SLOW_VISUAL_EXT) {
|
||||||
|
egl_val = EGL_SLOW_CONFIG;
|
||||||
|
}
|
||||||
|
else if (val == GLX_NON_CONFORMANT_VISUAL_EXT) {
|
||||||
|
GLX_conf->Base.Conformant &= ~EGL_OPENGL_BIT;
|
||||||
|
egl_val = EGL_NONE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
egl_val = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_eglSetConfigKey(&GLX_conf->Base, egl_attr, egl_val);
|
||||||
}
|
}
|
||||||
if (err)
|
|
||||||
return EGL_FALSE;
|
|
||||||
|
|
||||||
glXGetConfig(dpy, vinfo, GLX_RGBA, &val);
|
return (err) ? EGL_FALSE : EGL_TRUE;
|
||||||
if (!val)
|
|
||||||
return EGL_FALSE;
|
|
||||||
|
|
||||||
conformant = EGL_OPENGL_BIT;
|
|
||||||
glXGetConfig(dpy, vinfo, GLX_VISUAL_CAVEAT_EXT, &val);
|
|
||||||
if (val == GLX_SLOW_CONFIG)
|
|
||||||
config_caveat = EGL_SLOW_CONFIG;
|
|
||||||
if (val == GLX_NON_CONFORMANT_CONFIG)
|
|
||||||
conformant &= ~EGL_OPENGL_BIT;
|
|
||||||
if (!(conformant & EGL_OPENGL_ES_BIT))
|
|
||||||
config_caveat = EGL_NON_CONFORMANT_CONFIG;
|
|
||||||
|
|
||||||
_eglSetConfigKey(&GLX_conf->Base, EGL_CONFIG_CAVEAT, config_caveat);
|
|
||||||
_eglSetConfigKey(&GLX_conf->Base, EGL_NATIVE_VISUAL_ID, vinfo->visualid);
|
|
||||||
_eglSetConfigKey(&GLX_conf->Base, EGL_NATIVE_VISUAL_TYPE, vinfo->class);
|
|
||||||
|
|
||||||
/* pixmap and pbuffer surfaces must be single-buffered in EGL */
|
|
||||||
glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &val);
|
|
||||||
GLX_conf->double_buffered = val;
|
|
||||||
surface_type = EGL_WINDOW_BIT;
|
|
||||||
/* pixmap surfaces must be single-buffered in EGL */
|
|
||||||
if (!GLX_conf->double_buffered)
|
|
||||||
surface_type |= EGL_PIXMAP_BIT;
|
|
||||||
|
|
||||||
_eglSetConfigKey(&GLX_conf->Base, EGL_SURFACE_TYPE, surface_type);
|
|
||||||
|
|
||||||
_eglSetConfigKey(&GLX_conf->Base, EGL_NATIVE_RENDERABLE, EGL_TRUE);
|
|
||||||
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -307,30 +377,31 @@ static void
|
||||||
fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf)
|
fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf)
|
||||||
{
|
{
|
||||||
_EGLConfig *conf = &GLX_conf->Base;
|
_EGLConfig *conf = &GLX_conf->Base;
|
||||||
EGLint surface_type, r, g, b, a;
|
|
||||||
|
|
||||||
surface_type = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
|
|
||||||
if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) {
|
if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) {
|
||||||
/* some GLX impls do not like single-buffered window surface */
|
/* some GLX impls do not like single-buffered window surface */
|
||||||
surface_type &= ~EGL_WINDOW_BIT;
|
conf->SurfaceType &= ~EGL_WINDOW_BIT;
|
||||||
/* pbuffer bit is usually not set */
|
/* pbuffer bit is usually not set */
|
||||||
if (GLX_dpy->have_pbuffer)
|
if (GLX_dpy->have_pbuffer)
|
||||||
surface_type |= EGL_PBUFFER_BIT;
|
conf->SurfaceType |= EGL_PBUFFER_BIT;
|
||||||
SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no visual attribs unless window bit is set */
|
/* no visual attribs unless window bit is set */
|
||||||
if (!(surface_type & EGL_WINDOW_BIT)) {
|
if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
|
||||||
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, 0);
|
conf->NativeVisualID = 0;
|
||||||
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_NONE);
|
conf->NativeVisualType = EGL_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->TransparentType != EGL_TRANSPARENT_RGB) {
|
||||||
|
/* some impls set them to -1 (GLX_DONT_CARE) */
|
||||||
|
conf->TransparentRedValue = 0;
|
||||||
|
conf->TransparentGreenValue = 0;
|
||||||
|
conf->TransparentBlueValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure buffer size is set correctly */
|
/* make sure buffer size is set correctly */
|
||||||
r = GET_CONFIG_ATTRIB(conf, EGL_RED_SIZE);
|
conf->BufferSize =
|
||||||
g = GET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE);
|
conf->RedSize + conf->GreenSize + conf->BlueSize + conf->AlphaSize;
|
||||||
b = GET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE);
|
|
||||||
a = GET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE);
|
|
||||||
SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, r + g + b + a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -381,7 +452,7 @@ create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy,
|
||||||
memcpy(GLX_conf, &template, sizeof(template));
|
memcpy(GLX_conf, &template, sizeof(template));
|
||||||
GLX_conf->index = i;
|
GLX_conf->index = i;
|
||||||
|
|
||||||
_eglAddConfig(dpy, &GLX_conf->Base);
|
_eglLinkConfig(&GLX_conf->Base);
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -606,14 +677,16 @@ GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
|
||||||
struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
|
struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
|
||||||
struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
|
struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
|
||||||
struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
|
struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
|
||||||
|
_EGLContext *old_ctx;
|
||||||
|
_EGLSurface *old_dsurf, *old_rsurf;
|
||||||
GLXDrawable ddraw, rdraw;
|
GLXDrawable ddraw, rdraw;
|
||||||
GLXContext cctx;
|
GLXContext cctx;
|
||||||
EGLBoolean ret = EGL_FALSE;
|
EGLBoolean ret = EGL_FALSE;
|
||||||
|
|
||||||
(void) drv;
|
(void) drv;
|
||||||
|
|
||||||
/* bind the new context and return the "orphaned" one */
|
/* make new bindings */
|
||||||
if (!_eglBindContext(&ctx, &dsurf, &rsurf))
|
if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
ddraw = (GLX_dsurf) ? GLX_dsurf->glx_drawable : None;
|
ddraw = (GLX_dsurf) ? GLX_dsurf->glx_drawable : None;
|
||||||
|
|
@ -626,13 +699,27 @@ GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
|
||||||
ret = glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx);
|
ret = glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (dsurf && !_eglIsSurfaceLinked(dsurf))
|
if (_eglPutSurface(old_dsurf))
|
||||||
destroy_surface(disp, dsurf);
|
destroy_surface(disp, old_dsurf);
|
||||||
if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(rsurf))
|
if (_eglPutSurface(old_rsurf))
|
||||||
destroy_surface(disp, rsurf);
|
destroy_surface(disp, old_rsurf);
|
||||||
|
/* no destroy? */
|
||||||
|
_eglPutContext(old_ctx);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_eglBindContext(&ctx, &dsurf, &rsurf);
|
/* undo the previous _eglBindContext */
|
||||||
|
_eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf);
|
||||||
|
assert(&GLX_ctx->Base == ctx &&
|
||||||
|
&GLX_dsurf->Base == dsurf &&
|
||||||
|
&GLX_rsurf->Base == rsurf);
|
||||||
|
|
||||||
|
_eglPutSurface(dsurf);
|
||||||
|
_eglPutSurface(rsurf);
|
||||||
|
_eglPutContext(ctx);
|
||||||
|
|
||||||
|
_eglPutSurface(old_dsurf);
|
||||||
|
_eglPutSurface(old_rsurf);
|
||||||
|
_eglPutContext(old_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -836,7 +923,7 @@ GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
|
||||||
{
|
{
|
||||||
(void) drv;
|
(void) drv;
|
||||||
|
|
||||||
if (!_eglIsSurfaceBound(surf))
|
if (_eglPutSurface(surf))
|
||||||
destroy_surface(disp, surf);
|
destroy_surface(disp, surf);
|
||||||
|
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ SOURCES = \
|
||||||
eglcurrent.c \
|
eglcurrent.c \
|
||||||
egldisplay.c \
|
egldisplay.c \
|
||||||
egldriver.c \
|
egldriver.c \
|
||||||
|
eglfallbacks.c \
|
||||||
eglglobals.c \
|
eglglobals.c \
|
||||||
eglimage.c \
|
eglimage.c \
|
||||||
egllog.c \
|
egllog.c \
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ if env['platform'] != 'winddk':
|
||||||
'eglcurrent.c',
|
'eglcurrent.c',
|
||||||
'egldisplay.c',
|
'egldisplay.c',
|
||||||
'egldriver.c',
|
'egldriver.c',
|
||||||
|
'eglfallbacks.c',
|
||||||
'eglglobals.c',
|
'eglglobals.c',
|
||||||
'eglimage.c',
|
'eglimage.c',
|
||||||
'egllog.c',
|
'egllog.c',
|
||||||
|
|
|
||||||
|
|
@ -416,7 +416,7 @@ eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list,
|
||||||
RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
|
RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
|
||||||
|
|
||||||
context = drv->API.CreateContext(drv, disp, conf, share, attrib_list);
|
context = drv->API.CreateContext(drv, disp, conf, share, attrib_list);
|
||||||
ret = (context) ? _eglLinkContext(context, disp) : EGL_NO_CONTEXT;
|
ret = (context) ? _eglLinkContext(context) : EGL_NO_CONTEXT;
|
||||||
|
|
||||||
RETURN_EGL_EVAL(disp, ret);
|
RETURN_EGL_EVAL(disp, ret);
|
||||||
}
|
}
|
||||||
|
|
@ -515,7 +515,7 @@ eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
|
||||||
RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
|
RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
|
||||||
|
|
||||||
surf = drv->API.CreateWindowSurface(drv, disp, conf, window, attrib_list);
|
surf = drv->API.CreateWindowSurface(drv, disp, conf, window, attrib_list);
|
||||||
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE;
|
ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
|
||||||
|
|
||||||
RETURN_EGL_EVAL(disp, ret);
|
RETURN_EGL_EVAL(disp, ret);
|
||||||
}
|
}
|
||||||
|
|
@ -536,7 +536,7 @@ eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
|
||||||
RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
|
RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
|
||||||
|
|
||||||
surf = drv->API.CreatePixmapSurface(drv, disp, conf, pixmap, attrib_list);
|
surf = drv->API.CreatePixmapSurface(drv, disp, conf, pixmap, attrib_list);
|
||||||
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE;
|
ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
|
||||||
|
|
||||||
RETURN_EGL_EVAL(disp, ret);
|
RETURN_EGL_EVAL(disp, ret);
|
||||||
}
|
}
|
||||||
|
|
@ -555,7 +555,7 @@ eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
|
||||||
_EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
|
_EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
|
||||||
|
|
||||||
surf = drv->API.CreatePbufferSurface(drv, disp, conf, attrib_list);
|
surf = drv->API.CreatePbufferSurface(drv, disp, conf, attrib_list);
|
||||||
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE;
|
ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
|
||||||
|
|
||||||
RETURN_EGL_EVAL(disp, ret);
|
RETURN_EGL_EVAL(disp, ret);
|
||||||
}
|
}
|
||||||
|
|
@ -648,11 +648,12 @@ eglSwapInterval(EGLDisplay dpy, EGLint interval)
|
||||||
|
|
||||||
_EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
|
_EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
|
||||||
|
|
||||||
if (!ctx || !_eglIsContextLinked(ctx) || ctx->Resource.Display != disp)
|
if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
|
||||||
|
ctx->Resource.Display != disp)
|
||||||
RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_FALSE);
|
RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_FALSE);
|
||||||
|
|
||||||
surf = ctx->DrawSurface;
|
surf = ctx->DrawSurface;
|
||||||
if (!_eglIsSurfaceLinked(surf))
|
if (_eglGetSurfaceHandle(surf) == EGL_NO_SURFACE)
|
||||||
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
|
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
|
||||||
|
|
||||||
ret = drv->API.SwapInterval(drv, disp, surf, interval);
|
ret = drv->API.SwapInterval(drv, disp, surf, interval);
|
||||||
|
|
@ -673,7 +674,8 @@ eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
|
||||||
_EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv);
|
_EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv);
|
||||||
|
|
||||||
/* surface must be bound to current context in EGL 1.4 */
|
/* surface must be bound to current context in EGL 1.4 */
|
||||||
if (!ctx || !_eglIsContextLinked(ctx) || surf != ctx->DrawSurface)
|
if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
|
||||||
|
surf != ctx->DrawSurface)
|
||||||
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
|
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
|
||||||
|
|
||||||
ret = drv->API.SwapBuffers(drv, disp, surf);
|
ret = drv->API.SwapBuffers(drv, disp, surf);
|
||||||
|
|
@ -714,7 +716,8 @@ eglWaitClient(void)
|
||||||
_eglLockMutex(&disp->Mutex);
|
_eglLockMutex(&disp->Mutex);
|
||||||
|
|
||||||
/* let bad current context imply bad current surface */
|
/* let bad current context imply bad current surface */
|
||||||
if (!_eglIsContextLinked(ctx) || !_eglIsSurfaceLinked(ctx->DrawSurface))
|
if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
|
||||||
|
_eglGetSurfaceHandle(ctx->DrawSurface) == EGL_NO_SURFACE)
|
||||||
RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
|
RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
|
||||||
|
|
||||||
/* a valid current context implies an initialized current display */
|
/* a valid current context implies an initialized current display */
|
||||||
|
|
@ -763,7 +766,8 @@ eglWaitNative(EGLint engine)
|
||||||
_eglLockMutex(&disp->Mutex);
|
_eglLockMutex(&disp->Mutex);
|
||||||
|
|
||||||
/* let bad current context imply bad current surface */
|
/* let bad current context imply bad current surface */
|
||||||
if (!_eglIsContextLinked(ctx) || !_eglIsSurfaceLinked(ctx->DrawSurface))
|
if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
|
||||||
|
_eglGetSurfaceHandle(ctx->DrawSurface) == EGL_NO_SURFACE)
|
||||||
RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
|
RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
|
||||||
|
|
||||||
/* a valid current context implies an initialized current display */
|
/* a valid current context implies an initialized current display */
|
||||||
|
|
@ -1043,7 +1047,7 @@ eglCreateScreenSurfaceMESA(EGLDisplay dpy, EGLConfig config,
|
||||||
_EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
|
_EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
|
||||||
|
|
||||||
surf = drv->API.CreateScreenSurfaceMESA(drv, disp, conf, attrib_list);
|
surf = drv->API.CreateScreenSurfaceMESA(drv, disp, conf, attrib_list);
|
||||||
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE;
|
ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
|
||||||
|
|
||||||
RETURN_EGL_EVAL(disp, ret);
|
RETURN_EGL_EVAL(disp, ret);
|
||||||
}
|
}
|
||||||
|
|
@ -1235,7 +1239,7 @@ eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype,
|
||||||
|
|
||||||
surf = drv->API.CreatePbufferFromClientBuffer(drv, disp, buftype, buffer,
|
surf = drv->API.CreatePbufferFromClientBuffer(drv, disp, buftype, buffer,
|
||||||
conf, attrib_list);
|
conf, attrib_list);
|
||||||
ret = (surf) ? _eglLinkSurface(surf, disp) : EGL_NO_SURFACE;
|
ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
|
||||||
|
|
||||||
RETURN_EGL_EVAL(disp, ret);
|
RETURN_EGL_EVAL(disp, ret);
|
||||||
}
|
}
|
||||||
|
|
@ -1298,7 +1302,7 @@ eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
|
||||||
|
|
||||||
img = drv->API.CreateImageKHR(drv,
|
img = drv->API.CreateImageKHR(drv,
|
||||||
disp, context, target, buffer, attr_list);
|
disp, context, target, buffer, attr_list);
|
||||||
ret = (img) ? _eglLinkImage(img, disp) : EGL_NO_IMAGE_KHR;
|
ret = (img) ? _eglLinkImage(img) : EGL_NO_IMAGE_KHR;
|
||||||
|
|
||||||
RETURN_EGL_EVAL(disp, ret);
|
RETURN_EGL_EVAL(disp, ret);
|
||||||
}
|
}
|
||||||
|
|
@ -1344,7 +1348,7 @@ eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
|
||||||
RETURN_EGL_EVAL(disp, EGL_NO_SYNC_KHR);
|
RETURN_EGL_EVAL(disp, EGL_NO_SYNC_KHR);
|
||||||
|
|
||||||
sync = drv->API.CreateSyncKHR(drv, disp, type, attrib_list);
|
sync = drv->API.CreateSyncKHR(drv, disp, type, attrib_list);
|
||||||
ret = (sync) ? _eglLinkSync(sync, disp) : EGL_NO_SYNC_KHR;
|
ret = (sync) ? _eglLinkSync(sync) : EGL_NO_SYNC_KHR;
|
||||||
|
|
||||||
RETURN_EGL_EVAL(disp, ret);
|
RETURN_EGL_EVAL(disp, ret);
|
||||||
}
|
}
|
||||||
|
|
@ -1437,7 +1441,8 @@ eglSwapBuffersRegionNOK(EGLDisplay dpy, EGLSurface surface,
|
||||||
RETURN_EGL_EVAL(disp, EGL_FALSE);
|
RETURN_EGL_EVAL(disp, EGL_FALSE);
|
||||||
|
|
||||||
/* surface must be bound to current context in EGL 1.4 */
|
/* surface must be bound to current context in EGL 1.4 */
|
||||||
if (!ctx || !_eglIsContextLinked(ctx) || surf != ctx->DrawSurface)
|
if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
|
||||||
|
surf != ctx->DrawSurface)
|
||||||
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
|
RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
|
||||||
|
|
||||||
ret = drv->API.SwapBuffersRegionNOK(drv, disp, surf, numRects, rects);
|
ret = drv->API.SwapBuffersRegionNOK(drv, disp, surf, numRects, rects);
|
||||||
|
|
@ -1463,7 +1468,7 @@ eglCreateDRMImageMESA(EGLDisplay dpy, const EGLint *attr_list)
|
||||||
RETURN_EGL_EVAL(disp, EGL_NO_IMAGE_KHR);
|
RETURN_EGL_EVAL(disp, EGL_NO_IMAGE_KHR);
|
||||||
|
|
||||||
img = drv->API.CreateDRMImageMESA(drv, disp, attr_list);
|
img = drv->API.CreateDRMImageMESA(drv, disp, attr_list);
|
||||||
ret = (img) ? _eglLinkImage(img, disp) : EGL_NO_IMAGE_KHR;
|
ret = (img) ? _eglLinkImage(img) : EGL_NO_IMAGE_KHR;
|
||||||
|
|
||||||
RETURN_EGL_EVAL(disp, ret);
|
RETURN_EGL_EVAL(disp, ret);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,34 +24,34 @@
|
||||||
* IDs are from 1 to N respectively.
|
* IDs are from 1 to N respectively.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_eglInitConfig(_EGLConfig *config, _EGLDisplay *dpy, EGLint id)
|
_eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id)
|
||||||
{
|
{
|
||||||
memset(config, 0, sizeof(*config));
|
memset(conf, 0, sizeof(*conf));
|
||||||
|
|
||||||
config->Display = dpy;
|
conf->Display = dpy;
|
||||||
|
|
||||||
/* some attributes take non-zero default values */
|
/* some attributes take non-zero default values */
|
||||||
SET_CONFIG_ATTRIB(config, EGL_CONFIG_ID, id);
|
conf->ConfigID = id;
|
||||||
SET_CONFIG_ATTRIB(config, EGL_CONFIG_CAVEAT, EGL_NONE);
|
conf->ConfigCaveat = EGL_NONE;
|
||||||
SET_CONFIG_ATTRIB(config, EGL_TRANSPARENT_TYPE, EGL_NONE);
|
conf->TransparentType = EGL_NONE;
|
||||||
SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, EGL_NONE);
|
conf->NativeVisualType = EGL_NONE;
|
||||||
#ifdef EGL_VERSION_1_2
|
conf->ColorBufferType = EGL_RGB_BUFFER;
|
||||||
SET_CONFIG_ATTRIB(config, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
|
|
||||||
#endif /* EGL_VERSION_1_2 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link a config to a display and return the handle of the link.
|
* Link a config to its display and return the handle of the link.
|
||||||
* The handle can be passed to client directly.
|
* The handle can be passed to client directly.
|
||||||
*
|
*
|
||||||
* Note that we just save the ptr to the config (we don't copy the config).
|
* Note that we just save the ptr to the config (we don't copy the config).
|
||||||
*/
|
*/
|
||||||
EGLConfig
|
PUBLIC EGLConfig
|
||||||
_eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf)
|
_eglLinkConfig(_EGLConfig *conf)
|
||||||
{
|
{
|
||||||
|
_EGLDisplay *dpy = conf->Display;
|
||||||
|
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
assert(GET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID) > 0);
|
assert(dpy && conf->ConfigID > 0);
|
||||||
|
|
||||||
if (!dpy->Configs) {
|
if (!dpy->Configs) {
|
||||||
dpy->Configs = _eglCreateArray("Config", 16);
|
dpy->Configs = _eglCreateArray("Config", 16);
|
||||||
|
|
@ -59,23 +59,29 @@ _eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf)
|
||||||
return (EGLConfig) NULL;
|
return (EGLConfig) NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
conf->Display = dpy;
|
|
||||||
_eglAppendArray(dpy->Configs, (void *) conf);
|
_eglAppendArray(dpy->Configs, (void *) conf);
|
||||||
|
|
||||||
return (EGLConfig) conf;
|
return (EGLConfig) conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
/**
|
||||||
_eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy)
|
* Lookup a handle to find the linked config.
|
||||||
|
* Return NULL if the handle has no corresponding linked config.
|
||||||
|
*/
|
||||||
|
_EGLConfig *
|
||||||
|
_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy)
|
||||||
{
|
{
|
||||||
_EGLConfig *conf;
|
_EGLConfig *conf;
|
||||||
|
|
||||||
|
if (!dpy)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config);
|
conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config);
|
||||||
if (conf)
|
if (conf)
|
||||||
assert(conf->Display == dpy);
|
assert(conf->Display == dpy);
|
||||||
|
|
||||||
return (conf != NULL);
|
return conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -104,6 +110,7 @@ static const struct {
|
||||||
EGLint default_value;
|
EGLint default_value;
|
||||||
} _eglValidationTable[] =
|
} _eglValidationTable[] =
|
||||||
{
|
{
|
||||||
|
/* core */
|
||||||
{ EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER,
|
{ EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER,
|
||||||
ATTRIB_CRITERION_ATLEAST,
|
ATTRIB_CRITERION_ATLEAST,
|
||||||
0 },
|
0 },
|
||||||
|
|
@ -200,22 +207,13 @@ static const struct {
|
||||||
{ EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER,
|
{ EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER,
|
||||||
ATTRIB_CRITERION_EXACT,
|
ATTRIB_CRITERION_EXACT,
|
||||||
EGL_DONT_CARE },
|
EGL_DONT_CARE },
|
||||||
/* these are not real attributes */
|
|
||||||
{ EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO,
|
{ EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO,
|
||||||
ATTRIB_CRITERION_SPECIAL,
|
ATTRIB_CRITERION_SPECIAL,
|
||||||
EGL_NONE },
|
EGL_NONE },
|
||||||
/* there is a gap before EGL_SAMPLES */
|
/* extensions */
|
||||||
{ 0x3030, ATTRIB_TYPE_PSEUDO,
|
|
||||||
ATTRIB_CRITERION_IGNORE,
|
|
||||||
0 },
|
|
||||||
{ EGL_NONE, ATTRIB_TYPE_PSEUDO,
|
|
||||||
ATTRIB_CRITERION_IGNORE,
|
|
||||||
0 },
|
|
||||||
|
|
||||||
{ EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN,
|
{ EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN,
|
||||||
ATTRIB_CRITERION_EXACT,
|
ATTRIB_CRITERION_EXACT,
|
||||||
EGL_DONT_CARE },
|
EGL_DONT_CARE }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -232,18 +230,13 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
|
||||||
{
|
{
|
||||||
EGLint i, attr, val;
|
EGLint i, attr, val;
|
||||||
EGLBoolean valid = EGL_TRUE;
|
EGLBoolean valid = EGL_TRUE;
|
||||||
EGLint red_size = 0, green_size = 0, blue_size = 0, luminance_size = 0;
|
|
||||||
EGLint alpha_size = 0, buffer_size = 0;
|
|
||||||
|
|
||||||
/* all attributes should have been listed */
|
|
||||||
assert(ARRAY_SIZE(_eglValidationTable) == _EGL_CONFIG_NUM_ATTRIBS);
|
|
||||||
|
|
||||||
/* check attributes by their types */
|
/* check attributes by their types */
|
||||||
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
|
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
|
||||||
EGLint mask;
|
EGLint mask;
|
||||||
|
|
||||||
attr = _eglValidationTable[i].attr;
|
attr = _eglValidationTable[i].attr;
|
||||||
val = GET_CONFIG_ATTRIB(conf, attr);
|
val = _eglGetConfigKey(conf, attr);
|
||||||
|
|
||||||
switch (_eglValidationTable[i].type) {
|
switch (_eglValidationTable[i].type) {
|
||||||
case ATTRIB_TYPE_INTEGER:
|
case ATTRIB_TYPE_INTEGER:
|
||||||
|
|
@ -255,31 +248,15 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
|
||||||
break;
|
break;
|
||||||
case EGL_SAMPLE_BUFFERS:
|
case EGL_SAMPLE_BUFFERS:
|
||||||
/* there can be at most 1 sample buffer */
|
/* there can be at most 1 sample buffer */
|
||||||
if (val > 1)
|
if (val > 1 || val < 0)
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
break;
|
break;
|
||||||
case EGL_RED_SIZE:
|
default:
|
||||||
red_size = val;
|
|
||||||
break;
|
|
||||||
case EGL_GREEN_SIZE:
|
|
||||||
green_size = val;
|
|
||||||
break;
|
|
||||||
case EGL_BLUE_SIZE:
|
|
||||||
blue_size = val;
|
|
||||||
break;
|
|
||||||
case EGL_LUMINANCE_SIZE:
|
|
||||||
luminance_size = val;
|
|
||||||
break;
|
|
||||||
case EGL_ALPHA_SIZE:
|
|
||||||
alpha_size = val;
|
|
||||||
break;
|
|
||||||
case EGL_BUFFER_SIZE:
|
|
||||||
buffer_size = val;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ATTRIB_TYPE_BOOLEAN:
|
case ATTRIB_TYPE_BOOLEAN:
|
||||||
if (val != EGL_TRUE && val != EGL_FALSE)
|
if (val != EGL_TRUE && val != EGL_FALSE)
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
|
|
@ -366,17 +343,18 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
|
||||||
|
|
||||||
/* now check for conflicting attribute values */
|
/* now check for conflicting attribute values */
|
||||||
|
|
||||||
switch (GET_CONFIG_ATTRIB(conf, EGL_COLOR_BUFFER_TYPE)) {
|
switch (conf->ColorBufferType) {
|
||||||
case EGL_RGB_BUFFER:
|
case EGL_RGB_BUFFER:
|
||||||
if (luminance_size)
|
if (conf->LuminanceSize)
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
if (red_size + green_size + blue_size + alpha_size != buffer_size)
|
if (conf->RedSize + conf->GreenSize +
|
||||||
|
conf->BlueSize + conf->AlphaSize != conf->BufferSize)
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
break;
|
break;
|
||||||
case EGL_LUMINANCE_BUFFER:
|
case EGL_LUMINANCE_BUFFER:
|
||||||
if (red_size || green_size || blue_size)
|
if (conf->RedSize || conf->GreenSize || conf->BlueSize)
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
if (luminance_size + alpha_size != buffer_size)
|
if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -385,23 +363,19 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = GET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS);
|
if (!conf->SampleBuffers && conf->Samples)
|
||||||
if (!val && GET_CONFIG_ATTRIB(conf, EGL_SAMPLES))
|
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
_eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
|
_eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
|
if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
|
||||||
if (!(val & EGL_WINDOW_BIT)) {
|
if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
|
||||||
if (GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID) != 0 ||
|
|
||||||
GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE) != EGL_NONE)
|
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
}
|
}
|
||||||
if (!(val & EGL_PBUFFER_BIT)) {
|
if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
|
||||||
if (GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB) ||
|
if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
|
||||||
GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA))
|
|
||||||
valid = EGL_FALSE;
|
valid = EGL_FALSE;
|
||||||
}
|
}
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
|
|
@ -433,11 +407,11 @@ _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
attr = _eglValidationTable[i].attr;
|
attr = _eglValidationTable[i].attr;
|
||||||
cmp = GET_CONFIG_ATTRIB(criteria, attr);
|
cmp = _eglGetConfigKey(criteria, attr);
|
||||||
if (cmp == EGL_DONT_CARE)
|
if (cmp == EGL_DONT_CARE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
val = GET_CONFIG_ATTRIB(conf, attr);
|
val = _eglGetConfigKey(conf, attr);
|
||||||
switch (_eglValidationTable[i].criterion) {
|
switch (_eglValidationTable[i].criterion) {
|
||||||
case ATTRIB_CRITERION_EXACT:
|
case ATTRIB_CRITERION_EXACT:
|
||||||
if (val != cmp)
|
if (val != cmp)
|
||||||
|
|
@ -478,16 +452,11 @@ _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
|
||||||
static INLINE EGLBoolean
|
static INLINE EGLBoolean
|
||||||
_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
|
_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
|
||||||
{
|
{
|
||||||
if (_eglIndexConfig(conf, attr) < 0)
|
if (_eglOffsetOfConfig(attr) < 0)
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
/* there are some holes in the range */
|
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
case 0x3030 /* a gap before EGL_SAMPLES */:
|
|
||||||
case EGL_NONE:
|
|
||||||
#ifdef EGL_VERSION_1_4
|
|
||||||
case EGL_MATCH_NATIVE_PIXMAP:
|
case EGL_MATCH_NATIVE_PIXMAP:
|
||||||
#endif
|
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
case EGL_Y_INVERTED_NOK:
|
case EGL_Y_INVERTED_NOK:
|
||||||
return conf->Display->Extensions.NOK_texture_from_pixmap;
|
return conf->Display->Extensions.NOK_texture_from_pixmap;
|
||||||
|
|
@ -503,18 +472,18 @@ _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
|
||||||
* Return EGL_FALSE if any of the attribute is invalid.
|
* Return EGL_FALSE if any of the attribute is invalid.
|
||||||
*/
|
*/
|
||||||
EGLBoolean
|
EGLBoolean
|
||||||
_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list)
|
_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
|
||||||
|
const EGLint *attrib_list)
|
||||||
{
|
{
|
||||||
EGLint attr, val, i;
|
EGLint attr, val, i;
|
||||||
EGLint config_id = 0, level = 0;
|
|
||||||
EGLBoolean has_native_visual_type = EGL_FALSE;
|
_eglInitConfig(conf, dpy, EGL_DONT_CARE);
|
||||||
EGLBoolean has_transparent_color = EGL_FALSE;
|
|
||||||
|
|
||||||
/* reset to default values */
|
/* reset to default values */
|
||||||
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
|
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
|
||||||
attr = _eglValidationTable[i].attr;
|
attr = _eglValidationTable[i].attr;
|
||||||
val = _eglValidationTable[i].default_value;
|
val = _eglValidationTable[i].default_value;
|
||||||
SET_CONFIG_ATTRIB(conf, attr, val);
|
_eglSetConfigKey(conf, attr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse the list */
|
/* parse the list */
|
||||||
|
|
@ -525,58 +494,32 @@ _eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list)
|
||||||
if (!_eglIsConfigAttribValid(conf, attr))
|
if (!_eglIsConfigAttribValid(conf, attr))
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
SET_CONFIG_ATTRIB(conf, attr, val);
|
_eglSetConfigKey(conf, attr, val);
|
||||||
|
|
||||||
/* rememeber some attributes for post-processing */
|
|
||||||
switch (attr) {
|
|
||||||
case EGL_CONFIG_ID:
|
|
||||||
config_id = val;
|
|
||||||
break;
|
|
||||||
case EGL_LEVEL:
|
|
||||||
level = val;
|
|
||||||
break;
|
|
||||||
case EGL_NATIVE_VISUAL_TYPE:
|
|
||||||
has_native_visual_type = EGL_TRUE;
|
|
||||||
break;
|
|
||||||
case EGL_TRANSPARENT_RED_VALUE:
|
|
||||||
case EGL_TRANSPARENT_GREEN_VALUE:
|
|
||||||
case EGL_TRANSPARENT_BLUE_VALUE:
|
|
||||||
has_transparent_color = EGL_TRUE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_eglValidateConfig(conf, EGL_TRUE))
|
if (!_eglValidateConfig(conf, EGL_TRUE))
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
/* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */
|
/* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */
|
||||||
if (level == EGL_DONT_CARE)
|
if (conf->Level == EGL_DONT_CARE)
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
/* ignore other attributes when EGL_CONFIG_ID is given */
|
/* ignore other attributes when EGL_CONFIG_ID is given */
|
||||||
if (config_id > 0) {
|
if (conf->ConfigID != EGL_DONT_CARE) {
|
||||||
_eglResetConfigKeys(conf, EGL_DONT_CARE);
|
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
|
||||||
SET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID, config_id);
|
attr = _eglValidationTable[i].attr;
|
||||||
|
if (attr != EGL_CONFIG_ID)
|
||||||
|
_eglSetConfigKey(conf, attr, EGL_DONT_CARE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (has_native_visual_type) {
|
if (!(conf->SurfaceType & EGL_WINDOW_BIT))
|
||||||
val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
|
conf->NativeVisualType = EGL_DONT_CARE;
|
||||||
if (!(val & EGL_WINDOW_BIT))
|
|
||||||
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_transparent_color) {
|
if (conf->TransparentType == EGL_NONE) {
|
||||||
val = GET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE);
|
conf->TransparentRedValue = EGL_DONT_CARE;
|
||||||
if (val == EGL_NONE) {
|
conf->TransparentGreenValue = EGL_DONT_CARE;
|
||||||
SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE,
|
conf->TransparentBlueValue = EGL_DONT_CARE;
|
||||||
EGL_DONT_CARE);
|
|
||||||
SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE,
|
|
||||||
EGL_DONT_CARE);
|
|
||||||
SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE,
|
|
||||||
EGL_DONT_CARE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -610,7 +553,6 @@ _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
|
||||||
EGL_ALPHA_MASK_SIZE,
|
EGL_ALPHA_MASK_SIZE,
|
||||||
};
|
};
|
||||||
EGLint val1, val2;
|
EGLint val1, val2;
|
||||||
EGLBoolean rgb_buffer;
|
|
||||||
EGLint i;
|
EGLint i;
|
||||||
|
|
||||||
if (conf1 == conf2)
|
if (conf1 == conf2)
|
||||||
|
|
@ -619,44 +561,41 @@ _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
|
||||||
/* the enum values have the desired ordering */
|
/* the enum values have the desired ordering */
|
||||||
assert(EGL_NONE < EGL_SLOW_CONFIG);
|
assert(EGL_NONE < EGL_SLOW_CONFIG);
|
||||||
assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
|
assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
|
||||||
val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_CAVEAT);
|
val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
|
||||||
val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_CAVEAT);
|
if (val1)
|
||||||
if (val1 != val2)
|
return val1;
|
||||||
return (val1 - val2);
|
|
||||||
|
|
||||||
/* the enum values have the desired ordering */
|
/* the enum values have the desired ordering */
|
||||||
assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
|
assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
|
||||||
val1 = GET_CONFIG_ATTRIB(conf1, EGL_COLOR_BUFFER_TYPE);
|
val1 = conf1->ColorBufferType - conf2->ColorBufferType;
|
||||||
val2 = GET_CONFIG_ATTRIB(conf2, EGL_COLOR_BUFFER_TYPE);
|
if (val1)
|
||||||
if (val1 != val2)
|
return val1;
|
||||||
return (val1 - val2);
|
|
||||||
rgb_buffer = (val1 == EGL_RGB_BUFFER);
|
|
||||||
|
|
||||||
if (criteria) {
|
if (criteria) {
|
||||||
val1 = val2 = 0;
|
val1 = val2 = 0;
|
||||||
if (rgb_buffer) {
|
if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
|
||||||
if (GET_CONFIG_ATTRIB(criteria, EGL_RED_SIZE) > 0) {
|
if (criteria->RedSize > 0) {
|
||||||
val1 += GET_CONFIG_ATTRIB(conf1, EGL_RED_SIZE);
|
val1 += conf1->RedSize;
|
||||||
val2 += GET_CONFIG_ATTRIB(conf2, EGL_RED_SIZE);
|
val2 += conf2->RedSize;
|
||||||
}
|
}
|
||||||
if (GET_CONFIG_ATTRIB(criteria, EGL_GREEN_SIZE) > 0) {
|
if (criteria->GreenSize > 0) {
|
||||||
val1 += GET_CONFIG_ATTRIB(conf1, EGL_GREEN_SIZE);
|
val1 += conf1->GreenSize;
|
||||||
val2 += GET_CONFIG_ATTRIB(conf2, EGL_GREEN_SIZE);
|
val2 += conf2->GreenSize;
|
||||||
}
|
}
|
||||||
if (GET_CONFIG_ATTRIB(criteria, EGL_BLUE_SIZE) > 0) {
|
if (criteria->BlueSize > 0) {
|
||||||
val1 += GET_CONFIG_ATTRIB(conf1, EGL_BLUE_SIZE);
|
val1 += conf1->BlueSize;
|
||||||
val2 += GET_CONFIG_ATTRIB(conf2, EGL_BLUE_SIZE);
|
val2 += conf2->BlueSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (GET_CONFIG_ATTRIB(criteria, EGL_LUMINANCE_SIZE) > 0) {
|
if (criteria->LuminanceSize > 0) {
|
||||||
val1 += GET_CONFIG_ATTRIB(conf1, EGL_LUMINANCE_SIZE);
|
val1 += conf1->LuminanceSize;
|
||||||
val2 += GET_CONFIG_ATTRIB(conf2, EGL_LUMINANCE_SIZE);
|
val2 += conf2->LuminanceSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (GET_CONFIG_ATTRIB(criteria, EGL_ALPHA_SIZE) > 0) {
|
if (criteria->AlphaSize > 0) {
|
||||||
val1 += GET_CONFIG_ATTRIB(conf1, EGL_ALPHA_SIZE);
|
val1 += conf1->AlphaSize;
|
||||||
val2 += GET_CONFIG_ATTRIB(conf2, EGL_ALPHA_SIZE);
|
val2 += conf2->AlphaSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -669,24 +608,15 @@ _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
|
||||||
return (val2 - val1);
|
return (val2 - val1);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
|
for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
|
||||||
val1 = GET_CONFIG_ATTRIB(conf1, compare_attribs[i]);
|
val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
|
||||||
val2 = GET_CONFIG_ATTRIB(conf2, compare_attribs[i]);
|
val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
|
||||||
if (val1 != val2)
|
if (val1 != val2)
|
||||||
return (val1 - val2);
|
return (val1 - val2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
|
/* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
|
||||||
|
|
||||||
if (compare_id) {
|
return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
|
||||||
val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_ID);
|
|
||||||
val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_ID);
|
|
||||||
assert(val1 != val2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val1 = val2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (val1 - val2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -764,8 +694,7 @@ _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
|
||||||
if (!num_configs)
|
if (!num_configs)
|
||||||
return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
|
return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
|
||||||
|
|
||||||
_eglInitConfig(&criteria, disp, 0);
|
if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
|
||||||
if (!_eglParseConfigAttribList(&criteria, attrib_list))
|
|
||||||
return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
|
return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
|
||||||
|
|
||||||
configList = (_EGLConfig **) _eglFilterArray(disp->Configs, &count,
|
configList = (_EGLConfig **) _eglFilterArray(disp->Configs, &count,
|
||||||
|
|
@ -802,7 +731,7 @@ _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
|
||||||
if (!value)
|
if (!value)
|
||||||
return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
|
return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
|
||||||
|
|
||||||
*value = GET_CONFIG_ATTRIB(conf, attribute);
|
*value = _eglGetConfigKey(conf, attribute);
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,69 +6,103 @@
|
||||||
#include "egltypedefs.h"
|
#include "egltypedefs.h"
|
||||||
|
|
||||||
|
|
||||||
#define _EGL_CONFIG_FIRST_ATTRIB EGL_BUFFER_SIZE
|
/* update _eglValidationTable and _eglOffsetOfConfig before updating this
|
||||||
#define _EGL_CONFIG_LAST_ATTRIB EGL_CONFORMANT
|
* struct */
|
||||||
#define _EGL_CONFIG_NUM_CONTIGUOUS_ATTRIBS \
|
|
||||||
(_EGL_CONFIG_LAST_ATTRIB - _EGL_CONFIG_FIRST_ATTRIB + 1)
|
|
||||||
|
|
||||||
/* Attributes outside the contiguous block:
|
|
||||||
*
|
|
||||||
* EGL_Y_INVERTED_NOK
|
|
||||||
*/
|
|
||||||
#define _EGL_CONFIG_FIRST_EXTRA_ATTRIB _EGL_CONFIG_NUM_CONTIGUOUS_ATTRIBS
|
|
||||||
#define _EGL_CONFIG_NUM_EXTRA_ATTRIBS 1
|
|
||||||
|
|
||||||
#define _EGL_CONFIG_NUM_ATTRIBS \
|
|
||||||
_EGL_CONFIG_NUM_CONTIGUOUS_ATTRIBS + _EGL_CONFIG_NUM_EXTRA_ATTRIBS
|
|
||||||
|
|
||||||
|
|
||||||
struct _egl_config
|
struct _egl_config
|
||||||
{
|
{
|
||||||
_EGLDisplay *Display;
|
_EGLDisplay *Display;
|
||||||
EGLint Storage[_EGL_CONFIG_NUM_ATTRIBS];
|
|
||||||
|
/* core */
|
||||||
|
EGLint BufferSize;
|
||||||
|
EGLint AlphaSize;
|
||||||
|
EGLint BlueSize;
|
||||||
|
EGLint GreenSize;
|
||||||
|
EGLint RedSize;
|
||||||
|
EGLint DepthSize;
|
||||||
|
EGLint StencilSize;
|
||||||
|
EGLint ConfigCaveat;
|
||||||
|
EGLint ConfigID;
|
||||||
|
EGLint Level;
|
||||||
|
EGLint MaxPbufferHeight;
|
||||||
|
EGLint MaxPbufferPixels;
|
||||||
|
EGLint MaxPbufferWidth;
|
||||||
|
EGLint NativeRenderable;
|
||||||
|
EGLint NativeVisualID;
|
||||||
|
EGLint NativeVisualType;
|
||||||
|
EGLint Samples;
|
||||||
|
EGLint SampleBuffers;
|
||||||
|
EGLint SurfaceType;
|
||||||
|
EGLint TransparentType;
|
||||||
|
EGLint TransparentBlueValue;
|
||||||
|
EGLint TransparentGreenValue;
|
||||||
|
EGLint TransparentRedValue;
|
||||||
|
EGLint BindToTextureRGB;
|
||||||
|
EGLint BindToTextureRGBA;
|
||||||
|
EGLint MinSwapInterval;
|
||||||
|
EGLint MaxSwapInterval;
|
||||||
|
EGLint LuminanceSize;
|
||||||
|
EGLint AlphaMaskSize;
|
||||||
|
EGLint ColorBufferType;
|
||||||
|
EGLint RenderableType;
|
||||||
|
EGLint MatchNativePixmap;
|
||||||
|
EGLint Conformant;
|
||||||
|
|
||||||
|
/* extensions */
|
||||||
|
EGLint YInvertedNOK;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Macros for source level compatibility.
|
* Map an EGL attribute enum to the offset of the member in _EGLConfig.
|
||||||
*/
|
|
||||||
#define SET_CONFIG_ATTRIB(CONF, ATTR, VAL) _eglSetConfigKey(CONF, ATTR, VAL)
|
|
||||||
#define GET_CONFIG_ATTRIB(CONF, ATTR) _eglGetConfigKey(CONF, ATTR)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a key, return an index into the storage of the config.
|
|
||||||
* Return -1 if the key is invalid.
|
|
||||||
*/
|
*/
|
||||||
static INLINE EGLint
|
static INLINE EGLint
|
||||||
_eglIndexConfig(const _EGLConfig *conf, EGLint key)
|
_eglOffsetOfConfig(EGLint attr)
|
||||||
{
|
{
|
||||||
(void) conf;
|
switch (attr) {
|
||||||
if (key >= _EGL_CONFIG_FIRST_ATTRIB &&
|
#define ATTRIB_MAP(attr, memb) case attr: return offsetof(_EGLConfig, memb)
|
||||||
key < _EGL_CONFIG_FIRST_ATTRIB + _EGL_CONFIG_NUM_CONTIGUOUS_ATTRIBS)
|
/* core */
|
||||||
return key - _EGL_CONFIG_FIRST_ATTRIB;
|
ATTRIB_MAP(EGL_BUFFER_SIZE, BufferSize);
|
||||||
|
ATTRIB_MAP(EGL_ALPHA_SIZE, AlphaSize);
|
||||||
switch (key) {
|
ATTRIB_MAP(EGL_BLUE_SIZE, BlueSize);
|
||||||
case EGL_Y_INVERTED_NOK:
|
ATTRIB_MAP(EGL_GREEN_SIZE, GreenSize);
|
||||||
return _EGL_CONFIG_FIRST_EXTRA_ATTRIB;
|
ATTRIB_MAP(EGL_RED_SIZE, RedSize);
|
||||||
|
ATTRIB_MAP(EGL_DEPTH_SIZE, DepthSize);
|
||||||
|
ATTRIB_MAP(EGL_STENCIL_SIZE, StencilSize);
|
||||||
|
ATTRIB_MAP(EGL_CONFIG_CAVEAT, ConfigCaveat);
|
||||||
|
ATTRIB_MAP(EGL_CONFIG_ID, ConfigID);
|
||||||
|
ATTRIB_MAP(EGL_LEVEL, Level);
|
||||||
|
ATTRIB_MAP(EGL_MAX_PBUFFER_HEIGHT, MaxPbufferHeight);
|
||||||
|
ATTRIB_MAP(EGL_MAX_PBUFFER_PIXELS, MaxPbufferPixels);
|
||||||
|
ATTRIB_MAP(EGL_MAX_PBUFFER_WIDTH, MaxPbufferWidth);
|
||||||
|
ATTRIB_MAP(EGL_NATIVE_RENDERABLE, NativeRenderable);
|
||||||
|
ATTRIB_MAP(EGL_NATIVE_VISUAL_ID, NativeVisualID);
|
||||||
|
ATTRIB_MAP(EGL_NATIVE_VISUAL_TYPE, NativeVisualType);
|
||||||
|
ATTRIB_MAP(EGL_SAMPLES, Samples);
|
||||||
|
ATTRIB_MAP(EGL_SAMPLE_BUFFERS, SampleBuffers);
|
||||||
|
ATTRIB_MAP(EGL_SURFACE_TYPE, SurfaceType);
|
||||||
|
ATTRIB_MAP(EGL_TRANSPARENT_TYPE, TransparentType);
|
||||||
|
ATTRIB_MAP(EGL_TRANSPARENT_BLUE_VALUE, TransparentBlueValue);
|
||||||
|
ATTRIB_MAP(EGL_TRANSPARENT_GREEN_VALUE, TransparentGreenValue);
|
||||||
|
ATTRIB_MAP(EGL_TRANSPARENT_RED_VALUE, TransparentRedValue);
|
||||||
|
ATTRIB_MAP(EGL_BIND_TO_TEXTURE_RGB, BindToTextureRGB);
|
||||||
|
ATTRIB_MAP(EGL_BIND_TO_TEXTURE_RGBA, BindToTextureRGBA);
|
||||||
|
ATTRIB_MAP(EGL_MIN_SWAP_INTERVAL, MinSwapInterval);
|
||||||
|
ATTRIB_MAP(EGL_MAX_SWAP_INTERVAL, MaxSwapInterval);
|
||||||
|
ATTRIB_MAP(EGL_LUMINANCE_SIZE, LuminanceSize);
|
||||||
|
ATTRIB_MAP(EGL_ALPHA_MASK_SIZE, AlphaMaskSize);
|
||||||
|
ATTRIB_MAP(EGL_COLOR_BUFFER_TYPE, ColorBufferType);
|
||||||
|
ATTRIB_MAP(EGL_RENDERABLE_TYPE, RenderableType);
|
||||||
|
ATTRIB_MAP(EGL_MATCH_NATIVE_PIXMAP, MatchNativePixmap);
|
||||||
|
ATTRIB_MAP(EGL_CONFORMANT, Conformant);
|
||||||
|
/* extensions */
|
||||||
|
ATTRIB_MAP(EGL_Y_INVERTED_NOK, YInvertedNOK);
|
||||||
|
#undef ATTRIB_MAP
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset all keys in the config to a given value.
|
|
||||||
*/
|
|
||||||
static INLINE void
|
|
||||||
_eglResetConfigKeys(_EGLConfig *conf, EGLint val)
|
|
||||||
{
|
|
||||||
EGLint i;
|
|
||||||
for (i = 0; i < _EGL_CONFIG_NUM_ATTRIBS; i++)
|
|
||||||
conf->Storage[i] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a config for a given key.
|
* Update a config for a given key.
|
||||||
*
|
*
|
||||||
|
|
@ -79,9 +113,9 @@ _eglResetConfigKeys(_EGLConfig *conf, EGLint val)
|
||||||
static INLINE void
|
static INLINE void
|
||||||
_eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val)
|
_eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val)
|
||||||
{
|
{
|
||||||
EGLint idx = _eglIndexConfig(conf, key);
|
EGLint offset = _eglOffsetOfConfig(key);
|
||||||
assert(idx >= 0);
|
assert(offset >= 0);
|
||||||
conf->Storage[idx] = val;
|
*((EGLint *) ((char *) conf + offset)) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -91,9 +125,9 @@ _eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val)
|
||||||
static INLINE EGLint
|
static INLINE EGLint
|
||||||
_eglGetConfigKey(const _EGLConfig *conf, EGLint key)
|
_eglGetConfigKey(const _EGLConfig *conf, EGLint key)
|
||||||
{
|
{
|
||||||
EGLint idx = _eglIndexConfig(conf, key);
|
EGLint offset = _eglOffsetOfConfig(key);
|
||||||
assert(idx >= 0);
|
assert(offset >= 0);
|
||||||
return conf->Storage[idx];
|
return *((EGLint *) ((char *) conf + offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -102,34 +136,20 @@ _eglInitConfig(_EGLConfig *config, _EGLDisplay *dpy, EGLint id);
|
||||||
|
|
||||||
|
|
||||||
PUBLIC EGLConfig
|
PUBLIC EGLConfig
|
||||||
_eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf);
|
_eglLinkConfig(_EGLConfig *conf);
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern _EGLConfig *
|
||||||
_eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy);
|
_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup a handle to find the linked config.
|
* Return the handle of a linked config.
|
||||||
* Return NULL if the handle has no corresponding linked config.
|
|
||||||
*/
|
|
||||||
static INLINE _EGLConfig *
|
|
||||||
_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy)
|
|
||||||
{
|
|
||||||
_EGLConfig *conf = (_EGLConfig *) config;
|
|
||||||
if (!dpy || !_eglCheckConfigHandle(config, dpy))
|
|
||||||
conf = NULL;
|
|
||||||
return conf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the handle of a linked config, or NULL.
|
|
||||||
*/
|
*/
|
||||||
static INLINE EGLConfig
|
static INLINE EGLConfig
|
||||||
_eglGetConfigHandle(_EGLConfig *conf)
|
_eglGetConfigHandle(_EGLConfig *conf)
|
||||||
{
|
{
|
||||||
return (EGLConfig) ((conf && conf->Display) ? conf : NULL);
|
return (EGLConfig) conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -142,7 +162,8 @@ _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria);
|
||||||
|
|
||||||
|
|
||||||
PUBLIC EGLBoolean
|
PUBLIC EGLBoolean
|
||||||
_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list);
|
_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
|
||||||
|
const EGLint *attrib_list);
|
||||||
|
|
||||||
|
|
||||||
PUBLIC EGLint
|
PUBLIC EGLint
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,7 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(ctx, 0, sizeof(_EGLContext));
|
_eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
|
||||||
ctx->Resource.Display = dpy;
|
|
||||||
ctx->ClientAPI = api;
|
ctx->ClientAPI = api;
|
||||||
ctx->Config = conf;
|
ctx->Config = conf;
|
||||||
ctx->WindowRenderBuffer = EGL_NONE;
|
ctx->WindowRenderBuffer = EGL_NONE;
|
||||||
|
|
@ -113,13 +112,12 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
|
||||||
|
|
||||||
err = _eglParseContextAttribList(ctx, attrib_list);
|
err = _eglParseContextAttribList(ctx, attrib_list);
|
||||||
if (err == EGL_SUCCESS && ctx->Config) {
|
if (err == EGL_SUCCESS && ctx->Config) {
|
||||||
EGLint renderable_type, api_bit;
|
EGLint api_bit;
|
||||||
|
|
||||||
renderable_type = GET_CONFIG_ATTRIB(ctx->Config, EGL_RENDERABLE_TYPE);
|
|
||||||
api_bit = _eglGetContextAPIBit(ctx);
|
api_bit = _eglGetContextAPIBit(ctx);
|
||||||
if (!(renderable_type & api_bit)) {
|
if (!(ctx->Config->RenderableType & api_bit)) {
|
||||||
_eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
|
_eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
|
||||||
api_bit, renderable_type);
|
api_bit, ctx->Config->RenderableType);
|
||||||
err = EGL_BAD_CONFIG;
|
err = EGL_BAD_CONFIG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -130,29 +128,6 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Just a placeholder/demo function. Real driver will never use this!
|
|
||||||
*/
|
|
||||||
_EGLContext *
|
|
||||||
_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
|
|
||||||
_EGLContext *share_list, const EGLint *attrib_list)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default fallback routine - drivers should usually override this.
|
|
||||||
*/
|
|
||||||
EGLBoolean
|
|
||||||
_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
|
|
||||||
{
|
|
||||||
if (!_eglIsContextBound(ctx))
|
|
||||||
free(ctx);
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef EGL_VERSION_1_2
|
#ifdef EGL_VERSION_1_2
|
||||||
static EGLint
|
static EGLint
|
||||||
_eglQueryContextRenderBuffer(_EGLContext *ctx)
|
_eglQueryContextRenderBuffer(_EGLContext *ctx)
|
||||||
|
|
@ -183,7 +158,9 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
|
||||||
|
|
||||||
switch (attribute) {
|
switch (attribute) {
|
||||||
case EGL_CONFIG_ID:
|
case EGL_CONFIG_ID:
|
||||||
*value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID);
|
if (!c->Config)
|
||||||
|
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
|
||||||
|
*value = c->Config->ConfigID;
|
||||||
break;
|
break;
|
||||||
case EGL_CONTEXT_CLIENT_VERSION:
|
case EGL_CONTEXT_CLIENT_VERSION:
|
||||||
*value = c->ClientVersion;
|
*value = c->ClientVersion;
|
||||||
|
|
@ -272,10 +249,6 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
|
||||||
if (!surfaceless && (draw == NULL || read == NULL))
|
if (!surfaceless && (draw == NULL || read == NULL))
|
||||||
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
|
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
|
||||||
|
|
||||||
/* context stealing from another thread is not allowed */
|
|
||||||
if (ctx->Binding && ctx->Binding != t)
|
|
||||||
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The spec says
|
* The spec says
|
||||||
*
|
*
|
||||||
|
|
@ -283,16 +256,23 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
|
||||||
* bound to contexts in another thread, an EGL_BAD_ACCESS error is
|
* bound to contexts in another thread, an EGL_BAD_ACCESS error is
|
||||||
* generated."
|
* generated."
|
||||||
*
|
*
|
||||||
* But it also says
|
* and
|
||||||
*
|
*
|
||||||
* "at most one context may be bound to a particular surface at a given
|
* "at most one context may be bound to a particular surface at a given
|
||||||
* time"
|
* time"
|
||||||
*
|
|
||||||
* The latter is more restrictive so we can check only the latter case.
|
|
||||||
*/
|
*/
|
||||||
if ((draw && draw->CurrentContext && draw->CurrentContext != ctx) ||
|
if (ctx->Binding && ctx->Binding != t)
|
||||||
(read && read->CurrentContext && read->CurrentContext != ctx))
|
|
||||||
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
|
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
|
||||||
|
if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
|
||||||
|
if (draw->CurrentContext->Binding != t ||
|
||||||
|
draw->CurrentContext->ClientAPI != ctx->ClientAPI)
|
||||||
|
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
|
||||||
|
}
|
||||||
|
if (read && read->CurrentContext && read->CurrentContext != ctx) {
|
||||||
|
if (read->CurrentContext->Binding != t ||
|
||||||
|
read->CurrentContext->ClientAPI != ctx->ClientAPI)
|
||||||
|
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
|
||||||
|
}
|
||||||
|
|
||||||
/* simply require the configs to be equal */
|
/* simply require the configs to be equal */
|
||||||
if ((draw && draw->Config != ctx->Config) ||
|
if ((draw && draw->Config != ctx->Config) ||
|
||||||
|
|
@ -323,79 +303,65 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind the context to the current thread and given surfaces. Return the
|
* Bind the context to the current thread and given surfaces. Return the
|
||||||
* "orphaned" context and surfaces. Each argument is both input and output.
|
* previous bound context and surfaces. The caller should unreference the
|
||||||
|
* returned context and surfaces.
|
||||||
|
*
|
||||||
|
* Making a second call with the resources returned by the first call
|
||||||
|
* unsurprisingly undoes the first call, except for the resouce reference
|
||||||
|
* counts.
|
||||||
*/
|
*/
|
||||||
EGLBoolean
|
EGLBoolean
|
||||||
_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read)
|
_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
|
||||||
|
_EGLContext **old_ctx,
|
||||||
|
_EGLSurface **old_draw, _EGLSurface **old_read)
|
||||||
{
|
{
|
||||||
_EGLThreadInfo *t = _eglGetCurrentThread();
|
_EGLThreadInfo *t = _eglGetCurrentThread();
|
||||||
_EGLContext *newCtx = *ctx, *oldCtx;
|
_EGLContext *prev_ctx;
|
||||||
_EGLSurface *newDraw = *draw, *newRead = *read;
|
_EGLSurface *prev_draw, *prev_read;
|
||||||
|
|
||||||
if (!_eglCheckMakeCurrent(newCtx, newDraw, newRead))
|
if (!_eglCheckMakeCurrent(ctx, draw, read))
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
|
|
||||||
|
/* increment refcounts before binding */
|
||||||
|
_eglGetContext(ctx);
|
||||||
|
_eglGetSurface(draw);
|
||||||
|
_eglGetSurface(read);
|
||||||
|
|
||||||
/* bind the new context */
|
/* bind the new context */
|
||||||
oldCtx = _eglBindContextToThread(newCtx, t);
|
prev_ctx = _eglBindContextToThread(ctx, t);
|
||||||
|
|
||||||
/* break old bindings */
|
/* break previous bindings */
|
||||||
if (oldCtx) {
|
if (prev_ctx) {
|
||||||
*ctx = oldCtx;
|
prev_draw = prev_ctx->DrawSurface;
|
||||||
*draw = oldCtx->DrawSurface;
|
prev_read = prev_ctx->ReadSurface;
|
||||||
*read = oldCtx->ReadSurface;
|
|
||||||
|
|
||||||
if (*draw)
|
if (prev_draw)
|
||||||
(*draw)->CurrentContext = NULL;
|
prev_draw->CurrentContext = NULL;
|
||||||
if (*read)
|
if (prev_read)
|
||||||
(*read)->CurrentContext = NULL;
|
prev_read->CurrentContext = NULL;
|
||||||
|
|
||||||
oldCtx->DrawSurface = NULL;
|
prev_ctx->DrawSurface = NULL;
|
||||||
oldCtx->ReadSurface = NULL;
|
prev_ctx->ReadSurface = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prev_draw = prev_read = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* establish new bindings */
|
/* establish new bindings */
|
||||||
if (newCtx) {
|
if (ctx) {
|
||||||
if (newDraw)
|
if (draw)
|
||||||
newDraw->CurrentContext = newCtx;
|
draw->CurrentContext = ctx;
|
||||||
if (newRead)
|
if (read)
|
||||||
newRead->CurrentContext = newCtx;
|
read->CurrentContext = ctx;
|
||||||
|
|
||||||
newCtx->DrawSurface = newDraw;
|
ctx->DrawSurface = draw;
|
||||||
newCtx->ReadSurface = newRead;
|
ctx->ReadSurface = read;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* an old context or surface is not orphaned if it is still bound */
|
assert(old_ctx && old_draw && old_read);
|
||||||
if (*ctx == newCtx)
|
*old_ctx = prev_ctx;
|
||||||
*ctx = NULL;
|
*old_draw = prev_draw;
|
||||||
if (*draw == newDraw || *draw == newRead)
|
*old_read = prev_read;
|
||||||
*draw = NULL;
|
|
||||||
if (*read == newDraw || *read == newRead)
|
|
||||||
*read = NULL;
|
|
||||||
|
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Just a placeholder/demo function. Drivers should override this.
|
|
||||||
*/
|
|
||||||
EGLBoolean
|
|
||||||
_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw,
|
|
||||||
_EGLSurface *read, _EGLContext *ctx)
|
|
||||||
{
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is defined by the EGL_MESA_copy_context extension.
|
|
||||||
*/
|
|
||||||
EGLBoolean
|
|
||||||
_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source,
|
|
||||||
EGLContext dest, EGLint mask)
|
|
||||||
{
|
|
||||||
/* This function will always have to be overridden/implemented in the
|
|
||||||
* device driver. If the driver is based on Mesa, use _mesa_copy_context().
|
|
||||||
*/
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -34,51 +34,46 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy,
|
||||||
_EGLConfig *config, const EGLint *attrib_list);
|
_EGLConfig *config, const EGLint *attrib_list);
|
||||||
|
|
||||||
|
|
||||||
extern _EGLContext *
|
|
||||||
_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, _EGLContext *share_list, const EGLint *attrib_list);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLint attribute, EGLint *value);
|
_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLint attribute, EGLint *value);
|
||||||
|
|
||||||
|
|
||||||
PUBLIC EGLBoolean
|
PUBLIC EGLBoolean
|
||||||
_eglBindContext(_EGLContext **ctx, _EGLSurface **draw, _EGLSurface **read);
|
_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
|
||||||
|
_EGLContext **old_ctx,
|
||||||
|
_EGLSurface **old_draw, _EGLSurface **old_read);
|
||||||
extern EGLBoolean
|
|
||||||
_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source, EGLContext dest, EGLint mask);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the context is bound to a thread.
|
* Increment reference count for the context.
|
||||||
*
|
|
||||||
* The binding is considered a reference to the context. Drivers should not
|
|
||||||
* destroy a context when it is bound.
|
|
||||||
*/
|
*/
|
||||||
static INLINE EGLBoolean
|
static INLINE _EGLContext *
|
||||||
_eglIsContextBound(_EGLContext *ctx)
|
_eglGetContext(_EGLContext *ctx)
|
||||||
{
|
{
|
||||||
return (ctx->Binding != NULL);
|
if (ctx)
|
||||||
|
_eglGetResource(&ctx->Resource);
|
||||||
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link a context to a display and return the handle of the link.
|
* Decrement reference count for the context.
|
||||||
|
*/
|
||||||
|
static INLINE EGLBoolean
|
||||||
|
_eglPutContext(_EGLContext *ctx)
|
||||||
|
{
|
||||||
|
return (ctx) ? _eglPutResource(&ctx->Resource) : EGL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link a context to its display and return the handle of the link.
|
||||||
* The handle can be passed to client directly.
|
* The handle can be passed to client directly.
|
||||||
*/
|
*/
|
||||||
static INLINE EGLContext
|
static INLINE EGLContext
|
||||||
_eglLinkContext(_EGLContext *ctx, _EGLDisplay *dpy)
|
_eglLinkContext(_EGLContext *ctx)
|
||||||
{
|
{
|
||||||
_eglLinkResource(&ctx->Resource, _EGL_RESOURCE_CONTEXT, dpy);
|
_eglLinkResource(&ctx->Resource, _EGL_RESOURCE_CONTEXT);
|
||||||
return (EGLContext) ctx;
|
return (EGLContext) ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,18 +115,4 @@ _eglGetContextHandle(_EGLContext *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the context is linked to a display.
|
|
||||||
*
|
|
||||||
* The link is considered a reference to the context (the display is owning the
|
|
||||||
* context). Drivers should not destroy a context when it is linked.
|
|
||||||
*/
|
|
||||||
static INLINE EGLBoolean
|
|
||||||
_eglIsContextLinked(_EGLContext *ctx)
|
|
||||||
{
|
|
||||||
_EGLResource *res = (_EGLResource *) ctx;
|
|
||||||
return (res && _eglIsResourceLinked(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* EGLCONTEXT_INCLUDED */
|
#endif /* EGLCONTEXT_INCLUDED */
|
||||||
|
|
|
||||||
|
|
@ -233,17 +233,53 @@ _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link a resource to a display.
|
* Initialize a display resource.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_eglLinkResource(_EGLResource *res, _EGLResourceType type, _EGLDisplay *dpy)
|
_eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
|
||||||
{
|
{
|
||||||
assert(!res->Display || res->Display == dpy);
|
memset(res, 0, size);
|
||||||
|
|
||||||
res->Display = dpy;
|
res->Display = dpy;
|
||||||
|
res->RefCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment reference count for the resource.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_eglGetResource(_EGLResource *res)
|
||||||
|
{
|
||||||
|
assert(res && res->RefCount > 0);
|
||||||
|
/* hopefully a resource is always manipulated with its display locked */
|
||||||
|
res->RefCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement reference count for the resource.
|
||||||
|
*/
|
||||||
|
EGLBoolean
|
||||||
|
_eglPutResource(_EGLResource *res)
|
||||||
|
{
|
||||||
|
assert(res && res->RefCount > 0);
|
||||||
|
res->RefCount--;
|
||||||
|
return (!res->RefCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link a resource to its display.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_eglLinkResource(_EGLResource *res, _EGLResourceType type)
|
||||||
|
{
|
||||||
|
assert(res->Display);
|
||||||
|
|
||||||
res->IsLinked = EGL_TRUE;
|
res->IsLinked = EGL_TRUE;
|
||||||
res->Next = dpy->ResourceLists[type];
|
res->Next = res->Display->ResourceLists[type];
|
||||||
dpy->ResourceLists[type] = res;
|
res->Display->ResourceLists[type] = res;
|
||||||
|
_eglGetResource(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -270,6 +306,9 @@ _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
|
||||||
}
|
}
|
||||||
|
|
||||||
res->Next = NULL;
|
res->Next = NULL;
|
||||||
/* do not reset res->Display */
|
|
||||||
res->IsLinked = EGL_FALSE;
|
res->IsLinked = EGL_FALSE;
|
||||||
|
_eglPutResource(res);
|
||||||
|
|
||||||
|
/* We always unlink before destroy. The driver still owns a reference */
|
||||||
|
assert(res->RefCount);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ struct _egl_resource
|
||||||
/* which display the resource belongs to */
|
/* which display the resource belongs to */
|
||||||
_EGLDisplay *Display;
|
_EGLDisplay *Display;
|
||||||
EGLBoolean IsLinked;
|
EGLBoolean IsLinked;
|
||||||
|
EGLint RefCount;
|
||||||
|
|
||||||
/* used to link resources of the same type */
|
/* used to link resources of the same type */
|
||||||
_EGLResource *Next;
|
_EGLResource *Next;
|
||||||
|
|
@ -162,7 +163,19 @@ _eglGetDisplayHandle(_EGLDisplay *dpy)
|
||||||
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
_eglLinkResource(_EGLResource *res, _EGLResourceType type, _EGLDisplay *dpy);
|
_eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy);
|
||||||
|
|
||||||
|
|
||||||
|
PUBLIC void
|
||||||
|
_eglGetResource(_EGLResource *res);
|
||||||
|
|
||||||
|
|
||||||
|
PUBLIC EGLBoolean
|
||||||
|
_eglPutResource(_EGLResource *res);
|
||||||
|
|
||||||
|
|
||||||
|
extern void
|
||||||
|
_eglLinkResource(_EGLResource *res, _EGLResourceType type);
|
||||||
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,10 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "eglstring.h"
|
#include "eglstring.h"
|
||||||
#include "eglconfig.h"
|
|
||||||
#include "eglcontext.h"
|
|
||||||
#include "egldefines.h"
|
#include "egldefines.h"
|
||||||
#include "egldisplay.h"
|
#include "egldisplay.h"
|
||||||
#include "egldriver.h"
|
#include "egldriver.h"
|
||||||
#include "egllog.h"
|
#include "egllog.h"
|
||||||
#include "eglmisc.h"
|
|
||||||
#include "eglmode.h"
|
|
||||||
#include "eglscreen.h"
|
|
||||||
#include "eglsurface.h"
|
|
||||||
#include "eglimage.h"
|
|
||||||
#include "eglsync.h"
|
|
||||||
#include "eglmutex.h"
|
#include "eglmutex.h"
|
||||||
|
|
||||||
#if defined(_EGL_OS_UNIX)
|
#if defined(_EGL_OS_UNIX)
|
||||||
|
|
@ -662,77 +654,6 @@ _eglUnloadDrivers(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plug all the available fallback routines into the given driver's
|
|
||||||
* dispatch table.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
_eglInitDriverFallbacks(_EGLDriver *drv)
|
|
||||||
{
|
|
||||||
/* If a pointer is set to NULL, then the device driver _really_ has
|
|
||||||
* to implement it.
|
|
||||||
*/
|
|
||||||
drv->API.Initialize = NULL;
|
|
||||||
drv->API.Terminate = NULL;
|
|
||||||
|
|
||||||
drv->API.GetConfigs = _eglGetConfigs;
|
|
||||||
drv->API.ChooseConfig = _eglChooseConfig;
|
|
||||||
drv->API.GetConfigAttrib = _eglGetConfigAttrib;
|
|
||||||
|
|
||||||
drv->API.CreateContext = _eglCreateContext;
|
|
||||||
drv->API.DestroyContext = _eglDestroyContext;
|
|
||||||
drv->API.MakeCurrent = _eglMakeCurrent;
|
|
||||||
drv->API.QueryContext = _eglQueryContext;
|
|
||||||
|
|
||||||
drv->API.CreateWindowSurface = _eglCreateWindowSurface;
|
|
||||||
drv->API.CreatePixmapSurface = _eglCreatePixmapSurface;
|
|
||||||
drv->API.CreatePbufferSurface = _eglCreatePbufferSurface;
|
|
||||||
drv->API.DestroySurface = _eglDestroySurface;
|
|
||||||
drv->API.QuerySurface = _eglQuerySurface;
|
|
||||||
drv->API.SurfaceAttrib = _eglSurfaceAttrib;
|
|
||||||
drv->API.BindTexImage = _eglBindTexImage;
|
|
||||||
drv->API.ReleaseTexImage = _eglReleaseTexImage;
|
|
||||||
drv->API.SwapInterval = _eglSwapInterval;
|
|
||||||
drv->API.SwapBuffers = _eglSwapBuffers;
|
|
||||||
drv->API.CopyBuffers = _eglCopyBuffers;
|
|
||||||
|
|
||||||
drv->API.QueryString = _eglQueryString;
|
|
||||||
drv->API.WaitClient = _eglWaitClient;
|
|
||||||
drv->API.WaitNative = _eglWaitNative;
|
|
||||||
|
|
||||||
#ifdef EGL_MESA_screen_surface
|
|
||||||
drv->API.ChooseModeMESA = _eglChooseModeMESA;
|
|
||||||
drv->API.GetModesMESA = _eglGetModesMESA;
|
|
||||||
drv->API.GetModeAttribMESA = _eglGetModeAttribMESA;
|
|
||||||
drv->API.GetScreensMESA = _eglGetScreensMESA;
|
|
||||||
drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA;
|
|
||||||
drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA;
|
|
||||||
drv->API.ScreenPositionMESA = _eglScreenPositionMESA;
|
|
||||||
drv->API.QueryScreenMESA = _eglQueryScreenMESA;
|
|
||||||
drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA;
|
|
||||||
drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA;
|
|
||||||
drv->API.QueryModeStringMESA = _eglQueryModeStringMESA;
|
|
||||||
#endif /* EGL_MESA_screen_surface */
|
|
||||||
|
|
||||||
#ifdef EGL_VERSION_1_2
|
|
||||||
drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
|
|
||||||
#endif /* EGL_VERSION_1_2 */
|
|
||||||
|
|
||||||
#ifdef EGL_KHR_image_base
|
|
||||||
drv->API.CreateImageKHR = _eglCreateImageKHR;
|
|
||||||
drv->API.DestroyImageKHR = _eglDestroyImageKHR;
|
|
||||||
#endif /* EGL_KHR_image_base */
|
|
||||||
|
|
||||||
#ifdef EGL_KHR_reusable_sync
|
|
||||||
drv->API.CreateSyncKHR = _eglCreateSyncKHR;
|
|
||||||
drv->API.DestroySyncKHR = _eglDestroySyncKHR;
|
|
||||||
drv->API.ClientWaitSyncKHR = _eglClientWaitSyncKHR;
|
|
||||||
drv->API.SignalSyncKHR = _eglSignalSyncKHR;
|
|
||||||
drv->API.GetSyncAttribKHR = _eglGetSyncAttribKHR;
|
|
||||||
#endif /* EGL_KHR_reusable_sync */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke a callback function on each EGL search path.
|
* Invoke a callback function on each EGL search path.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ extern void
|
||||||
_eglUnloadDrivers(void);
|
_eglUnloadDrivers(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* defined in eglfallbacks.c */
|
||||||
PUBLIC void
|
PUBLIC void
|
||||||
_eglInitDriverFallbacks(_EGLDriver *drv);
|
_eglInitDriverFallbacks(_EGLDriver *drv);
|
||||||
|
|
||||||
|
|
|
||||||
99
src/egl/main/eglfallbacks.c
Normal file
99
src/egl/main/eglfallbacks.c
Normal 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
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "eglimage.h"
|
#include "eglimage.h"
|
||||||
#include "eglcurrent.h"
|
|
||||||
#include "egllog.h"
|
#include "egllog.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -12,28 +11,57 @@
|
||||||
/**
|
/**
|
||||||
* Parse the list of image attributes and return the proper error code.
|
* Parse the list of image attributes and return the proper error code.
|
||||||
*/
|
*/
|
||||||
static EGLint
|
EGLint
|
||||||
_eglParseImageAttribList(_EGLImage *img, const EGLint *attrib_list)
|
_eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *dpy,
|
||||||
|
const EGLint *attrib_list)
|
||||||
{
|
{
|
||||||
EGLint i, err = EGL_SUCCESS;
|
EGLint i, err = EGL_SUCCESS;
|
||||||
|
|
||||||
|
(void) dpy;
|
||||||
|
|
||||||
|
memset(attrs, 0, sizeof(attrs));
|
||||||
|
attrs->ImagePreserved = EGL_FALSE;
|
||||||
|
attrs->GLTextureLevel = 0;
|
||||||
|
attrs->GLTextureZOffset = 0;
|
||||||
|
|
||||||
if (!attrib_list)
|
if (!attrib_list)
|
||||||
return EGL_SUCCESS;
|
return err;
|
||||||
|
|
||||||
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
|
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
|
||||||
EGLint attr = attrib_list[i++];
|
EGLint attr = attrib_list[i++];
|
||||||
EGLint val = attrib_list[i];
|
EGLint val = attrib_list[i];
|
||||||
|
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
|
/* EGL_KHR_image_base */
|
||||||
case EGL_IMAGE_PRESERVED_KHR:
|
case EGL_IMAGE_PRESERVED_KHR:
|
||||||
img->Preserved = val;
|
attrs->ImagePreserved = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* EGL_KHR_gl_image */
|
||||||
case EGL_GL_TEXTURE_LEVEL_KHR:
|
case EGL_GL_TEXTURE_LEVEL_KHR:
|
||||||
img->GLTextureLevel = val;
|
attrs->GLTextureLevel = val;
|
||||||
break;
|
break;
|
||||||
case EGL_GL_TEXTURE_ZOFFSET_KHR:
|
case EGL_GL_TEXTURE_ZOFFSET_KHR:
|
||||||
img->GLTextureZOffset = val;
|
attrs->GLTextureZOffset = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* EGL_MESA_drm_image */
|
||||||
|
case EGL_WIDTH:
|
||||||
|
attrs->Width = val;
|
||||||
|
break;
|
||||||
|
case EGL_HEIGHT:
|
||||||
|
attrs->Height = val;
|
||||||
|
break;
|
||||||
|
case EGL_DRM_BUFFER_FORMAT_MESA:
|
||||||
|
attrs->DRMBufferFormatMESA = val;
|
||||||
|
break;
|
||||||
|
case EGL_DRM_BUFFER_USE_MESA:
|
||||||
|
attrs->DRMBufferUseMESA = val;
|
||||||
|
break;
|
||||||
|
case EGL_DRM_BUFFER_STRIDE_MESA:
|
||||||
|
attrs->DRMBufferStrideMESA = val;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* unknown attrs are ignored */
|
/* unknown attrs are ignored */
|
||||||
break;
|
break;
|
||||||
|
|
@ -50,41 +78,12 @@ _eglParseImageAttribList(_EGLImage *img, const EGLint *attrib_list)
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
EGLBoolean
|
||||||
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy, const EGLint *attrib_list)
|
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy)
|
||||||
{
|
{
|
||||||
EGLint err;
|
_eglInitResource(&img->Resource, sizeof(*img), dpy);
|
||||||
|
|
||||||
memset(img, 0, sizeof(_EGLImage));
|
|
||||||
img->Resource.Display = dpy;
|
|
||||||
|
|
||||||
img->Preserved = EGL_FALSE;
|
|
||||||
img->GLTextureLevel = 0;
|
|
||||||
img->GLTextureZOffset = 0;
|
|
||||||
|
|
||||||
err = _eglParseImageAttribList(img, attrib_list);
|
|
||||||
if (err != EGL_SUCCESS)
|
|
||||||
return _eglError(err, "eglCreateImageKHR");
|
|
||||||
|
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_EGLImage *
|
|
||||||
_eglCreateImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx,
|
|
||||||
EGLenum target, EGLClientBuffer buffer,
|
|
||||||
const EGLint *attr_list)
|
|
||||||
{
|
|
||||||
/* driver should override this function */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
|
||||||
_eglDestroyImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *image)
|
|
||||||
{
|
|
||||||
/* driver should override this function */
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* EGL_KHR_image_base */
|
#endif /* EGL_KHR_image_base */
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,23 @@
|
||||||
#include "egldisplay.h"
|
#include "egldisplay.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct _egl_image_attribs
|
||||||
|
{
|
||||||
|
/* EGL_KHR_image_base */
|
||||||
|
EGLBoolean ImagePreserved;
|
||||||
|
|
||||||
|
/* EGL_KHR_gl_image */
|
||||||
|
EGLint GLTextureLevel;
|
||||||
|
EGLint GLTextureZOffset;
|
||||||
|
|
||||||
|
/* EGL_MESA_drm_image */
|
||||||
|
EGLint Width;
|
||||||
|
EGLint Height;
|
||||||
|
EGLint DRMBufferFormatMESA;
|
||||||
|
EGLint DRMBufferUseMESA;
|
||||||
|
EGLint DRMBufferStrideMESA;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Base" class for device driver images.
|
* "Base" class for device driver images.
|
||||||
*/
|
*/
|
||||||
|
|
@ -13,34 +30,48 @@ struct _egl_image
|
||||||
{
|
{
|
||||||
/* An image is a display resource */
|
/* An image is a display resource */
|
||||||
_EGLResource Resource;
|
_EGLResource Resource;
|
||||||
|
|
||||||
EGLBoolean Preserved;
|
|
||||||
EGLint GLTextureLevel;
|
|
||||||
EGLint GLTextureZOffset;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
PUBLIC EGLint
|
||||||
|
_eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *dpy,
|
||||||
|
const EGLint *attrib_list);
|
||||||
|
|
||||||
|
|
||||||
PUBLIC EGLBoolean
|
PUBLIC EGLBoolean
|
||||||
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy, const EGLint *attrib_list);
|
_eglInitImage(_EGLImage *img, _EGLDisplay *dpy);
|
||||||
|
|
||||||
|
|
||||||
extern _EGLImage *
|
|
||||||
_eglCreateImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx,
|
|
||||||
EGLenum target, EGLClientBuffer buffer, const EGLint *attr_list);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglDestroyImageKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *image);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link an image to a display and return the handle of the link.
|
* Increment reference count for the image.
|
||||||
|
*/
|
||||||
|
static INLINE _EGLImage *
|
||||||
|
_eglGetImage(_EGLImage *img)
|
||||||
|
{
|
||||||
|
if (img)
|
||||||
|
_eglGetResource(&img->Resource);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement reference count for the image.
|
||||||
|
*/
|
||||||
|
static INLINE EGLBoolean
|
||||||
|
_eglPutImage(_EGLImage *img)
|
||||||
|
{
|
||||||
|
return (img) ? _eglPutResource(&img->Resource) : EGL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link an image to its display and return the handle of the link.
|
||||||
* The handle can be passed to client directly.
|
* The handle can be passed to client directly.
|
||||||
*/
|
*/
|
||||||
static INLINE EGLImageKHR
|
static INLINE EGLImageKHR
|
||||||
_eglLinkImage(_EGLImage *img, _EGLDisplay *dpy)
|
_eglLinkImage(_EGLImage *img)
|
||||||
{
|
{
|
||||||
_eglLinkResource(&img->Resource, _EGL_RESOURCE_IMAGE, dpy);
|
_eglLinkResource(&img->Resource, _EGL_RESOURCE_IMAGE);
|
||||||
return (EGLImageKHR) img;
|
return (EGLImageKHR) img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,15 +113,4 @@ _eglGetImageHandle(_EGLImage *img)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the image is linked to a display.
|
|
||||||
*/
|
|
||||||
static INLINE EGLBoolean
|
|
||||||
_eglIsImageLinked(_EGLImage *img)
|
|
||||||
{
|
|
||||||
_EGLResource *res = (_EGLResource *) img;
|
|
||||||
return (res && _eglIsResourceLinked(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* EGLIMAGE_INCLUDED */
|
#endif /* EGLIMAGE_INCLUDED */
|
||||||
|
|
|
||||||
|
|
@ -158,32 +158,3 @@ _eglQueryString(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
|
||||||
_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
|
|
||||||
{
|
|
||||||
/* just a placeholder */
|
|
||||||
(void) drv;
|
|
||||||
(void) dpy;
|
|
||||||
(void) ctx;
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
|
||||||
_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
|
|
||||||
{
|
|
||||||
/* just a placeholder */
|
|
||||||
(void) drv;
|
|
||||||
(void) dpy;
|
|
||||||
switch (engine) {
|
|
||||||
case EGL_CORE_NATIVE_ENGINE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_eglError(EGL_BAD_PARAMETER, "eglWaitNative(engine)");
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,4 @@ extern const char *
|
||||||
_eglQueryString(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name);
|
_eglQueryString(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name);
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* EGLMISC_INCLUDED */
|
#endif /* EGLMISC_INCLUDED */
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "egldisplay.h"
|
#include "egldisplay.h"
|
||||||
#include "egldriver.h"
|
|
||||||
#include "eglmode.h"
|
#include "eglmode.h"
|
||||||
#include "eglcurrent.h"
|
#include "eglcurrent.h"
|
||||||
#include "eglscreen.h"
|
#include "eglscreen.h"
|
||||||
#include "eglstring.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef EGL_MESA_screen_surface
|
#ifdef EGL_MESA_screen_surface
|
||||||
|
|
@ -31,56 +29,24 @@ _eglLookupMode(EGLModeMESA mode, _EGLDisplay *disp)
|
||||||
/* loop over all screens on the display */
|
/* loop over all screens on the display */
|
||||||
for (scrnum = 0; scrnum < disp->Screens->Size; scrnum++) {
|
for (scrnum = 0; scrnum < disp->Screens->Size; scrnum++) {
|
||||||
const _EGLScreen *scrn = disp->Screens->Elements[scrnum];
|
const _EGLScreen *scrn = disp->Screens->Elements[scrnum];
|
||||||
EGLint i;
|
EGLint idx;
|
||||||
/* search list of modes for handle */
|
|
||||||
for (i = 0; i < scrn->NumModes; i++) {
|
|
||||||
if (scrn->Modes[i].Handle == mode) {
|
|
||||||
return scrn->Modes + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
/*
|
||||||
}
|
* the mode ids of a screen ranges from scrn->Handle to scrn->Handle +
|
||||||
|
* scrn->NumModes
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new mode with the given attributes (width, height, depth, refreshRate)
|
|
||||||
* to the given screen.
|
|
||||||
* Assign a new mode ID/handle to the mode as well.
|
|
||||||
* \return pointer to the new _EGLMode
|
|
||||||
*/
|
*/
|
||||||
_EGLMode *
|
if (mode >= scrn->Handle &&
|
||||||
_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height,
|
mode < scrn->Handle + _EGL_SCREEN_MAX_MODES) {
|
||||||
EGLint refreshRate, const char *name)
|
idx = mode - scrn->Handle;
|
||||||
{
|
|
||||||
EGLint n;
|
|
||||||
_EGLMode *newModes;
|
|
||||||
|
|
||||||
assert(screen);
|
assert(idx < scrn->NumModes && scrn->Modes[idx].Handle == mode);
|
||||||
assert(width > 0);
|
|
||||||
assert(height > 0);
|
|
||||||
assert(refreshRate > 0);
|
|
||||||
|
|
||||||
n = screen->NumModes;
|
return &scrn->Modes[idx];
|
||||||
newModes = (_EGLMode *) realloc(screen->Modes, (n+1) * sizeof(_EGLMode));
|
|
||||||
if (newModes) {
|
|
||||||
screen->Modes = newModes;
|
|
||||||
screen->Modes[n].Handle = n + 1;
|
|
||||||
screen->Modes[n].Width = width;
|
|
||||||
screen->Modes[n].Height = height;
|
|
||||||
screen->Modes[n].RefreshRate = refreshRate;
|
|
||||||
screen->Modes[n].Optimal = EGL_FALSE;
|
|
||||||
screen->Modes[n].Interlaced = EGL_FALSE;
|
|
||||||
screen->Modes[n].Name = _eglstrdup(name);
|
|
||||||
screen->NumModes++;
|
|
||||||
return screen->Modes + n;
|
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,6 @@ extern _EGLMode *
|
||||||
_eglLookupMode(EGLModeMESA mode, _EGLDisplay *dpy);
|
_eglLookupMode(EGLModeMESA mode, _EGLDisplay *dpy);
|
||||||
|
|
||||||
|
|
||||||
PUBLIC _EGLMode *
|
|
||||||
_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height,
|
|
||||||
EGLint refreshRate, const char *name);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
_eglChooseModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
|
_eglChooseModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
|
||||||
const EGLint *attrib_list, EGLModeMESA *modes,
|
const EGLint *attrib_list, EGLModeMESA *modes,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
#include "egldisplay.h"
|
#include "egldisplay.h"
|
||||||
#include "eglcurrent.h"
|
#include "eglcurrent.h"
|
||||||
#include "eglmode.h"
|
#include "eglmode.h"
|
||||||
#include "eglconfig.h"
|
|
||||||
#include "eglsurface.h"
|
#include "eglsurface.h"
|
||||||
#include "eglscreen.h"
|
#include "eglscreen.h"
|
||||||
#include "eglmutex.h"
|
#include "eglmutex.h"
|
||||||
|
|
@ -42,7 +41,8 @@ _eglAllocScreenHandle(void)
|
||||||
EGLScreenMESA s;
|
EGLScreenMESA s;
|
||||||
|
|
||||||
_eglLockMutex(&_eglNextScreenHandleMutex);
|
_eglLockMutex(&_eglNextScreenHandleMutex);
|
||||||
s = _eglNextScreenHandle++;
|
s = _eglNextScreenHandle;
|
||||||
|
_eglNextScreenHandle += _EGL_SCREEN_MAX_MODES;
|
||||||
_eglUnlockMutex(&_eglNextScreenHandleMutex);
|
_eglUnlockMutex(&_eglNextScreenHandleMutex);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
|
@ -53,16 +53,54 @@ _eglAllocScreenHandle(void)
|
||||||
* Initialize an _EGLScreen object to default values.
|
* Initialize an _EGLScreen object to default values.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_eglInitScreen(_EGLScreen *screen)
|
_eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes)
|
||||||
{
|
{
|
||||||
memset(screen, 0, sizeof(_EGLScreen));
|
memset(screen, 0, sizeof(_EGLScreen));
|
||||||
|
|
||||||
|
screen->Display = dpy;
|
||||||
|
screen->NumModes = num_modes;
|
||||||
screen->StepX = 1;
|
screen->StepX = 1;
|
||||||
screen->StepY = 1;
|
screen->StepY = 1;
|
||||||
|
|
||||||
|
if (num_modes > _EGL_SCREEN_MAX_MODES)
|
||||||
|
num_modes = _EGL_SCREEN_MAX_MODES;
|
||||||
|
screen->Modes = (_EGLMode *) calloc(num_modes, sizeof(*screen->Modes));
|
||||||
|
screen->NumModes = (screen->Modes) ? num_modes : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a public screen handle, return the internal _EGLScreen object.
|
* Link a screen to its display and return the handle of the link.
|
||||||
|
* The handle can be passed to client directly.
|
||||||
|
*/
|
||||||
|
EGLScreenMESA
|
||||||
|
_eglLinkScreen(_EGLScreen *screen)
|
||||||
|
{
|
||||||
|
_EGLDisplay *display;
|
||||||
|
EGLint i;
|
||||||
|
|
||||||
|
assert(screen && screen->Display);
|
||||||
|
display = screen->Display;
|
||||||
|
|
||||||
|
if (!display->Screens) {
|
||||||
|
display->Screens = _eglCreateArray("Screen", 4);
|
||||||
|
if (!display->Screens)
|
||||||
|
return (EGLScreenMESA) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
screen->Handle = _eglAllocScreenHandle();
|
||||||
|
for (i = 0; i < screen->NumModes; i++)
|
||||||
|
screen->Modes[i].Handle = screen->Handle + i;
|
||||||
|
|
||||||
|
_eglAppendArray(display->Screens, (void *) screen);
|
||||||
|
|
||||||
|
return screen->Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a handle to find the linked config.
|
||||||
|
* Return NULL if the handle has no corresponding linked config.
|
||||||
*/
|
*/
|
||||||
_EGLScreen *
|
_EGLScreen *
|
||||||
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
|
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
|
||||||
|
|
@ -74,39 +112,21 @@ _eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
|
||||||
|
|
||||||
for (i = 0; i < display->Screens->Size; i++) {
|
for (i = 0; i < display->Screens->Size; i++) {
|
||||||
_EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i];
|
_EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i];
|
||||||
if (scr->Handle == screen)
|
if (scr->Handle == screen) {
|
||||||
|
assert(scr->Display == display);
|
||||||
return scr;
|
return scr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the given _EGLScreen to the display's list of screens.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen)
|
|
||||||
{
|
|
||||||
assert(display);
|
|
||||||
assert(screen);
|
|
||||||
|
|
||||||
if (!display->Screens) {
|
|
||||||
display->Screens = _eglCreateArray("Screen", 4);
|
|
||||||
if (!display->Screens)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
screen->Handle = _eglAllocScreenHandle();
|
|
||||||
_eglAppendArray(display->Screens, (void *) screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static EGLBoolean
|
static EGLBoolean
|
||||||
_eglFlattenScreen(void *elem, void *buffer)
|
_eglFlattenScreen(void *elem, void *buffer)
|
||||||
{
|
{
|
||||||
_EGLScreen *scr = (_EGLScreen *) elem;
|
_EGLScreen *scr = (_EGLScreen *) elem;
|
||||||
EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
|
EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
|
||||||
*handle = scr->Handle;
|
*handle = _eglGetScreenHandle(scr);
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,66 +142,6 @@ _eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *display, EGLScreenMESA *screens
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drivers should do a proper implementation.
|
|
||||||
*/
|
|
||||||
_EGLSurface *
|
|
||||||
_eglCreateScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
|
|
||||||
const EGLint *attrib_list)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the given surface on the named screen.
|
|
||||||
* If surface is EGL_NO_SURFACE, disable the screen's output.
|
|
||||||
*
|
|
||||||
* This is just a placeholder function; drivers will always override
|
|
||||||
* this with code that _really_ shows the surface.
|
|
||||||
*/
|
|
||||||
EGLBoolean
|
|
||||||
_eglShowScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
|
|
||||||
_EGLScreen *scrn, _EGLSurface *surf,
|
|
||||||
_EGLMode *mode)
|
|
||||||
{
|
|
||||||
if (!surf) {
|
|
||||||
scrn->CurrentSurface = NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (surf->Type != EGL_SCREEN_BIT_MESA) {
|
|
||||||
_eglError(EGL_BAD_SURFACE, "eglShowSurfaceMESA");
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
if (surf->Width < mode->Width || surf->Height < mode->Height) {
|
|
||||||
_eglError(EGL_BAD_SURFACE,
|
|
||||||
"eglShowSurfaceMESA(surface smaller than screen size)");
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
scrn->CurrentSurface = surf;
|
|
||||||
scrn->CurrentMode = mode;
|
|
||||||
}
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a screen's current display mode.
|
|
||||||
* Note: mode = EGL_NO_MODE is valid (turns off the screen)
|
|
||||||
*
|
|
||||||
* This is just a placeholder function; drivers will always override
|
|
||||||
* this with code that _really_ sets the mode.
|
|
||||||
*/
|
|
||||||
EGLBoolean
|
|
||||||
_eglScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
|
|
||||||
_EGLMode *m)
|
|
||||||
{
|
|
||||||
scrn->CurrentMode = m;
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a screen's surface origin.
|
* Set a screen's surface origin.
|
||||||
*/
|
*/
|
||||||
|
|
@ -242,33 +202,4 @@ _eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the modes associated with given screen.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
_eglDestroyScreenModes(_EGLScreen *scrn)
|
|
||||||
{
|
|
||||||
EGLint i;
|
|
||||||
for (i = 0; i < scrn->NumModes; i++) {
|
|
||||||
if (scrn->Modes[i].Name)
|
|
||||||
free((char *) scrn->Modes[i].Name); /* cast away const */
|
|
||||||
}
|
|
||||||
if (scrn->Modes)
|
|
||||||
free(scrn->Modes);
|
|
||||||
scrn->Modes = NULL;
|
|
||||||
scrn->NumModes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default fallback routine - drivers should usually override this.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
_eglDestroyScreen(_EGLScreen *scrn)
|
|
||||||
{
|
|
||||||
_eglDestroyScreenModes(scrn);
|
|
||||||
free(scrn);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* EGL_MESA_screen_surface */
|
#endif /* EGL_MESA_screen_surface */
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
#ifdef EGL_MESA_screen_surface
|
#ifdef EGL_MESA_screen_surface
|
||||||
|
|
||||||
|
|
||||||
|
#define _EGL_SCREEN_MAX_MODES 16
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Per-screen information.
|
* Per-screen information.
|
||||||
* Note that an EGL screen doesn't have a size. A screen may be set to
|
* Note that an EGL screen doesn't have a size. A screen may be set to
|
||||||
|
|
@ -19,6 +22,8 @@
|
||||||
*/
|
*/
|
||||||
struct _egl_screen
|
struct _egl_screen
|
||||||
{
|
{
|
||||||
|
_EGLDisplay *Display;
|
||||||
|
|
||||||
EGLScreenMESA Handle; /* The public/opaque handle which names this object */
|
EGLScreenMESA Handle; /* The public/opaque handle which names this object */
|
||||||
|
|
||||||
_EGLMode *CurrentMode;
|
_EGLMode *CurrentMode;
|
||||||
|
|
@ -33,41 +38,35 @@ struct _egl_screen
|
||||||
|
|
||||||
|
|
||||||
PUBLIC void
|
PUBLIC void
|
||||||
_eglInitScreen(_EGLScreen *screen);
|
_eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes);
|
||||||
|
|
||||||
|
|
||||||
|
PUBLIC EGLScreenMESA
|
||||||
|
_eglLinkScreen(_EGLScreen *screen);
|
||||||
|
|
||||||
|
|
||||||
extern _EGLScreen *
|
extern _EGLScreen *
|
||||||
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *dpy);
|
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *dpy);
|
||||||
|
|
||||||
|
|
||||||
PUBLIC void
|
/**
|
||||||
_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen);
|
* Return the handle of a linked screen.
|
||||||
|
*/
|
||||||
|
static INLINE EGLScreenMESA
|
||||||
|
_eglGetScreenHandle(_EGLScreen *screen)
|
||||||
|
{
|
||||||
|
return (screen) ? screen->Handle : (EGLScreenMESA) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
_eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *dpy, EGLScreenMESA *screens, EGLint max_screens, EGLint *num_screens);
|
_eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *dpy, EGLScreenMESA *screens, EGLint max_screens, EGLint *num_screens);
|
||||||
|
|
||||||
|
|
||||||
extern _EGLSurface *
|
|
||||||
_eglCreateScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, const EGLint *attrib_list);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglShowScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, _EGLSurface *surf, _EGLMode *m);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, _EGLMode *m);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
_eglScreenPositionMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, EGLint x, EGLint y);
|
_eglScreenPositionMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, EGLint x, EGLint y);
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglQueryDisplayMESA(_EGLDriver *drv, _EGLDisplay *dpy, EGLint attribute, EGLint *value);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
_eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
|
_eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
|
||||||
_EGLScreen *scrn, _EGLSurface **surface);
|
_EGLScreen *scrn, _EGLSurface **surface);
|
||||||
|
|
@ -81,14 +80,6 @@ extern EGLBoolean
|
||||||
_eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, EGLint attribute, EGLint *value);
|
_eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn, EGLint attribute, EGLint *value);
|
||||||
|
|
||||||
|
|
||||||
extern void
|
|
||||||
_eglDestroyScreenModes(_EGLScreen *scrn);
|
|
||||||
|
|
||||||
|
|
||||||
PUBLIC void
|
|
||||||
_eglDestroyScreen(_EGLScreen *scrn);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* EGL_MESA_screen_surface */
|
#endif /* EGL_MESA_screen_surface */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@
|
||||||
static void
|
static void
|
||||||
_eglClampSwapInterval(_EGLSurface *surf, EGLint interval)
|
_eglClampSwapInterval(_EGLSurface *surf, EGLint interval)
|
||||||
{
|
{
|
||||||
EGLint bound = GET_CONFIG_ATTRIB(surf->Config, EGL_MAX_SWAP_INTERVAL);
|
EGLint bound = surf->Config->MaxSwapInterval;
|
||||||
if (interval >= bound) {
|
if (interval >= bound) {
|
||||||
interval = bound;
|
interval = bound;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bound = GET_CONFIG_ATTRIB(surf->Config, EGL_MIN_SWAP_INTERVAL);
|
bound = surf->Config->MinSwapInterval;
|
||||||
if (interval < bound)
|
if (interval < bound)
|
||||||
interval = bound;
|
interval = bound;
|
||||||
}
|
}
|
||||||
|
|
@ -263,14 +263,13 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE) & type) == 0) {
|
if ((conf->SurfaceType & type) == 0) {
|
||||||
/* The config can't be used to create a surface of this type */
|
/* The config can't be used to create a surface of this type */
|
||||||
_eglError(EGL_BAD_CONFIG, func);
|
_eglError(EGL_BAD_CONFIG, func);
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(surf, 0, sizeof(_EGLSurface));
|
_eglInitResource(&surf->Resource, sizeof(*surf), dpy);
|
||||||
surf->Resource.Display = dpy;
|
|
||||||
surf->Type = type;
|
surf->Type = type;
|
||||||
surf->Config = conf;
|
surf->Config = conf;
|
||||||
|
|
||||||
|
|
@ -303,24 +302,6 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
|
||||||
_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
|
|
||||||
{
|
|
||||||
/* Drivers have to do the actual buffer swap. */
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
|
||||||
_eglCopyBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
|
|
||||||
EGLNativePixmapType target)
|
|
||||||
{
|
|
||||||
/* copy surface to native pixmap */
|
|
||||||
/* All implementation burdon for this is in the device driver */
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
EGLBoolean
|
||||||
_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
|
_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
|
||||||
EGLint attribute, EGLint *value)
|
EGLint attribute, EGLint *value)
|
||||||
|
|
@ -333,7 +314,7 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
|
||||||
*value = surface->Height;
|
*value = surface->Height;
|
||||||
break;
|
break;
|
||||||
case EGL_CONFIG_ID:
|
case EGL_CONFIG_ID:
|
||||||
*value = GET_CONFIG_ATTRIB(surface->Config, EGL_CONFIG_ID);
|
*value = surface->Config->ConfigID;
|
||||||
break;
|
break;
|
||||||
case EGL_LARGEST_PBUFFER:
|
case EGL_LARGEST_PBUFFER:
|
||||||
*value = surface->LargestPbuffer;
|
*value = surface->LargestPbuffer;
|
||||||
|
|
@ -388,51 +369,6 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drivers should do a proper implementation.
|
|
||||||
*/
|
|
||||||
_EGLSurface *
|
|
||||||
_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
|
|
||||||
EGLNativeWindowType window, const EGLint *attrib_list)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drivers should do a proper implementation.
|
|
||||||
*/
|
|
||||||
_EGLSurface *
|
|
||||||
_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
|
|
||||||
EGLNativePixmapType pixmap, const EGLint *attrib_list)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drivers should do a proper implementation.
|
|
||||||
*/
|
|
||||||
_EGLSurface *
|
|
||||||
_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
|
|
||||||
const EGLint *attrib_list)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default fallback routine - drivers should usually override this.
|
|
||||||
*/
|
|
||||||
EGLBoolean
|
|
||||||
_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
|
|
||||||
{
|
|
||||||
if (!_eglIsSurfaceBound(surf))
|
|
||||||
free(surf);
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default fallback routine - drivers might override this.
|
* Default fallback routine - drivers might override this.
|
||||||
*/
|
*/
|
||||||
|
|
@ -445,7 +381,7 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
|
||||||
|
|
||||||
switch (attribute) {
|
switch (attribute) {
|
||||||
case EGL_MIPMAP_LEVEL:
|
case EGL_MIPMAP_LEVEL:
|
||||||
confval = GET_CONFIG_ATTRIB(surface->Config, EGL_RENDERABLE_TYPE);
|
confval = surface->Config->RenderableType;
|
||||||
if (!(confval & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT))) {
|
if (!(confval & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT))) {
|
||||||
err = EGL_BAD_PARAMETER;
|
err = EGL_BAD_PARAMETER;
|
||||||
break;
|
break;
|
||||||
|
|
@ -457,7 +393,7 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
|
||||||
case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
|
case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
|
||||||
break;
|
break;
|
||||||
case EGL_MULTISAMPLE_RESOLVE_BOX:
|
case EGL_MULTISAMPLE_RESOLVE_BOX:
|
||||||
confval = GET_CONFIG_ATTRIB(surface->Config, EGL_SURFACE_TYPE);
|
confval = surface->Config->SurfaceType;
|
||||||
if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
|
if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
|
||||||
err = EGL_BAD_MATCH;
|
err = EGL_BAD_MATCH;
|
||||||
break;
|
break;
|
||||||
|
|
@ -474,7 +410,7 @@ _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
|
||||||
case EGL_BUFFER_DESTROYED:
|
case EGL_BUFFER_DESTROYED:
|
||||||
break;
|
break;
|
||||||
case EGL_BUFFER_PRESERVED:
|
case EGL_BUFFER_PRESERVED:
|
||||||
confval = GET_CONFIG_ATTRIB(surface->Config, EGL_SURFACE_TYPE);
|
confval = surface->Config->SurfaceType;
|
||||||
if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
|
if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
|
||||||
err = EGL_BAD_MATCH;
|
err = EGL_BAD_MATCH;
|
||||||
break;
|
break;
|
||||||
|
|
@ -536,40 +472,6 @@ _eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
|
||||||
_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
|
|
||||||
EGLint buffer)
|
|
||||||
{
|
|
||||||
/* Just do basic error checking and return success/fail.
|
|
||||||
* Drivers must implement the real stuff.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (surface->Type != EGL_PBUFFER_BIT) {
|
|
||||||
_eglError(EGL_BAD_SURFACE, "eglBindTexImage");
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (surface->TextureFormat == EGL_NO_TEXTURE) {
|
|
||||||
_eglError(EGL_BAD_MATCH, "eglBindTexImage");
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer != EGL_BACK_BUFFER) {
|
|
||||||
_eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!surface->BoundToTexture) {
|
|
||||||
_eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
surface->BoundToTexture = EGL_FALSE;
|
|
||||||
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
EGLBoolean
|
||||||
_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
|
_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
|
||||||
EGLint interval)
|
EGLint interval)
|
||||||
|
|
@ -577,24 +479,3 @@ _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
|
||||||
_eglClampSwapInterval(surf, interval);
|
_eglClampSwapInterval(surf, interval);
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef EGL_VERSION_1_2
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example function - drivers should do a proper implementation.
|
|
||||||
*/
|
|
||||||
_EGLSurface *
|
|
||||||
_eglCreatePbufferFromClientBuffer(_EGLDriver *drv, _EGLDisplay *dpy,
|
|
||||||
EGLenum buftype, EGLClientBuffer buffer,
|
|
||||||
_EGLConfig *conf, const EGLint *attrib_list)
|
|
||||||
{
|
|
||||||
if (buftype != EGL_OPENVG_IMAGE) {
|
|
||||||
_eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* EGL_VERSION_1_2 */
|
|
||||||
|
|
|
||||||
|
|
@ -51,34 +51,10 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
|
||||||
_EGLConfig *config, const EGLint *attrib_list);
|
_EGLConfig *config, const EGLint *attrib_list);
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglCopyBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLNativePixmapType target);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint *value);
|
_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint *value);
|
||||||
|
|
||||||
|
|
||||||
extern _EGLSurface *
|
|
||||||
_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, EGLNativeWindowType window, const EGLint *attrib_list);
|
|
||||||
|
|
||||||
|
|
||||||
extern _EGLSurface *
|
|
||||||
_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, EGLNativePixmapType pixmap, const EGLint *attrib_list);
|
|
||||||
|
|
||||||
|
|
||||||
extern _EGLSurface *
|
|
||||||
_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, const EGLint *attrib_list);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
_eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint value);
|
_eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint value);
|
||||||
|
|
||||||
|
|
@ -87,45 +63,40 @@ PUBLIC extern EGLBoolean
|
||||||
_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint buffer);
|
_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint buffer);
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint buffer);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval);
|
_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval);
|
||||||
|
|
||||||
|
|
||||||
#ifdef EGL_VERSION_1_2
|
|
||||||
|
|
||||||
extern _EGLSurface *
|
|
||||||
_eglCreatePbufferFromClientBuffer(_EGLDriver *drv, _EGLDisplay *dpy,
|
|
||||||
EGLenum buftype, EGLClientBuffer buffer,
|
|
||||||
_EGLConfig *conf, const EGLint *attrib_list);
|
|
||||||
|
|
||||||
#endif /* EGL_VERSION_1_2 */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if there is a context bound to the surface.
|
* Increment reference count for the surface.
|
||||||
*
|
|
||||||
* The binding is considered a reference to the surface. Drivers should not
|
|
||||||
* destroy a surface when it is bound.
|
|
||||||
*/
|
*/
|
||||||
static INLINE EGLBoolean
|
static INLINE _EGLSurface *
|
||||||
_eglIsSurfaceBound(_EGLSurface *surf)
|
_eglGetSurface(_EGLSurface *surf)
|
||||||
{
|
{
|
||||||
return (surf->CurrentContext != NULL);
|
if (surf)
|
||||||
|
_eglGetResource(&surf->Resource);
|
||||||
|
return surf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link a surface to a display and return the handle of the link.
|
* Decrement reference count for the surface.
|
||||||
|
*/
|
||||||
|
static INLINE EGLBoolean
|
||||||
|
_eglPutSurface(_EGLSurface *surf)
|
||||||
|
{
|
||||||
|
return (surf) ? _eglPutResource(&surf->Resource) : EGL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link a surface to its display and return the handle of the link.
|
||||||
* The handle can be passed to client directly.
|
* The handle can be passed to client directly.
|
||||||
*/
|
*/
|
||||||
static INLINE EGLSurface
|
static INLINE EGLSurface
|
||||||
_eglLinkSurface(_EGLSurface *surf, _EGLDisplay *dpy)
|
_eglLinkSurface(_EGLSurface *surf)
|
||||||
{
|
{
|
||||||
_eglLinkResource(&surf->Resource, _EGL_RESOURCE_SURFACE, dpy);
|
_eglLinkResource(&surf->Resource, _EGL_RESOURCE_SURFACE);
|
||||||
return (EGLSurface) surf;
|
return (EGLSurface) surf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,18 +138,4 @@ _eglGetSurfaceHandle(_EGLSurface *surf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the surface is linked to a display.
|
|
||||||
*
|
|
||||||
* The link is considered a reference to the surface (the display is owning the
|
|
||||||
* surface). Drivers should not destroy a surface when it is linked.
|
|
||||||
*/
|
|
||||||
static INLINE EGLBoolean
|
|
||||||
_eglIsSurfaceLinked(_EGLSurface *surf)
|
|
||||||
{
|
|
||||||
_EGLResource *res = (_EGLResource *) surf;
|
|
||||||
return (res && _eglIsResourceLinked(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* EGLSURFACE_INCLUDED */
|
#endif /* EGLSURFACE_INCLUDED */
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,7 @@ _eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type,
|
||||||
!(type == EGL_SYNC_FENCE_KHR && dpy->Extensions.KHR_fence_sync))
|
!(type == EGL_SYNC_FENCE_KHR && dpy->Extensions.KHR_fence_sync))
|
||||||
return _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
|
return _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
|
||||||
|
|
||||||
memset(sync, 0, sizeof(*sync));
|
_eglInitResource(&sync->Resource, sizeof(*sync), dpy);
|
||||||
|
|
||||||
sync->Resource.Display = dpy;
|
|
||||||
|
|
||||||
sync->Type = type;
|
sync->Type = type;
|
||||||
sync->SyncStatus = EGL_UNSIGNALED_KHR;
|
sync->SyncStatus = EGL_UNSIGNALED_KHR;
|
||||||
sync->SyncCondition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
|
sync->SyncCondition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
|
||||||
|
|
@ -66,37 +63,6 @@ _eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_EGLSync *
|
|
||||||
_eglCreateSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy,
|
|
||||||
EGLenum type, const EGLint *attrib_list)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
|
||||||
_eglDestroySyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
|
|
||||||
{
|
|
||||||
return EGL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EGLint
|
|
||||||
_eglClientWaitSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
|
||||||
EGLint flags, EGLTimeKHR timeout)
|
|
||||||
{
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
|
||||||
_eglSignalSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
|
||||||
EGLenum mode)
|
|
||||||
{
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EGLBoolean
|
EGLBoolean
|
||||||
_eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
_eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
||||||
EGLint attribute, EGLint *value)
|
EGLint attribute, EGLint *value)
|
||||||
|
|
|
||||||
|
|
@ -28,38 +28,41 @@ _eglInitSync(_EGLSync *sync, _EGLDisplay *dpy, EGLenum type,
|
||||||
const EGLint *attrib_list);
|
const EGLint *attrib_list);
|
||||||
|
|
||||||
|
|
||||||
extern _EGLSync *
|
|
||||||
_eglCreateSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy,
|
|
||||||
EGLenum type, const EGLint *attrib_list);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglDestroySyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLint
|
|
||||||
_eglClientWaitSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
|
||||||
EGLint flags, EGLTimeKHR timeout);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
|
||||||
_eglSignalSyncKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
|
||||||
EGLenum mode);
|
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
_eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
_eglGetSyncAttribKHR(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
||||||
EGLint attribute, EGLint *value);
|
EGLint attribute, EGLint *value);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link a sync to a display and return the handle of the link.
|
* Increment reference count for the sync.
|
||||||
|
*/
|
||||||
|
static INLINE _EGLSync *
|
||||||
|
_eglGetSync(_EGLSync *sync)
|
||||||
|
{
|
||||||
|
if (sync)
|
||||||
|
_eglGetResource(&sync->Resource);
|
||||||
|
return sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement reference count for the sync.
|
||||||
|
*/
|
||||||
|
static INLINE EGLBoolean
|
||||||
|
_eglPutSync(_EGLSync *sync)
|
||||||
|
{
|
||||||
|
return (sync) ? _eglPutResource(&sync->Resource) : EGL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link a sync to its display and return the handle of the link.
|
||||||
* The handle can be passed to client directly.
|
* The handle can be passed to client directly.
|
||||||
*/
|
*/
|
||||||
static INLINE EGLSyncKHR
|
static INLINE EGLSyncKHR
|
||||||
_eglLinkSync(_EGLSync *sync, _EGLDisplay *dpy)
|
_eglLinkSync(_EGLSync *sync)
|
||||||
{
|
{
|
||||||
_eglLinkResource(&sync->Resource, _EGL_RESOURCE_SYNC, dpy);
|
_eglLinkResource(&sync->Resource, _EGL_RESOURCE_SYNC);
|
||||||
return (EGLSyncKHR) sync;
|
return (EGLSyncKHR) sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,20 +103,6 @@ _eglGetSyncHandle(_EGLSync *sync)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the sync is linked to a display.
|
|
||||||
*
|
|
||||||
* The link is considered a reference to the sync (the display is owning the
|
|
||||||
* sync). Drivers should not destroy a sync when it is linked.
|
|
||||||
*/
|
|
||||||
static INLINE EGLBoolean
|
|
||||||
_eglIsSyncLinked(_EGLSync *sync)
|
|
||||||
{
|
|
||||||
_EGLResource *res = (_EGLResource *) sync;
|
|
||||||
return (res && _eglIsResourceLinked(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* EGL_KHR_reusable_sync */
|
#endif /* EGL_KHR_reusable_sync */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ typedef struct _egl_extensions _EGLExtensions;
|
||||||
|
|
||||||
typedef struct _egl_image _EGLImage;
|
typedef struct _egl_image _EGLImage;
|
||||||
|
|
||||||
|
typedef struct _egl_image_attribs _EGLImageAttribs;
|
||||||
|
|
||||||
typedef struct _egl_mode _EGLMode;
|
typedef struct _egl_mode _EGLMode;
|
||||||
|
|
||||||
typedef struct _egl_resource _EGLResource;
|
typedef struct _egl_resource _EGLResource;
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,7 @@ GALLIVM_SOURCES = \
|
||||||
gallivm/lp_bld_struct.c \
|
gallivm/lp_bld_struct.c \
|
||||||
gallivm/lp_bld_swizzle.c \
|
gallivm/lp_bld_swizzle.c \
|
||||||
gallivm/lp_bld_tgsi_aos.c \
|
gallivm/lp_bld_tgsi_aos.c \
|
||||||
|
gallivm/lp_bld_tgsi_info.c \
|
||||||
gallivm/lp_bld_tgsi_soa.c \
|
gallivm/lp_bld_tgsi_soa.c \
|
||||||
gallivm/lp_bld_type.c \
|
gallivm/lp_bld_type.c \
|
||||||
draw/draw_llvm.c \
|
draw/draw_llvm.c \
|
||||||
|
|
@ -207,16 +208,16 @@ include ../Makefile.template
|
||||||
|
|
||||||
|
|
||||||
indices/u_indices_gen.c: indices/u_indices_gen.py
|
indices/u_indices_gen.c: indices/u_indices_gen.py
|
||||||
python $< > $@
|
$(PYTHON2) $< > $@
|
||||||
|
|
||||||
indices/u_unfilled_gen.c: indices/u_unfilled_gen.py
|
indices/u_unfilled_gen.c: indices/u_unfilled_gen.py
|
||||||
python $< > $@
|
$(PYTHON2) $< > $@
|
||||||
|
|
||||||
util/u_format_srgb.c: util/u_format_srgb.py
|
util/u_format_srgb.c: util/u_format_srgb.py
|
||||||
python $< > $@
|
$(PYTHON2) $< > $@
|
||||||
|
|
||||||
util/u_format_table.c: util/u_format_table.py util/u_format_pack.py util/u_format_parse.py util/u_format.csv
|
util/u_format_table.c: util/u_format_table.py util/u_format_pack.py util/u_format_parse.py util/u_format.csv
|
||||||
python util/u_format_table.py util/u_format.csv > $@
|
$(PYTHON2) util/u_format_table.py util/u_format.csv > $@
|
||||||
|
|
||||||
util/u_half.c: util/u_half.py
|
util/u_half.c: util/u_half.py
|
||||||
python util/u_half.py > $@
|
$(PYTHON2) util/u_half.py > $@
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,7 @@ if env['llvm']:
|
||||||
'gallivm/lp_bld_struct.c',
|
'gallivm/lp_bld_struct.c',
|
||||||
'gallivm/lp_bld_swizzle.c',
|
'gallivm/lp_bld_swizzle.c',
|
||||||
'gallivm/lp_bld_tgsi_aos.c',
|
'gallivm/lp_bld_tgsi_aos.c',
|
||||||
|
'gallivm/lp_bld_tgsi_info.c',
|
||||||
'gallivm/lp_bld_tgsi_soa.c',
|
'gallivm/lp_bld_tgsi_soa.c',
|
||||||
'gallivm/lp_bld_type.c',
|
'gallivm/lp_bld_type.c',
|
||||||
'draw/draw_llvm.c',
|
'draw/draw_llvm.c',
|
||||||
|
|
|
||||||
|
|
@ -335,6 +335,7 @@ draw_set_mapped_constant_buffer(struct draw_context *draw,
|
||||||
case PIPE_SHADER_VERTEX:
|
case PIPE_SHADER_VERTEX:
|
||||||
draw->pt.user.vs_constants[slot] = buffer;
|
draw->pt.user.vs_constants[slot] = buffer;
|
||||||
draw->pt.user.vs_constants_size[slot] = size;
|
draw->pt.user.vs_constants_size[slot] = size;
|
||||||
|
draw->pt.user.planes = (float (*) [12][4]) &(draw->plane[0]);
|
||||||
draw_vs_set_constants(draw, slot, buffer, size);
|
draw_vs_set_constants(draw, slot, buffer, size);
|
||||||
break;
|
break;
|
||||||
case PIPE_SHADER_GEOMETRY:
|
case PIPE_SHADER_GEOMETRY:
|
||||||
|
|
@ -721,9 +722,9 @@ draw_set_mapped_texture(struct draw_context *draw,
|
||||||
unsigned sampler_idx,
|
unsigned sampler_idx,
|
||||||
uint32_t width, uint32_t height, uint32_t depth,
|
uint32_t width, uint32_t height, uint32_t depth,
|
||||||
uint32_t last_level,
|
uint32_t last_level,
|
||||||
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
|
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
|
||||||
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
|
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
|
||||||
const void *data[DRAW_MAX_TEXTURE_LEVELS])
|
const void *data[PIPE_MAX_TEXTURE_LEVELS])
|
||||||
{
|
{
|
||||||
#ifdef HAVE_LLVM
|
#ifdef HAVE_LLVM
|
||||||
if(draw->llvm)
|
if(draw->llvm)
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@ struct draw_geometry_shader;
|
||||||
struct draw_fragment_shader;
|
struct draw_fragment_shader;
|
||||||
struct tgsi_sampler;
|
struct tgsi_sampler;
|
||||||
|
|
||||||
#define DRAW_MAX_TEXTURE_LEVELS 13 /* 4K x 4K for now */
|
|
||||||
|
|
||||||
struct draw_context *draw_create( struct pipe_context *pipe );
|
struct draw_context *draw_create( struct pipe_context *pipe );
|
||||||
|
|
||||||
|
|
@ -120,9 +119,9 @@ draw_set_mapped_texture(struct draw_context *draw,
|
||||||
unsigned sampler_idx,
|
unsigned sampler_idx,
|
||||||
uint32_t width, uint32_t height, uint32_t depth,
|
uint32_t width, uint32_t height, uint32_t depth,
|
||||||
uint32_t last_level,
|
uint32_t last_level,
|
||||||
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
|
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
|
||||||
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
|
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
|
||||||
const void *data[DRAW_MAX_TEXTURE_LEVELS]);
|
const void *data[PIPE_MAX_TEXTURE_LEVELS]);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@
|
||||||
#include "draw_vs.h"
|
#include "draw_vs.h"
|
||||||
|
|
||||||
#include "gallivm/lp_bld_arit.h"
|
#include "gallivm/lp_bld_arit.h"
|
||||||
|
#include "gallivm/lp_bld_logic.h"
|
||||||
|
#include "gallivm/lp_bld_const.h"
|
||||||
|
#include "gallivm/lp_bld_swizzle.h"
|
||||||
#include "gallivm/lp_bld_struct.h"
|
#include "gallivm/lp_bld_struct.h"
|
||||||
#include "gallivm/lp_bld_type.h"
|
#include "gallivm/lp_bld_type.h"
|
||||||
#include "gallivm/lp_bld_flow.h"
|
#include "gallivm/lp_bld_flow.h"
|
||||||
|
|
@ -43,7 +46,6 @@
|
||||||
#include "tgsi/tgsi_exec.h"
|
#include "tgsi/tgsi_exec.h"
|
||||||
#include "tgsi/tgsi_dump.h"
|
#include "tgsi/tgsi_dump.h"
|
||||||
|
|
||||||
#include "util/u_cpu_detect.h"
|
|
||||||
#include "util/u_math.h"
|
#include "util/u_math.h"
|
||||||
#include "util/u_pointer.h"
|
#include "util/u_pointer.h"
|
||||||
#include "util/u_string.h"
|
#include "util/u_string.h"
|
||||||
|
|
@ -72,12 +74,12 @@ init_globals(struct draw_llvm *llvm)
|
||||||
elem_types[DRAW_JIT_TEXTURE_DEPTH] = LLVMInt32Type();
|
elem_types[DRAW_JIT_TEXTURE_DEPTH] = LLVMInt32Type();
|
||||||
elem_types[DRAW_JIT_TEXTURE_LAST_LEVEL] = LLVMInt32Type();
|
elem_types[DRAW_JIT_TEXTURE_LAST_LEVEL] = LLVMInt32Type();
|
||||||
elem_types[DRAW_JIT_TEXTURE_ROW_STRIDE] =
|
elem_types[DRAW_JIT_TEXTURE_ROW_STRIDE] =
|
||||||
LLVMArrayType(LLVMInt32Type(), DRAW_MAX_TEXTURE_LEVELS);
|
LLVMArrayType(LLVMInt32Type(), PIPE_MAX_TEXTURE_LEVELS);
|
||||||
elem_types[DRAW_JIT_TEXTURE_IMG_STRIDE] =
|
elem_types[DRAW_JIT_TEXTURE_IMG_STRIDE] =
|
||||||
LLVMArrayType(LLVMInt32Type(), DRAW_MAX_TEXTURE_LEVELS);
|
LLVMArrayType(LLVMInt32Type(), PIPE_MAX_TEXTURE_LEVELS);
|
||||||
elem_types[DRAW_JIT_TEXTURE_DATA] =
|
elem_types[DRAW_JIT_TEXTURE_DATA] =
|
||||||
LLVMArrayType(LLVMPointerType(LLVMInt8Type(), 0),
|
LLVMArrayType(LLVMPointerType(LLVMInt8Type(), 0),
|
||||||
DRAW_MAX_TEXTURE_LEVELS);
|
PIPE_MAX_TEXTURE_LEVELS);
|
||||||
elem_types[DRAW_JIT_TEXTURE_MIN_LOD] = LLVMFloatType();
|
elem_types[DRAW_JIT_TEXTURE_MIN_LOD] = LLVMFloatType();
|
||||||
elem_types[DRAW_JIT_TEXTURE_MAX_LOD] = LLVMFloatType();
|
elem_types[DRAW_JIT_TEXTURE_MAX_LOD] = LLVMFloatType();
|
||||||
elem_types[DRAW_JIT_TEXTURE_LOD_BIAS] = LLVMFloatType();
|
elem_types[DRAW_JIT_TEXTURE_LOD_BIAS] = LLVMFloatType();
|
||||||
|
|
@ -128,12 +130,14 @@ init_globals(struct draw_llvm *llvm)
|
||||||
|
|
||||||
/* struct draw_jit_context */
|
/* struct draw_jit_context */
|
||||||
{
|
{
|
||||||
LLVMTypeRef elem_types[3];
|
LLVMTypeRef elem_types[5];
|
||||||
LLVMTypeRef context_type;
|
LLVMTypeRef context_type;
|
||||||
|
|
||||||
elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */
|
elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */
|
||||||
elem_types[1] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */
|
elem_types[1] = LLVMPointerType(LLVMFloatType(), 0); /* gs_constants */
|
||||||
elem_types[2] = LLVMArrayType(texture_type,
|
elem_types[2] = LLVMPointerType(LLVMArrayType(LLVMArrayType(LLVMFloatType(), 4), 12), 0); /* planes */
|
||||||
|
elem_types[3] = LLVMPointerType(LLVMFloatType(), 0); /* viewport */
|
||||||
|
elem_types[4] = LLVMArrayType(texture_type,
|
||||||
PIPE_MAX_VERTEX_SAMPLERS); /* textures */
|
PIPE_MAX_VERTEX_SAMPLERS); /* textures */
|
||||||
|
|
||||||
context_type = LLVMStructType(elem_types, Elements(elem_types), 0);
|
context_type = LLVMStructType(elem_types, Elements(elem_types), 0);
|
||||||
|
|
@ -142,6 +146,8 @@ init_globals(struct draw_llvm *llvm)
|
||||||
llvm->target, context_type, 0);
|
llvm->target, context_type, 0);
|
||||||
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, gs_constants,
|
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, gs_constants,
|
||||||
llvm->target, context_type, 1);
|
llvm->target, context_type, 1);
|
||||||
|
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, planes,
|
||||||
|
llvm->target, context_type, 2);
|
||||||
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, textures,
|
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, textures,
|
||||||
llvm->target, context_type,
|
llvm->target, context_type,
|
||||||
DRAW_JIT_CTX_TEXTURES);
|
DRAW_JIT_CTX_TEXTURES);
|
||||||
|
|
@ -267,13 +273,7 @@ draw_llvm_create(struct draw_context *draw)
|
||||||
LLVMAddConstantPropagationPass(llvm->pass);
|
LLVMAddConstantPropagationPass(llvm->pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(util_cpu_caps.has_sse4_1) {
|
|
||||||
/* FIXME: There is a bug in this pass, whereby the combination of fptosi
|
|
||||||
* and sitofp (necessary for trunc/floor/ceil/round implementation)
|
|
||||||
* somehow becomes invalid code.
|
|
||||||
*/
|
|
||||||
LLVMAddInstructionCombiningPass(llvm->pass);
|
LLVMAddInstructionCombiningPass(llvm->pass);
|
||||||
}
|
|
||||||
LLVMAddGVNPass(llvm->pass);
|
LLVMAddGVNPass(llvm->pass);
|
||||||
} else {
|
} else {
|
||||||
/* We need at least this pass to prevent the backends to fail in
|
/* We need at least this pass to prevent the backends to fail in
|
||||||
|
|
@ -421,7 +421,7 @@ generate_fetch(LLVMBuilderRef builder,
|
||||||
"instance_divisor");
|
"instance_divisor");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* limit index to min(inex, vb_max_index) */
|
/* limit index to min(index, vb_max_index) */
|
||||||
cond = LLVMBuildICmp(builder, LLVMIntULE, index, vb_max_index, "");
|
cond = LLVMBuildICmp(builder, LLVMIntULE, index, vb_max_index, "");
|
||||||
index = LLVMBuildSelect(builder, cond, index, vb_max_index, "");
|
index = LLVMBuildSelect(builder, cond, index, vb_max_index, "");
|
||||||
|
|
||||||
|
|
@ -550,19 +550,28 @@ static void
|
||||||
store_aos(LLVMBuilderRef builder,
|
store_aos(LLVMBuilderRef builder,
|
||||||
LLVMValueRef io_ptr,
|
LLVMValueRef io_ptr,
|
||||||
LLVMValueRef index,
|
LLVMValueRef index,
|
||||||
LLVMValueRef value)
|
LLVMValueRef value,
|
||||||
|
LLVMValueRef clipmask)
|
||||||
{
|
{
|
||||||
LLVMValueRef id_ptr = draw_jit_header_id(builder, io_ptr);
|
LLVMValueRef id_ptr = draw_jit_header_id(builder, io_ptr);
|
||||||
LLVMValueRef data_ptr = draw_jit_header_data(builder, io_ptr);
|
LLVMValueRef data_ptr = draw_jit_header_data(builder, io_ptr);
|
||||||
LLVMValueRef indices[3];
|
LLVMValueRef indices[3];
|
||||||
|
LLVMValueRef val, shift;
|
||||||
|
|
||||||
indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||||
indices[1] = index;
|
indices[1] = index;
|
||||||
indices[2] = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
indices[2] = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||||
|
|
||||||
/* undefined vertex */
|
/* initialize vertex id:16 = 0xffff, pad:3 = 0, edgeflag:1 = 1 */
|
||||||
LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(),
|
val = LLVMConstInt(LLVMInt32Type(), 0xffff1, 0);
|
||||||
0xffff, 0), id_ptr);
|
shift = LLVMConstInt(LLVMInt32Type(), 12, 0);
|
||||||
|
val = LLVMBuildShl(builder, val, shift, "");
|
||||||
|
/* add clipmask:12 */
|
||||||
|
val = LLVMBuildOr(builder, val, clipmask, "");
|
||||||
|
|
||||||
|
/* store vertex header */
|
||||||
|
LLVMBuildStore(builder, val, id_ptr);
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG_STORE
|
#if DEBUG_STORE
|
||||||
lp_build_printf(builder, " ---- %p storing attribute %d (io = %p)\n", data_ptr, index, io_ptr);
|
lp_build_printf(builder, " ---- %p storing attribute %d (io = %p)\n", data_ptr, index, io_ptr);
|
||||||
|
|
@ -617,7 +626,8 @@ store_aos_array(LLVMBuilderRef builder,
|
||||||
LLVMValueRef io_ptr,
|
LLVMValueRef io_ptr,
|
||||||
LLVMValueRef aos[NUM_CHANNELS],
|
LLVMValueRef aos[NUM_CHANNELS],
|
||||||
int attrib,
|
int attrib,
|
||||||
int num_outputs)
|
int num_outputs,
|
||||||
|
LLVMValueRef clipmask)
|
||||||
{
|
{
|
||||||
LLVMValueRef attr_index = LLVMConstInt(LLVMInt32Type(), attrib, 0);
|
LLVMValueRef attr_index = LLVMConstInt(LLVMInt32Type(), attrib, 0);
|
||||||
LLVMValueRef ind0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
LLVMValueRef ind0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||||
|
|
@ -625,6 +635,7 @@ store_aos_array(LLVMBuilderRef builder,
|
||||||
LLVMValueRef ind2 = LLVMConstInt(LLVMInt32Type(), 2, 0);
|
LLVMValueRef ind2 = LLVMConstInt(LLVMInt32Type(), 2, 0);
|
||||||
LLVMValueRef ind3 = LLVMConstInt(LLVMInt32Type(), 3, 0);
|
LLVMValueRef ind3 = LLVMConstInt(LLVMInt32Type(), 3, 0);
|
||||||
LLVMValueRef io0_ptr, io1_ptr, io2_ptr, io3_ptr;
|
LLVMValueRef io0_ptr, io1_ptr, io2_ptr, io3_ptr;
|
||||||
|
LLVMValueRef clipmask0, clipmask1, clipmask2, clipmask3;
|
||||||
|
|
||||||
debug_assert(NUM_CHANNELS == 4);
|
debug_assert(NUM_CHANNELS == 4);
|
||||||
|
|
||||||
|
|
@ -637,21 +648,31 @@ store_aos_array(LLVMBuilderRef builder,
|
||||||
io3_ptr = LLVMBuildGEP(builder, io_ptr,
|
io3_ptr = LLVMBuildGEP(builder, io_ptr,
|
||||||
&ind3, 1, "");
|
&ind3, 1, "");
|
||||||
|
|
||||||
#if DEBUG_STORE
|
clipmask0 = LLVMBuildExtractElement(builder, clipmask,
|
||||||
lp_build_printf(builder, " io = %p, indexes[%d, %d, %d, %d]\n",
|
ind0, "");
|
||||||
io_ptr, ind0, ind1, ind2, ind3);
|
clipmask1 = LLVMBuildExtractElement(builder, clipmask,
|
||||||
#endif
|
ind1, "");
|
||||||
|
clipmask2 = LLVMBuildExtractElement(builder, clipmask,
|
||||||
|
ind2, "");
|
||||||
|
clipmask3 = LLVMBuildExtractElement(builder, clipmask,
|
||||||
|
ind3, "");
|
||||||
|
|
||||||
store_aos(builder, io0_ptr, attr_index, aos[0]);
|
#if DEBUG_STORE
|
||||||
store_aos(builder, io1_ptr, attr_index, aos[1]);
|
lp_build_printf(builder, "io = %p, indexes[%d, %d, %d, %d]\n, clipmask0 = %x, clipmask1 = %x, clipmask2 = %x, clipmask3 = %x\n",
|
||||||
store_aos(builder, io2_ptr, attr_index, aos[2]);
|
io_ptr, ind0, ind1, ind2, ind3, clipmask0, clipmask1, clipmask2, clipmask3);
|
||||||
store_aos(builder, io3_ptr, attr_index, aos[3]);
|
#endif
|
||||||
|
/* store for each of the 4 vertices */
|
||||||
|
store_aos(builder, io0_ptr, attr_index, aos[0], clipmask0);
|
||||||
|
store_aos(builder, io1_ptr, attr_index, aos[1], clipmask1);
|
||||||
|
store_aos(builder, io2_ptr, attr_index, aos[2], clipmask2);
|
||||||
|
store_aos(builder, io3_ptr, attr_index, aos[3], clipmask3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
convert_to_aos(LLVMBuilderRef builder,
|
convert_to_aos(LLVMBuilderRef builder,
|
||||||
LLVMValueRef io,
|
LLVMValueRef io,
|
||||||
LLVMValueRef (*outputs)[NUM_CHANNELS],
|
LLVMValueRef (*outputs)[NUM_CHANNELS],
|
||||||
|
LLVMValueRef clipmask,
|
||||||
int num_outputs,
|
int num_outputs,
|
||||||
int max_vertices)
|
int max_vertices)
|
||||||
{
|
{
|
||||||
|
|
@ -680,13 +701,305 @@ convert_to_aos(LLVMBuilderRef builder,
|
||||||
io,
|
io,
|
||||||
aos,
|
aos,
|
||||||
attrib,
|
attrib,
|
||||||
num_outputs);
|
num_outputs,
|
||||||
|
clipmask);
|
||||||
}
|
}
|
||||||
#if DEBUG_STORE
|
#if DEBUG_STORE
|
||||||
lp_build_printf(builder, " # storing end\n");
|
lp_build_printf(builder, " # storing end\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stores original vertex positions in clip coordinates
|
||||||
|
* There is probably a more efficient way to do this, 4 floats at once
|
||||||
|
* rather than extracting each element one by one.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
store_clip(LLVMBuilderRef builder,
|
||||||
|
LLVMValueRef io_ptr,
|
||||||
|
LLVMValueRef (*outputs)[NUM_CHANNELS])
|
||||||
|
{
|
||||||
|
LLVMValueRef out[4];
|
||||||
|
LLVMValueRef indices[2];
|
||||||
|
LLVMValueRef io0_ptr, io1_ptr, io2_ptr, io3_ptr;
|
||||||
|
LLVMValueRef clip_ptr0, clip_ptr1, clip_ptr2, clip_ptr3;
|
||||||
|
LLVMValueRef clip0_ptr, clip1_ptr, clip2_ptr, clip3_ptr;
|
||||||
|
LLVMValueRef out0elem, out1elem, out2elem, out3elem;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
LLVMValueRef ind0 = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||||
|
LLVMValueRef ind1 = LLVMConstInt(LLVMInt32Type(), 1, 0);
|
||||||
|
LLVMValueRef ind2 = LLVMConstInt(LLVMInt32Type(), 2, 0);
|
||||||
|
LLVMValueRef ind3 = LLVMConstInt(LLVMInt32Type(), 3, 0);
|
||||||
|
|
||||||
|
indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||||
|
indices[1] = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||||
|
|
||||||
|
out[0] = LLVMBuildLoad(builder, outputs[0][0], ""); /*x0 x1 x2 x3*/
|
||||||
|
out[1] = LLVMBuildLoad(builder, outputs[0][1], ""); /*y0 y1 y2 y3*/
|
||||||
|
out[2] = LLVMBuildLoad(builder, outputs[0][2], ""); /*z0 z1 z2 z3*/
|
||||||
|
out[3] = LLVMBuildLoad(builder, outputs[0][3], ""); /*w0 w1 w2 w3*/
|
||||||
|
|
||||||
|
io0_ptr = LLVMBuildGEP(builder, io_ptr, &ind0, 1, "");
|
||||||
|
io1_ptr = LLVMBuildGEP(builder, io_ptr, &ind1, 1, "");
|
||||||
|
io2_ptr = LLVMBuildGEP(builder, io_ptr, &ind2, 1, "");
|
||||||
|
io3_ptr = LLVMBuildGEP(builder, io_ptr, &ind3, 1, "");
|
||||||
|
|
||||||
|
clip_ptr0 = draw_jit_header_clip(builder, io0_ptr);
|
||||||
|
clip_ptr1 = draw_jit_header_clip(builder, io1_ptr);
|
||||||
|
clip_ptr2 = draw_jit_header_clip(builder, io2_ptr);
|
||||||
|
clip_ptr3 = draw_jit_header_clip(builder, io3_ptr);
|
||||||
|
|
||||||
|
for (i = 0; i<4; i++){
|
||||||
|
clip0_ptr = LLVMBuildGEP(builder, clip_ptr0,
|
||||||
|
indices, 2, ""); //x0
|
||||||
|
clip1_ptr = LLVMBuildGEP(builder, clip_ptr1,
|
||||||
|
indices, 2, ""); //x1
|
||||||
|
clip2_ptr = LLVMBuildGEP(builder, clip_ptr2,
|
||||||
|
indices, 2, ""); //x2
|
||||||
|
clip3_ptr = LLVMBuildGEP(builder, clip_ptr3,
|
||||||
|
indices, 2, ""); //x3
|
||||||
|
|
||||||
|
out0elem = LLVMBuildExtractElement(builder, out[i],
|
||||||
|
ind0, ""); //x0
|
||||||
|
out1elem = LLVMBuildExtractElement(builder, out[i],
|
||||||
|
ind1, ""); //x1
|
||||||
|
out2elem = LLVMBuildExtractElement(builder, out[i],
|
||||||
|
ind2, ""); //x2
|
||||||
|
out3elem = LLVMBuildExtractElement(builder, out[i],
|
||||||
|
ind3, ""); //x3
|
||||||
|
|
||||||
|
LLVMBuildStore(builder, out0elem, clip0_ptr);
|
||||||
|
LLVMBuildStore(builder, out1elem, clip1_ptr);
|
||||||
|
LLVMBuildStore(builder, out2elem, clip2_ptr);
|
||||||
|
LLVMBuildStore(builder, out3elem, clip3_ptr);
|
||||||
|
|
||||||
|
indices[1]= LLVMBuildAdd(builder, indices[1], ind1, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Equivalent of _mm_set1_ps(a)
|
||||||
|
*/
|
||||||
|
static LLVMValueRef vec4f_from_scalar(LLVMBuilderRef bld,
|
||||||
|
LLVMValueRef a,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
LLVMValueRef res = LLVMGetUndef(LLVMVectorType(LLVMFloatType(), 4));
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < 4; ++i) {
|
||||||
|
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
|
||||||
|
res = LLVMBuildInsertElement(bld, res, a, index, i == 3 ? name : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transforms the outputs for viewport mapping
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
generate_viewport(struct draw_llvm *llvm,
|
||||||
|
LLVMBuilderRef builder,
|
||||||
|
LLVMValueRef (*outputs)[NUM_CHANNELS],
|
||||||
|
LLVMValueRef context_ptr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct lp_type f32_type = lp_type_float_vec(32);
|
||||||
|
LLVMValueRef out3 = LLVMBuildLoad(builder, outputs[0][3], ""); /*w0 w1 w2 w3*/
|
||||||
|
LLVMValueRef const1 = lp_build_const_vec(f32_type, 1.0); /*1.0 1.0 1.0 1.0*/
|
||||||
|
LLVMValueRef vp_ptr = draw_jit_context_viewport(builder, context_ptr);
|
||||||
|
|
||||||
|
/* for 1/w convention*/
|
||||||
|
out3 = LLVMBuildFDiv(builder, const1, out3, "");
|
||||||
|
LLVMBuildStore(builder, out3, outputs[0][3]);
|
||||||
|
|
||||||
|
/* Viewport Mapping */
|
||||||
|
for (i=0; i<3; i++){
|
||||||
|
LLVMValueRef out = LLVMBuildLoad(builder, outputs[0][i], ""); /*x0 x1 x2 x3*/
|
||||||
|
LLVMValueRef scale;
|
||||||
|
LLVMValueRef trans;
|
||||||
|
LLVMValueRef scale_i;
|
||||||
|
LLVMValueRef trans_i;
|
||||||
|
LLVMValueRef index;
|
||||||
|
|
||||||
|
index = LLVMConstInt(LLVMInt32Type(), i, 0);
|
||||||
|
scale_i = LLVMBuildGEP(builder, vp_ptr, &index, 1, "");
|
||||||
|
|
||||||
|
index = LLVMConstInt(LLVMInt32Type(), i+4, 0);
|
||||||
|
trans_i = LLVMBuildGEP(builder, vp_ptr, &index, 1, "");
|
||||||
|
|
||||||
|
scale = vec4f_from_scalar(builder, LLVMBuildLoad(builder, scale_i, ""), "scale");
|
||||||
|
trans = vec4f_from_scalar(builder, LLVMBuildLoad(builder, trans_i, ""), "trans");
|
||||||
|
|
||||||
|
/* divide by w */
|
||||||
|
out = LLVMBuildFMul(builder, out, out3, "");
|
||||||
|
/* mult by scale */
|
||||||
|
out = LLVMBuildFMul(builder, out, scale, "");
|
||||||
|
/* add translation */
|
||||||
|
out = LLVMBuildFAdd(builder, out, trans, "");
|
||||||
|
|
||||||
|
/* store transformed outputs */
|
||||||
|
LLVMBuildStore(builder, out, outputs[0][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns clipmask as 4xi32 bitmask for the 4 vertices
|
||||||
|
*/
|
||||||
|
static LLVMValueRef
|
||||||
|
generate_clipmask(LLVMBuilderRef builder,
|
||||||
|
LLVMValueRef (*outputs)[NUM_CHANNELS],
|
||||||
|
boolean clip_xy,
|
||||||
|
boolean clip_z,
|
||||||
|
boolean clip_user,
|
||||||
|
boolean clip_halfz,
|
||||||
|
unsigned nr,
|
||||||
|
LLVMValueRef context_ptr)
|
||||||
|
{
|
||||||
|
LLVMValueRef mask; /* stores the <4xi32> clipmasks */
|
||||||
|
LLVMValueRef test, temp;
|
||||||
|
LLVMValueRef zero, shift;
|
||||||
|
LLVMValueRef pos_x, pos_y, pos_z, pos_w;
|
||||||
|
LLVMValueRef plane1, planes, plane_ptr, sum;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
struct lp_type f32_type = lp_type_float_vec(32);
|
||||||
|
|
||||||
|
mask = lp_build_const_int_vec(lp_type_int_vec(32), 0);
|
||||||
|
temp = lp_build_const_int_vec(lp_type_int_vec(32), 0);
|
||||||
|
zero = lp_build_const_vec(f32_type, 0); /* 0.0f 0.0f 0.0f 0.0f */
|
||||||
|
shift = lp_build_const_int_vec(lp_type_int_vec(32), 1); /* 1 1 1 1 */
|
||||||
|
|
||||||
|
/* Assuming position stored at output[0] */
|
||||||
|
pos_x = LLVMBuildLoad(builder, outputs[0][0], ""); /*x0 x1 x2 x3*/
|
||||||
|
pos_y = LLVMBuildLoad(builder, outputs[0][1], ""); /*y0 y1 y2 y3*/
|
||||||
|
pos_z = LLVMBuildLoad(builder, outputs[0][2], ""); /*z0 z1 z2 z3*/
|
||||||
|
pos_w = LLVMBuildLoad(builder, outputs[0][3], ""); /*w0 w1 w2 w3*/
|
||||||
|
|
||||||
|
/* Cliptest, for hardwired planes */
|
||||||
|
if (clip_xy){
|
||||||
|
/* plane 1 */
|
||||||
|
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, pos_x , pos_w);
|
||||||
|
temp = shift;
|
||||||
|
test = LLVMBuildAnd(builder, test, temp, "");
|
||||||
|
mask = test;
|
||||||
|
|
||||||
|
/* plane 2 */
|
||||||
|
test = LLVMBuildFAdd(builder, pos_x, pos_w, "");
|
||||||
|
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, test);
|
||||||
|
temp = LLVMBuildShl(builder, temp, shift, "");
|
||||||
|
test = LLVMBuildAnd(builder, test, temp, "");
|
||||||
|
mask = LLVMBuildOr(builder, mask, test, "");
|
||||||
|
|
||||||
|
/* plane 3 */
|
||||||
|
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, pos_y, pos_w);
|
||||||
|
temp = LLVMBuildShl(builder, temp, shift, "");
|
||||||
|
test = LLVMBuildAnd(builder, test, temp, "");
|
||||||
|
mask = LLVMBuildOr(builder, mask, test, "");
|
||||||
|
|
||||||
|
/* plane 4 */
|
||||||
|
test = LLVMBuildFAdd(builder, pos_y, pos_w, "");
|
||||||
|
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, test);
|
||||||
|
temp = LLVMBuildShl(builder, temp, shift, "");
|
||||||
|
test = LLVMBuildAnd(builder, test, temp, "");
|
||||||
|
mask = LLVMBuildOr(builder, mask, test, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clip_z){
|
||||||
|
temp = lp_build_const_int_vec(lp_type_int_vec(32), 16);
|
||||||
|
if (clip_halfz){
|
||||||
|
/* plane 5 */
|
||||||
|
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, pos_z);
|
||||||
|
test = LLVMBuildAnd(builder, test, temp, "");
|
||||||
|
mask = LLVMBuildOr(builder, mask, test, "");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
/* plane 5 */
|
||||||
|
test = LLVMBuildFAdd(builder, pos_z, pos_w, "");
|
||||||
|
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, test);
|
||||||
|
test = LLVMBuildAnd(builder, test, temp, "");
|
||||||
|
mask = LLVMBuildOr(builder, mask, test, "");
|
||||||
|
}
|
||||||
|
/* plane 6 */
|
||||||
|
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, pos_z, pos_w);
|
||||||
|
temp = LLVMBuildShl(builder, temp, shift, "");
|
||||||
|
test = LLVMBuildAnd(builder, test, temp, "");
|
||||||
|
mask = LLVMBuildOr(builder, mask, test, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clip_user){
|
||||||
|
LLVMValueRef planes_ptr = draw_jit_context_planes(builder, context_ptr);
|
||||||
|
LLVMValueRef indices[3];
|
||||||
|
temp = lp_build_const_int_vec(lp_type_int_vec(32), 32);
|
||||||
|
|
||||||
|
/* userclip planes */
|
||||||
|
for (i = 6; i < nr; i++) {
|
||||||
|
indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||||
|
indices[1] = LLVMConstInt(LLVMInt32Type(), i, 0);
|
||||||
|
|
||||||
|
indices[2] = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||||
|
plane_ptr = LLVMBuildGEP(builder, planes_ptr, indices, 3, "");
|
||||||
|
plane1 = LLVMBuildLoad(builder, plane_ptr, "plane_x");
|
||||||
|
planes = vec4f_from_scalar(builder, plane1, "plane4_x");
|
||||||
|
sum = LLVMBuildFMul(builder, planes, pos_x, "");
|
||||||
|
|
||||||
|
indices[2] = LLVMConstInt(LLVMInt32Type(), 1, 0);
|
||||||
|
plane_ptr = LLVMBuildGEP(builder, planes_ptr, indices, 3, "");
|
||||||
|
plane1 = LLVMBuildLoad(builder, plane_ptr, "plane_y");
|
||||||
|
planes = vec4f_from_scalar(builder, plane1, "plane4_y");
|
||||||
|
test = LLVMBuildFMul(builder, planes, pos_y, "");
|
||||||
|
sum = LLVMBuildFAdd(builder, sum, test, "");
|
||||||
|
|
||||||
|
indices[2] = LLVMConstInt(LLVMInt32Type(), 2, 0);
|
||||||
|
plane_ptr = LLVMBuildGEP(builder, planes_ptr, indices, 3, "");
|
||||||
|
plane1 = LLVMBuildLoad(builder, plane_ptr, "plane_z");
|
||||||
|
planes = vec4f_from_scalar(builder, plane1, "plane4_z");
|
||||||
|
test = LLVMBuildFMul(builder, planes, pos_z, "");
|
||||||
|
sum = LLVMBuildFAdd(builder, sum, test, "");
|
||||||
|
|
||||||
|
indices[2] = LLVMConstInt(LLVMInt32Type(), 3, 0);
|
||||||
|
plane_ptr = LLVMBuildGEP(builder, planes_ptr, indices, 3, "");
|
||||||
|
plane1 = LLVMBuildLoad(builder, plane_ptr, "plane_w");
|
||||||
|
planes = vec4f_from_scalar(builder, plane1, "plane4_w");
|
||||||
|
test = LLVMBuildFMul(builder, planes, pos_w, "");
|
||||||
|
sum = LLVMBuildFAdd(builder, sum, test, "");
|
||||||
|
|
||||||
|
test = lp_build_compare(builder, f32_type, PIPE_FUNC_GREATER, zero, sum);
|
||||||
|
temp = LLVMBuildShl(builder, temp, shift, "");
|
||||||
|
test = LLVMBuildAnd(builder, test, temp, "");
|
||||||
|
mask = LLVMBuildOr(builder, mask, test, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns boolean if any clipping has occurred
|
||||||
|
* Used zero/non-zero i32 value to represent boolean
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
clipmask_bool(LLVMBuilderRef builder,
|
||||||
|
LLVMValueRef clipmask,
|
||||||
|
LLVMValueRef ret_ptr)
|
||||||
|
{
|
||||||
|
LLVMValueRef ret = LLVMBuildLoad(builder, ret_ptr, "");
|
||||||
|
LLVMValueRef temp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<4; i++){
|
||||||
|
temp = LLVMBuildExtractElement(builder, clipmask,
|
||||||
|
LLVMConstInt(LLVMInt32Type(), i, 0) , "");
|
||||||
|
ret = LLVMBuildOr(builder, ret, temp, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMBuildStore(builder, ret, ret_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
|
draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
|
||||||
{
|
{
|
||||||
|
|
@ -706,6 +1019,11 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
|
||||||
LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS];
|
LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS];
|
||||||
void *code;
|
void *code;
|
||||||
struct lp_build_sampler_soa *sampler = 0;
|
struct lp_build_sampler_soa *sampler = 0;
|
||||||
|
LLVMValueRef ret, ret_ptr;
|
||||||
|
boolean bypass_viewport = variant->key.bypass_viewport;
|
||||||
|
boolean enable_cliptest = variant->key.clip_xy ||
|
||||||
|
variant->key.clip_z ||
|
||||||
|
variant->key.clip_user;
|
||||||
|
|
||||||
arg_types[0] = llvm->context_ptr_type; /* context */
|
arg_types[0] = llvm->context_ptr_type; /* context */
|
||||||
arg_types[1] = llvm->vertex_header_ptr_type; /* vertex_header */
|
arg_types[1] = llvm->vertex_header_ptr_type; /* vertex_header */
|
||||||
|
|
@ -716,7 +1034,7 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
|
||||||
arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */
|
arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */
|
||||||
arg_types[7] = LLVMInt32Type(); /* instance_id */
|
arg_types[7] = LLVMInt32Type(); /* instance_id */
|
||||||
|
|
||||||
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
|
func_type = LLVMFunctionType(LLVMInt32Type(), arg_types, Elements(arg_types), 0);
|
||||||
|
|
||||||
variant->function = LLVMAddFunction(llvm->module, "draw_llvm_shader", func_type);
|
variant->function = LLVMAddFunction(llvm->module, "draw_llvm_shader", func_type);
|
||||||
LLVMSetFunctionCallConv(variant->function, LLVMCCallConv);
|
LLVMSetFunctionCallConv(variant->function, LLVMCCallConv);
|
||||||
|
|
@ -756,6 +1074,10 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
|
||||||
|
|
||||||
step = LLVMConstInt(LLVMInt32Type(), max_vertices, 0);
|
step = LLVMConstInt(LLVMInt32Type(), max_vertices, 0);
|
||||||
|
|
||||||
|
/* function will return non-zero i32 value if any clipped vertices */
|
||||||
|
ret_ptr = lp_build_alloca(builder, LLVMInt32Type(), "");
|
||||||
|
LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), 0, 0), ret_ptr);
|
||||||
|
|
||||||
/* code generated texture sampling */
|
/* code generated texture sampling */
|
||||||
sampler = draw_llvm_sampler_soa_create(
|
sampler = draw_llvm_sampler_soa_create(
|
||||||
draw_llvm_variant_key_samplers(&variant->key),
|
draw_llvm_variant_key_samplers(&variant->key),
|
||||||
|
|
@ -770,6 +1092,7 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
|
||||||
LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
|
LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
|
||||||
LLVMValueRef aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } };
|
LLVMValueRef aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } };
|
||||||
LLVMValueRef io;
|
LLVMValueRef io;
|
||||||
|
LLVMValueRef clipmask; /* holds the clipmask value */
|
||||||
const LLVMValueRef (*ptr_aos)[NUM_CHANNELS];
|
const LLVMValueRef (*ptr_aos)[NUM_CHANNELS];
|
||||||
|
|
||||||
io_itr = LLVMBuildSub(builder, lp_loop.counter, start, "");
|
io_itr = LLVMBuildSub(builder, lp_loop.counter, start, "");
|
||||||
|
|
@ -806,10 +1129,37 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
|
||||||
context_ptr,
|
context_ptr,
|
||||||
sampler);
|
sampler);
|
||||||
|
|
||||||
convert_to_aos(builder, io, outputs,
|
/* store original positions in clip before further manipulation */
|
||||||
|
store_clip(builder, io, outputs);
|
||||||
|
|
||||||
|
/* do cliptest */
|
||||||
|
if (enable_cliptest){
|
||||||
|
/* allocate clipmask, assign it integer type */
|
||||||
|
clipmask = generate_clipmask(builder, outputs,
|
||||||
|
variant->key.clip_xy,
|
||||||
|
variant->key.clip_z,
|
||||||
|
variant->key.clip_user,
|
||||||
|
variant->key.clip_halfz,
|
||||||
|
variant->key.nr_planes,
|
||||||
|
context_ptr);
|
||||||
|
/* return clipping boolean value for function */
|
||||||
|
clipmask_bool(builder, clipmask, ret_ptr);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
clipmask = lp_build_const_int_vec(lp_type_int_vec(32), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do viewport mapping */
|
||||||
|
if (!bypass_viewport){
|
||||||
|
generate_viewport(llvm, builder, outputs, context_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store clipmask in vertex header and positions in data */
|
||||||
|
convert_to_aos(builder, io, outputs, clipmask,
|
||||||
draw->vs.vertex_shader->info.num_outputs,
|
draw->vs.vertex_shader->info.num_outputs,
|
||||||
max_vertices);
|
max_vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_build_loop_end_cond(builder, end, step, LLVMIntUGE, &lp_loop);
|
lp_build_loop_end_cond(builder, end, step, LLVMIntUGE, &lp_loop);
|
||||||
|
|
||||||
sampler->destroy(sampler);
|
sampler->destroy(sampler);
|
||||||
|
|
@ -819,7 +1169,8 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
|
||||||
lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0);
|
lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LLVMBuildRetVoid(builder);
|
ret = LLVMBuildLoad(builder, ret_ptr,"");
|
||||||
|
LLVMBuildRet(builder, ret);
|
||||||
|
|
||||||
LLVMDisposeBuilder(builder);
|
LLVMDisposeBuilder(builder);
|
||||||
|
|
||||||
|
|
@ -870,6 +1221,11 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
|
||||||
LLVMValueRef fetch_max;
|
LLVMValueRef fetch_max;
|
||||||
void *code;
|
void *code;
|
||||||
struct lp_build_sampler_soa *sampler = 0;
|
struct lp_build_sampler_soa *sampler = 0;
|
||||||
|
LLVMValueRef ret, ret_ptr;
|
||||||
|
boolean bypass_viewport = variant->key.bypass_viewport;
|
||||||
|
boolean enable_cliptest = variant->key.clip_xy ||
|
||||||
|
variant->key.clip_z ||
|
||||||
|
variant->key.clip_user;
|
||||||
|
|
||||||
arg_types[0] = llvm->context_ptr_type; /* context */
|
arg_types[0] = llvm->context_ptr_type; /* context */
|
||||||
arg_types[1] = llvm->vertex_header_ptr_type; /* vertex_header */
|
arg_types[1] = llvm->vertex_header_ptr_type; /* vertex_header */
|
||||||
|
|
@ -880,10 +1236,9 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
|
||||||
arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */
|
arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */
|
||||||
arg_types[7] = LLVMInt32Type(); /* instance_id */
|
arg_types[7] = LLVMInt32Type(); /* instance_id */
|
||||||
|
|
||||||
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
|
func_type = LLVMFunctionType(LLVMInt32Type(), arg_types, Elements(arg_types), 0);
|
||||||
|
|
||||||
variant->function_elts = LLVMAddFunction(llvm->module, "draw_llvm_shader_elts",
|
variant->function_elts = LLVMAddFunction(llvm->module, "draw_llvm_shader_elts", func_type);
|
||||||
func_type);
|
|
||||||
LLVMSetFunctionCallConv(variant->function_elts, LLVMCCallConv);
|
LLVMSetFunctionCallConv(variant->function_elts, LLVMCCallConv);
|
||||||
for(i = 0; i < Elements(arg_types); ++i)
|
for(i = 0; i < Elements(arg_types); ++i)
|
||||||
if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
|
||||||
|
|
@ -929,11 +1284,16 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
|
||||||
LLVMConstInt(LLVMInt32Type(), 1, 0),
|
LLVMConstInt(LLVMInt32Type(), 1, 0),
|
||||||
"fetch_max");
|
"fetch_max");
|
||||||
|
|
||||||
|
/* function returns non-zero i32 value if any clipped vertices */
|
||||||
|
ret_ptr = lp_build_alloca(builder, LLVMInt32Type(), "");
|
||||||
|
LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), 0, 0), ret_ptr);
|
||||||
|
|
||||||
lp_build_loop_begin(builder, LLVMConstInt(LLVMInt32Type(), 0, 0), &lp_loop);
|
lp_build_loop_begin(builder, LLVMConstInt(LLVMInt32Type(), 0, 0), &lp_loop);
|
||||||
{
|
{
|
||||||
LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
|
LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
|
||||||
LLVMValueRef aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } };
|
LLVMValueRef aos_attribs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS] = { { 0 } };
|
||||||
LLVMValueRef io;
|
LLVMValueRef io;
|
||||||
|
LLVMValueRef clipmask; /* holds the clipmask value */
|
||||||
const LLVMValueRef (*ptr_aos)[NUM_CHANNELS];
|
const LLVMValueRef (*ptr_aos)[NUM_CHANNELS];
|
||||||
|
|
||||||
io_itr = lp_loop.counter;
|
io_itr = lp_loop.counter;
|
||||||
|
|
@ -980,10 +1340,40 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
|
||||||
context_ptr,
|
context_ptr,
|
||||||
sampler);
|
sampler);
|
||||||
|
|
||||||
convert_to_aos(builder, io, outputs,
|
/* store original positions in clip before further manipulation */
|
||||||
|
store_clip(builder, io, outputs);
|
||||||
|
|
||||||
|
/* do cliptest */
|
||||||
|
if (enable_cliptest){
|
||||||
|
/* allocate clipmask, assign it integer type */
|
||||||
|
clipmask = generate_clipmask(builder, outputs,
|
||||||
|
variant->key.clip_xy,
|
||||||
|
variant->key.clip_z,
|
||||||
|
variant->key.clip_user,
|
||||||
|
variant->key.clip_halfz,
|
||||||
|
variant->key.nr_planes,
|
||||||
|
context_ptr);
|
||||||
|
/* return clipping boolean value for function */
|
||||||
|
clipmask_bool(builder, clipmask, ret_ptr);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
clipmask = lp_build_const_int_vec(lp_type_int_vec(32), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do viewport mapping */
|
||||||
|
if (!bypass_viewport){
|
||||||
|
generate_viewport(llvm, builder, outputs, context_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store clipmask in vertex header,
|
||||||
|
* original positions in clip
|
||||||
|
* and transformed positions in data
|
||||||
|
*/
|
||||||
|
convert_to_aos(builder, io, outputs, clipmask,
|
||||||
draw->vs.vertex_shader->info.num_outputs,
|
draw->vs.vertex_shader->info.num_outputs,
|
||||||
max_vertices);
|
max_vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_build_loop_end_cond(builder, fetch_count, step, LLVMIntUGE, &lp_loop);
|
lp_build_loop_end_cond(builder, fetch_count, step, LLVMIntUGE, &lp_loop);
|
||||||
|
|
||||||
sampler->destroy(sampler);
|
sampler->destroy(sampler);
|
||||||
|
|
@ -993,7 +1383,8 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
|
||||||
lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0);
|
lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LLVMBuildRetVoid(builder);
|
ret = LLVMBuildLoad(builder, ret_ptr,"");
|
||||||
|
LLVMBuildRet(builder, ret);
|
||||||
|
|
||||||
LLVMDisposeBuilder(builder);
|
LLVMDisposeBuilder(builder);
|
||||||
|
|
||||||
|
|
@ -1038,6 +1429,16 @@ draw_llvm_make_variant_key(struct draw_llvm *llvm, char *store)
|
||||||
*/
|
*/
|
||||||
key->nr_vertex_elements = llvm->draw->pt.nr_vertex_elements;
|
key->nr_vertex_elements = llvm->draw->pt.nr_vertex_elements;
|
||||||
|
|
||||||
|
/* will have to rig this up properly later */
|
||||||
|
key->clip_xy = llvm->draw->clip_xy;
|
||||||
|
key->clip_z = llvm->draw->clip_z;
|
||||||
|
key->clip_user = llvm->draw->clip_user;
|
||||||
|
key->bypass_viewport = llvm->draw->identity_viewport;
|
||||||
|
key->clip_halfz = !llvm->draw->rasterizer->gl_rasterization_rules;
|
||||||
|
key->need_edgeflags = (llvm->draw->vs.edgeflag_output ? TRUE : FALSE);
|
||||||
|
key->nr_planes = llvm->draw->nr_planes;
|
||||||
|
key->pad = 0;
|
||||||
|
|
||||||
/* All variants of this shader will have the same value for
|
/* All variants of this shader will have the same value for
|
||||||
* nr_samplers. Not yet trying to compact away holes in the
|
* nr_samplers. Not yet trying to compact away holes in the
|
||||||
* sampler array.
|
* sampler array.
|
||||||
|
|
@ -1066,9 +1467,9 @@ draw_llvm_set_mapped_texture(struct draw_context *draw,
|
||||||
unsigned sampler_idx,
|
unsigned sampler_idx,
|
||||||
uint32_t width, uint32_t height, uint32_t depth,
|
uint32_t width, uint32_t height, uint32_t depth,
|
||||||
uint32_t last_level,
|
uint32_t last_level,
|
||||||
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
|
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
|
||||||
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
|
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
|
||||||
const void *data[DRAW_MAX_TEXTURE_LEVELS])
|
const void *data[PIPE_MAX_TEXTURE_LEVELS])
|
||||||
{
|
{
|
||||||
unsigned j;
|
unsigned j;
|
||||||
struct draw_jit_texture *jit_tex;
|
struct draw_jit_texture *jit_tex;
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@
|
||||||
#include <llvm-c/Target.h>
|
#include <llvm-c/Target.h>
|
||||||
#include <llvm-c/ExecutionEngine.h>
|
#include <llvm-c/ExecutionEngine.h>
|
||||||
|
|
||||||
#define DRAW_MAX_TEXTURE_LEVELS 13 /* 4K x 4K for now */
|
|
||||||
|
|
||||||
struct draw_llvm;
|
struct draw_llvm;
|
||||||
struct llvm_vertex_shader;
|
struct llvm_vertex_shader;
|
||||||
|
|
@ -52,9 +51,9 @@ struct draw_jit_texture
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
uint32_t depth;
|
uint32_t depth;
|
||||||
uint32_t last_level;
|
uint32_t last_level;
|
||||||
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS];
|
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS];
|
||||||
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS];
|
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS];
|
||||||
const void *data[DRAW_MAX_TEXTURE_LEVELS];
|
const void *data[PIPE_MAX_TEXTURE_LEVELS];
|
||||||
float min_lod;
|
float min_lod;
|
||||||
float max_lod;
|
float max_lod;
|
||||||
float lod_bias;
|
float lod_bias;
|
||||||
|
|
@ -97,7 +96,8 @@ struct draw_jit_context
|
||||||
{
|
{
|
||||||
const float *vs_constants;
|
const float *vs_constants;
|
||||||
const float *gs_constants;
|
const float *gs_constants;
|
||||||
|
float (*planes) [12][4];
|
||||||
|
float *viewport;
|
||||||
|
|
||||||
struct draw_jit_texture textures[PIPE_MAX_VERTEX_SAMPLERS];
|
struct draw_jit_texture textures[PIPE_MAX_VERTEX_SAMPLERS];
|
||||||
};
|
};
|
||||||
|
|
@ -109,18 +109,22 @@ struct draw_jit_context
|
||||||
#define draw_jit_context_gs_constants(_builder, _ptr) \
|
#define draw_jit_context_gs_constants(_builder, _ptr) \
|
||||||
lp_build_struct_get(_builder, _ptr, 1, "gs_constants")
|
lp_build_struct_get(_builder, _ptr, 1, "gs_constants")
|
||||||
|
|
||||||
#define DRAW_JIT_CTX_TEXTURES 2
|
#define draw_jit_context_planes(_builder, _ptr) \
|
||||||
|
lp_build_struct_get(_builder, _ptr, 2, "planes")
|
||||||
|
|
||||||
|
#define draw_jit_context_viewport(_builder, _ptr) \
|
||||||
|
lp_build_struct_get(_builder, _ptr, 3, "viewport")
|
||||||
|
|
||||||
|
#define DRAW_JIT_CTX_TEXTURES 4
|
||||||
|
|
||||||
#define draw_jit_context_textures(_builder, _ptr) \
|
#define draw_jit_context_textures(_builder, _ptr) \
|
||||||
lp_build_struct_get_ptr(_builder, _ptr, DRAW_JIT_CTX_TEXTURES, "textures")
|
lp_build_struct_get_ptr(_builder, _ptr, DRAW_JIT_CTX_TEXTURES, "textures")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define draw_jit_header_id(_builder, _ptr) \
|
#define draw_jit_header_id(_builder, _ptr) \
|
||||||
lp_build_struct_get_ptr(_builder, _ptr, 0, "id")
|
lp_build_struct_get_ptr(_builder, _ptr, 0, "id")
|
||||||
|
|
||||||
#define draw_jit_header_clip(_builder, _ptr) \
|
#define draw_jit_header_clip(_builder, _ptr) \
|
||||||
lp_build_struct_get(_builder, _ptr, 1, "clip")
|
lp_build_struct_get_ptr(_builder, _ptr, 1, "clip")
|
||||||
|
|
||||||
#define draw_jit_header_data(_builder, _ptr) \
|
#define draw_jit_header_data(_builder, _ptr) \
|
||||||
lp_build_struct_get_ptr(_builder, _ptr, 2, "data")
|
lp_build_struct_get_ptr(_builder, _ptr, 2, "data")
|
||||||
|
|
@ -136,7 +140,7 @@ struct draw_jit_context
|
||||||
lp_build_struct_get(_builder, _ptr, 2, "buffer_offset")
|
lp_build_struct_get(_builder, _ptr, 2, "buffer_offset")
|
||||||
|
|
||||||
|
|
||||||
typedef void
|
typedef int
|
||||||
(*draw_jit_vert_func)(struct draw_jit_context *context,
|
(*draw_jit_vert_func)(struct draw_jit_context *context,
|
||||||
struct vertex_header *io,
|
struct vertex_header *io,
|
||||||
const char *vbuffers[PIPE_MAX_ATTRIBS],
|
const char *vbuffers[PIPE_MAX_ATTRIBS],
|
||||||
|
|
@ -147,7 +151,7 @@ typedef void
|
||||||
unsigned instance_id);
|
unsigned instance_id);
|
||||||
|
|
||||||
|
|
||||||
typedef void
|
typedef int
|
||||||
(*draw_jit_vert_func_elts)(struct draw_jit_context *context,
|
(*draw_jit_vert_func_elts)(struct draw_jit_context *context,
|
||||||
struct vertex_header *io,
|
struct vertex_header *io,
|
||||||
const char *vbuffers[PIPE_MAX_ATTRIBS],
|
const char *vbuffers[PIPE_MAX_ATTRIBS],
|
||||||
|
|
@ -159,8 +163,16 @@ typedef void
|
||||||
|
|
||||||
struct draw_llvm_variant_key
|
struct draw_llvm_variant_key
|
||||||
{
|
{
|
||||||
unsigned nr_vertex_elements:16;
|
unsigned nr_vertex_elements:8;
|
||||||
unsigned nr_samplers:16;
|
unsigned nr_samplers:8;
|
||||||
|
unsigned clip_xy:1;
|
||||||
|
unsigned clip_z:1;
|
||||||
|
unsigned clip_user:1;
|
||||||
|
unsigned clip_halfz:1;
|
||||||
|
unsigned bypass_viewport:1;
|
||||||
|
unsigned need_edgeflags:1;
|
||||||
|
unsigned nr_planes:4;
|
||||||
|
unsigned pad:6;
|
||||||
|
|
||||||
/* Variable number of vertex elements:
|
/* Variable number of vertex elements:
|
||||||
*/
|
*/
|
||||||
|
|
@ -290,8 +302,8 @@ draw_llvm_set_mapped_texture(struct draw_context *draw,
|
||||||
unsigned sampler_idx,
|
unsigned sampler_idx,
|
||||||
uint32_t width, uint32_t height, uint32_t depth,
|
uint32_t width, uint32_t height, uint32_t depth,
|
||||||
uint32_t last_level,
|
uint32_t last_level,
|
||||||
uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
|
uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS],
|
||||||
uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
|
uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS],
|
||||||
const void *data[DRAW_MAX_TEXTURE_LEVELS]);
|
const void *data[PIPE_MAX_TEXTURE_LEVELS]);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,9 @@ struct draw_context
|
||||||
unsigned vs_constants_size[PIPE_MAX_CONSTANT_BUFFERS];
|
unsigned vs_constants_size[PIPE_MAX_CONSTANT_BUFFERS];
|
||||||
const void *gs_constants[PIPE_MAX_CONSTANT_BUFFERS];
|
const void *gs_constants[PIPE_MAX_CONSTANT_BUFFERS];
|
||||||
unsigned gs_constants_size[PIPE_MAX_CONSTANT_BUFFERS];
|
unsigned gs_constants_size[PIPE_MAX_CONSTANT_BUFFERS];
|
||||||
|
|
||||||
|
/* pointer to planes */
|
||||||
|
float (*planes)[12][4];
|
||||||
} user;
|
} user;
|
||||||
|
|
||||||
boolean test_fse; /* enable FSE even though its not correct (eg for softpipe) */
|
boolean test_fse; /* enable FSE even though its not correct (eg for softpipe) */
|
||||||
|
|
|
||||||
|
|
@ -287,6 +287,84 @@ draw_print_arrays(struct draw_context *draw, uint prim, int start, uint count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Helper code for below */
|
||||||
|
#define PRIM_RESTART_LOOP(elements) \
|
||||||
|
do { \
|
||||||
|
for (i = start; i < end; i++) { \
|
||||||
|
if (elements[i] == info->restart_index) { \
|
||||||
|
if (cur_count > 0) { \
|
||||||
|
/* draw elts up to prev pos */ \
|
||||||
|
draw_pt_arrays(draw, prim, cur_start, cur_count); \
|
||||||
|
} \
|
||||||
|
/* begin new prim at next elt */ \
|
||||||
|
cur_start = i + 1; \
|
||||||
|
cur_count = 0; \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
cur_count++; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
if (cur_count > 0) { \
|
||||||
|
draw_pt_arrays(draw, prim, cur_start, cur_count); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For drawing prims with primitive restart enabled.
|
||||||
|
* Scan for restart indexes and draw the runs of elements/vertices between
|
||||||
|
* the restarts.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
draw_pt_arrays_restart(struct draw_context *draw,
|
||||||
|
const struct pipe_draw_info *info)
|
||||||
|
{
|
||||||
|
const unsigned prim = info->mode;
|
||||||
|
const unsigned start = info->start;
|
||||||
|
const unsigned count = info->count;
|
||||||
|
const unsigned end = start + count;
|
||||||
|
unsigned i, cur_start, cur_count;
|
||||||
|
|
||||||
|
assert(info->primitive_restart);
|
||||||
|
|
||||||
|
if (draw->pt.user.elts) {
|
||||||
|
/* indexed prims (draw_elements) */
|
||||||
|
cur_start = start;
|
||||||
|
cur_count = 0;
|
||||||
|
|
||||||
|
switch (draw->pt.user.eltSize) {
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
const ubyte *elt_ub = (const ubyte *) draw->pt.user.elts;
|
||||||
|
PRIM_RESTART_LOOP(elt_ub);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
const ushort *elt_us = (const ushort *) draw->pt.user.elts;
|
||||||
|
PRIM_RESTART_LOOP(elt_us);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
const uint *elt_ui = (const uint *) draw->pt.user.elts;
|
||||||
|
PRIM_RESTART_LOOP(elt_ui);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "bad eltSize in draw_arrays()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Non-indexed prims (draw_arrays).
|
||||||
|
* Primitive restart should have been handled in the state tracker.
|
||||||
|
*/
|
||||||
|
draw_pt_arrays(draw, prim, start, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Non-instanced drawing.
|
* Non-instanced drawing.
|
||||||
* \sa draw_arrays_instanced
|
* \sa draw_arrays_instanced
|
||||||
|
|
@ -395,6 +473,12 @@ draw_vbo(struct draw_context *draw,
|
||||||
|
|
||||||
for (instance = 0; instance < info->instance_count; instance++) {
|
for (instance = 0; instance < info->instance_count; instance++) {
|
||||||
draw->instance_id = instance + info->start_instance;
|
draw->instance_id = instance + info->start_instance;
|
||||||
|
|
||||||
|
if (info->primitive_restart) {
|
||||||
|
draw_pt_arrays_restart(draw, info);
|
||||||
|
}
|
||||||
|
else {
|
||||||
draw_pt_arrays(draw, info->mode, info->start, info->count);
|
draw_pt_arrays(draw, info->mode, info->start, info->count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,11 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
|
||||||
draw->pt.user.vs_constants[0];
|
draw->pt.user.vs_constants[0];
|
||||||
fpme->llvm->jit_context.gs_constants =
|
fpme->llvm->jit_context.gs_constants =
|
||||||
draw->pt.user.gs_constants[0];
|
draw->pt.user.gs_constants[0];
|
||||||
|
fpme->llvm->jit_context.planes =
|
||||||
|
(float (*) [12][4]) draw->pt.user.planes[0];
|
||||||
|
fpme->llvm->jit_context.viewport =
|
||||||
|
(float *)draw->viewport.scale;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -217,6 +222,7 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
|
||||||
struct draw_vertex_info gs_vert_info;
|
struct draw_vertex_info gs_vert_info;
|
||||||
struct draw_vertex_info *vert_info;
|
struct draw_vertex_info *vert_info;
|
||||||
unsigned opt = fpme->opt;
|
unsigned opt = fpme->opt;
|
||||||
|
unsigned clipped = 0;
|
||||||
|
|
||||||
llvm_vert_info.count = fetch_info->count;
|
llvm_vert_info.count = fetch_info->count;
|
||||||
llvm_vert_info.vertex_size = fpme->vertex_size;
|
llvm_vert_info.vertex_size = fpme->vertex_size;
|
||||||
|
|
@ -230,7 +236,7 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fetch_info->linear)
|
if (fetch_info->linear)
|
||||||
fpme->current_variant->jit_func( &fpme->llvm->jit_context,
|
clipped = fpme->current_variant->jit_func( &fpme->llvm->jit_context,
|
||||||
llvm_vert_info.verts,
|
llvm_vert_info.verts,
|
||||||
(const char **)draw->pt.user.vbuffer,
|
(const char **)draw->pt.user.vbuffer,
|
||||||
fetch_info->start,
|
fetch_info->start,
|
||||||
|
|
@ -239,7 +245,7 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
|
||||||
draw->pt.vertex_buffer,
|
draw->pt.vertex_buffer,
|
||||||
draw->instance_id);
|
draw->instance_id);
|
||||||
else
|
else
|
||||||
fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context,
|
clipped = fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context,
|
||||||
llvm_vert_info.verts,
|
llvm_vert_info.verts,
|
||||||
(const char **)draw->pt.user.vbuffer,
|
(const char **)draw->pt.user.vbuffer,
|
||||||
fetch_info->elts,
|
fetch_info->elts,
|
||||||
|
|
@ -266,6 +272,9 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
|
||||||
FREE(vert_info->verts);
|
FREE(vert_info->verts);
|
||||||
vert_info = &gs_vert_info;
|
vert_info = &gs_vert_info;
|
||||||
prim_info = &gs_prim_info;
|
prim_info = &gs_prim_info;
|
||||||
|
|
||||||
|
clipped = draw_pt_post_vs_run( fpme->post_vs, vert_info );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stream output needs to be done before clipping */
|
/* stream output needs to be done before clipping */
|
||||||
|
|
@ -273,11 +282,11 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle,
|
||||||
vert_info,
|
vert_info,
|
||||||
prim_info );
|
prim_info );
|
||||||
|
|
||||||
if (draw_pt_post_vs_run( fpme->post_vs, vert_info )) {
|
if (clipped) {
|
||||||
opt |= PT_PIPELINE;
|
opt |= PT_PIPELINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do we need to run the pipeline?
|
/* Do we need to run the pipeline? Now will come here if clipped
|
||||||
*/
|
*/
|
||||||
if (opt & PT_PIPELINE) {
|
if (opt & PT_PIPELINE) {
|
||||||
pipeline( fpme,
|
pipeline( fpme,
|
||||||
|
|
|
||||||
|
|
@ -983,6 +983,12 @@ enum lp_build_round_sse41_mode
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for SSE4.1's ROUNDxx instructions.
|
||||||
|
*
|
||||||
|
* NOTE: In the SSE4.1's nearest mode, if two values are equally close, the
|
||||||
|
* result is the even value. That is, rounding 2.5 will be 2.0, and not 3.0.
|
||||||
|
*/
|
||||||
static INLINE LLVMValueRef
|
static INLINE LLVMValueRef
|
||||||
lp_build_round_sse41(struct lp_build_context *bld,
|
lp_build_round_sse41(struct lp_build_context *bld,
|
||||||
LLVMValueRef a,
|
LLVMValueRef a,
|
||||||
|
|
@ -1053,10 +1059,58 @@ lp_build_round_sse41(struct lp_build_context *bld,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static INLINE LLVMValueRef
|
||||||
|
lp_build_iround_nearest_sse2(struct lp_build_context *bld,
|
||||||
|
LLVMValueRef a)
|
||||||
|
{
|
||||||
|
const struct lp_type type = bld->type;
|
||||||
|
LLVMTypeRef i32t = LLVMInt32Type();
|
||||||
|
LLVMTypeRef ret_type = lp_build_int_vec_type(type);
|
||||||
|
const char *intrinsic;
|
||||||
|
LLVMValueRef res;
|
||||||
|
|
||||||
|
assert(type.floating);
|
||||||
|
/* using the double precision conversions is a bit more complicated */
|
||||||
|
assert(type.width == 32);
|
||||||
|
|
||||||
|
assert(lp_check_value(type, a));
|
||||||
|
assert(util_cpu_caps.has_sse2);
|
||||||
|
|
||||||
|
/* This is relying on MXCSR rounding mode, which should always be nearest. */
|
||||||
|
if (type.length == 1) {
|
||||||
|
LLVMTypeRef vec_type;
|
||||||
|
LLVMValueRef undef;
|
||||||
|
LLVMValueRef arg;
|
||||||
|
LLVMValueRef index0 = LLVMConstInt(i32t, 0, 0);
|
||||||
|
|
||||||
|
vec_type = LLVMVectorType(bld->elem_type, 4);
|
||||||
|
|
||||||
|
intrinsic = "llvm.x86.sse.cvtss2si";
|
||||||
|
|
||||||
|
undef = LLVMGetUndef(vec_type);
|
||||||
|
|
||||||
|
arg = LLVMBuildInsertElement(bld->builder, undef, a, index0, "");
|
||||||
|
|
||||||
|
res = lp_build_intrinsic_unary(bld->builder, intrinsic,
|
||||||
|
ret_type, arg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(type.width*type.length == 128);
|
||||||
|
|
||||||
|
intrinsic = "llvm.x86.sse2.cvtps2dq";
|
||||||
|
|
||||||
|
res = lp_build_intrinsic_unary(bld->builder, intrinsic,
|
||||||
|
ret_type, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the integer part of a float (vector) value. The returned value is
|
* Return the integer part of a float (vector) value (== round toward zero).
|
||||||
* a float (vector).
|
* The returned value is a float (vector).
|
||||||
* Ex: trunc(-1.5) = 1.0
|
* Ex: trunc(-1.5) = -1.0
|
||||||
*/
|
*/
|
||||||
LLVMValueRef
|
LLVMValueRef
|
||||||
lp_build_trunc(struct lp_build_context *bld,
|
lp_build_trunc(struct lp_build_context *bld,
|
||||||
|
|
@ -1181,9 +1235,9 @@ lp_build_fract(struct lp_build_context *bld,
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the integer part of a float (vector) value. The returned value is
|
* Return the integer part of a float (vector) value (== round toward zero).
|
||||||
* an integer (vector).
|
* The returned value is an integer (vector).
|
||||||
* Ex: itrunc(-1.5) = 1
|
* Ex: itrunc(-1.5) = -1
|
||||||
*/
|
*/
|
||||||
LLVMValueRef
|
LLVMValueRef
|
||||||
lp_build_itrunc(struct lp_build_context *bld,
|
lp_build_itrunc(struct lp_build_context *bld,
|
||||||
|
|
@ -1217,7 +1271,11 @@ lp_build_iround(struct lp_build_context *bld,
|
||||||
|
|
||||||
assert(lp_check_value(type, a));
|
assert(lp_check_value(type, a));
|
||||||
|
|
||||||
if (util_cpu_caps.has_sse4_1 &&
|
if (util_cpu_caps.has_sse2 &&
|
||||||
|
((type.width == 32) && (type.length == 1 || type.length == 4))) {
|
||||||
|
return lp_build_iround_nearest_sse2(bld, a);
|
||||||
|
}
|
||||||
|
else if (util_cpu_caps.has_sse4_1 &&
|
||||||
(type.length == 1 || type.width*type.length == 128)) {
|
(type.length == 1 || type.width*type.length == 128)) {
|
||||||
res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_NEAREST);
|
res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_NEAREST);
|
||||||
}
|
}
|
||||||
|
|
@ -1371,8 +1429,6 @@ lp_build_ifloor_fract(struct lp_build_context *bld,
|
||||||
LLVMValueRef *out_ipart,
|
LLVMValueRef *out_ipart,
|
||||||
LLVMValueRef *out_fpart)
|
LLVMValueRef *out_fpart)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
const struct lp_type type = bld->type;
|
const struct lp_type type = bld->type;
|
||||||
LLVMValueRef ipart;
|
LLVMValueRef ipart;
|
||||||
|
|
||||||
|
|
@ -2209,6 +2265,71 @@ lp_build_exp2(struct lp_build_context *bld,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the exponent of a IEEE-754 floating point value.
|
||||||
|
*
|
||||||
|
* Optionally apply an integer bias.
|
||||||
|
*
|
||||||
|
* Result is an integer value with
|
||||||
|
*
|
||||||
|
* ifloor(log2(x)) + bias
|
||||||
|
*/
|
||||||
|
LLVMValueRef
|
||||||
|
lp_build_extract_exponent(struct lp_build_context *bld,
|
||||||
|
LLVMValueRef x,
|
||||||
|
int bias)
|
||||||
|
{
|
||||||
|
const struct lp_type type = bld->type;
|
||||||
|
unsigned mantissa = lp_mantissa(type);
|
||||||
|
LLVMValueRef res;
|
||||||
|
|
||||||
|
assert(type.floating);
|
||||||
|
|
||||||
|
assert(lp_check_value(bld->type, x));
|
||||||
|
|
||||||
|
x = LLVMBuildBitCast(bld->builder, x, bld->int_vec_type, "");
|
||||||
|
|
||||||
|
res = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
|
||||||
|
res = LLVMBuildAnd(bld->builder, res, lp_build_const_int_vec(type, 255), "");
|
||||||
|
res = LLVMBuildSub(bld->builder, res, lp_build_const_int_vec(type, 127 - bias), "");
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the mantissa of the a floating.
|
||||||
|
*
|
||||||
|
* Result is a floating point value with
|
||||||
|
*
|
||||||
|
* x / floor(log2(x))
|
||||||
|
*/
|
||||||
|
LLVMValueRef
|
||||||
|
lp_build_extract_mantissa(struct lp_build_context *bld,
|
||||||
|
LLVMValueRef x)
|
||||||
|
{
|
||||||
|
const struct lp_type type = bld->type;
|
||||||
|
unsigned mantissa = lp_mantissa(type);
|
||||||
|
LLVMValueRef mantmask = lp_build_const_int_vec(type, (1ULL << mantissa) - 1);
|
||||||
|
LLVMValueRef one = LLVMConstBitCast(bld->one, bld->int_vec_type);
|
||||||
|
LLVMValueRef res;
|
||||||
|
|
||||||
|
assert(lp_check_value(bld->type, x));
|
||||||
|
|
||||||
|
assert(type.floating);
|
||||||
|
|
||||||
|
x = LLVMBuildBitCast(bld->builder, x, bld->int_vec_type, "");
|
||||||
|
|
||||||
|
/* res = x / 2**ipart */
|
||||||
|
res = LLVMBuildAnd(bld->builder, x, mantmask, "");
|
||||||
|
res = LLVMBuildOr(bld->builder, res, one, "");
|
||||||
|
res = LLVMBuildBitCast(bld->builder, res, bld->vec_type, "");
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimax polynomial fit of log2(x)/(x - 1), for x in range [1, 2[
|
* Minimax polynomial fit of log2(x)/(x - 1), for x in range [1, 2[
|
||||||
* These coefficients can be generate with
|
* These coefficients can be generate with
|
||||||
|
|
@ -2333,7 +2454,10 @@ lp_build_log2(struct lp_build_context *bld,
|
||||||
/**
|
/**
|
||||||
* Faster (and less accurate) log2.
|
* Faster (and less accurate) log2.
|
||||||
*
|
*
|
||||||
* log2(x) = floor(log2(x)) + frac(x)
|
* log2(x) = floor(log2(x)) - 1 + x / 2**floor(log2(x))
|
||||||
|
*
|
||||||
|
* Piece-wise linear approximation, with exact results when x is a
|
||||||
|
* power of two.
|
||||||
*
|
*
|
||||||
* See http://www.flipcode.com/archives/Fast_log_Function.shtml
|
* See http://www.flipcode.com/archives/Fast_log_Function.shtml
|
||||||
*/
|
*/
|
||||||
|
|
@ -2341,35 +2465,21 @@ LLVMValueRef
|
||||||
lp_build_fast_log2(struct lp_build_context *bld,
|
lp_build_fast_log2(struct lp_build_context *bld,
|
||||||
LLVMValueRef x)
|
LLVMValueRef x)
|
||||||
{
|
{
|
||||||
const struct lp_type type = bld->type;
|
|
||||||
LLVMTypeRef vec_type = bld->vec_type;
|
|
||||||
LLVMTypeRef int_vec_type = bld->int_vec_type;
|
|
||||||
|
|
||||||
unsigned mantissa = lp_mantissa(type);
|
|
||||||
LLVMValueRef mantmask = lp_build_const_int_vec(type, (1ULL << mantissa) - 1);
|
|
||||||
LLVMValueRef one = LLVMConstBitCast(bld->one, int_vec_type);
|
|
||||||
|
|
||||||
LLVMValueRef ipart;
|
LLVMValueRef ipart;
|
||||||
LLVMValueRef fpart;
|
LLVMValueRef fpart;
|
||||||
|
|
||||||
assert(lp_check_value(bld->type, x));
|
assert(lp_check_value(bld->type, x));
|
||||||
|
|
||||||
assert(type.floating);
|
assert(bld->type.floating);
|
||||||
|
|
||||||
x = LLVMBuildBitCast(bld->builder, x, int_vec_type, "");
|
|
||||||
|
|
||||||
/* ipart = floor(log2(x)) - 1 */
|
/* ipart = floor(log2(x)) - 1 */
|
||||||
ipart = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
|
ipart = lp_build_extract_exponent(bld, x, -1);
|
||||||
ipart = LLVMBuildAnd(bld->builder, ipart, lp_build_const_int_vec(type, 255), "");
|
ipart = LLVMBuildSIToFP(bld->builder, ipart, bld->vec_type, "");
|
||||||
ipart = LLVMBuildSub(bld->builder, ipart, lp_build_const_int_vec(type, 128), "");
|
|
||||||
ipart = LLVMBuildSIToFP(bld->builder, ipart, vec_type, "");
|
|
||||||
|
|
||||||
/* fpart = 1.0 + frac(x) */
|
/* fpart = x / 2**ipart */
|
||||||
fpart = LLVMBuildAnd(bld->builder, x, mantmask, "");
|
fpart = lp_build_extract_mantissa(bld, x);
|
||||||
fpart = LLVMBuildOr(bld->builder, fpart, one, "");
|
|
||||||
fpart = LLVMBuildBitCast(bld->builder, fpart, vec_type, "");
|
|
||||||
|
|
||||||
/* floor(log2(x)) + frac(x) */
|
/* ipart + fpart */
|
||||||
return LLVMBuildFAdd(bld->builder, ipart, fpart, "");
|
return LLVMBuildFAdd(bld->builder, ipart, fpart, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2383,27 +2493,18 @@ LLVMValueRef
|
||||||
lp_build_ilog2(struct lp_build_context *bld,
|
lp_build_ilog2(struct lp_build_context *bld,
|
||||||
LLVMValueRef x)
|
LLVMValueRef x)
|
||||||
{
|
{
|
||||||
const struct lp_type type = bld->type;
|
LLVMValueRef sqrt2 = lp_build_const_vec(bld->type, M_SQRT2);
|
||||||
LLVMTypeRef int_vec_type = bld->int_vec_type;
|
|
||||||
|
|
||||||
unsigned mantissa = lp_mantissa(type);
|
|
||||||
LLVMValueRef sqrt2 = lp_build_const_vec(type, 1.4142135623730951);
|
|
||||||
|
|
||||||
LLVMValueRef ipart;
|
LLVMValueRef ipart;
|
||||||
|
|
||||||
assert(lp_check_value(bld->type, x));
|
assert(bld->type.floating);
|
||||||
|
|
||||||
assert(type.floating);
|
assert(lp_check_value(bld->type, x));
|
||||||
|
|
||||||
/* x * 2^(0.5) i.e., add 0.5 to the log2(x) */
|
/* x * 2^(0.5) i.e., add 0.5 to the log2(x) */
|
||||||
x = LLVMBuildFMul(bld->builder, x, sqrt2, "");
|
x = LLVMBuildFMul(bld->builder, x, sqrt2, "");
|
||||||
|
|
||||||
x = LLVMBuildBitCast(bld->builder, x, int_vec_type, "");
|
|
||||||
|
|
||||||
/* ipart = floor(log2(x) + 0.5) */
|
/* ipart = floor(log2(x) + 0.5) */
|
||||||
ipart = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
|
ipart = lp_build_extract_exponent(bld, x, 0);
|
||||||
ipart = LLVMBuildAnd(bld->builder, ipart, lp_build_const_int_vec(type, 255), "");
|
|
||||||
ipart = LLVMBuildSub(bld->builder, ipart, lp_build_const_int_vec(type, 127), "");
|
|
||||||
|
|
||||||
return ipart;
|
return ipart;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,15 @@ LLVMValueRef
|
||||||
lp_build_exp2(struct lp_build_context *bld,
|
lp_build_exp2(struct lp_build_context *bld,
|
||||||
LLVMValueRef a);
|
LLVMValueRef a);
|
||||||
|
|
||||||
|
LLVMValueRef
|
||||||
|
lp_build_extract_exponent(struct lp_build_context *bld,
|
||||||
|
LLVMValueRef x,
|
||||||
|
int bias);
|
||||||
|
|
||||||
|
LLVMValueRef
|
||||||
|
lp_build_extract_mantissa(struct lp_build_context *bld,
|
||||||
|
LLVMValueRef x);
|
||||||
|
|
||||||
LLVMValueRef
|
LLVMValueRef
|
||||||
lp_build_log2(struct lp_build_context *bld,
|
lp_build_log2(struct lp_build_context *bld,
|
||||||
LLVMValueRef a);
|
LLVMValueRef a);
|
||||||
|
|
@ -226,7 +235,6 @@ LLVMValueRef
|
||||||
lp_build_ilog2(struct lp_build_context *bld,
|
lp_build_ilog2(struct lp_build_context *bld,
|
||||||
LLVMValueRef x);
|
LLVMValueRef x);
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_exp2_approx(struct lp_build_context *bld,
|
lp_build_exp2_approx(struct lp_build_context *bld,
|
||||||
LLVMValueRef x,
|
LLVMValueRef x,
|
||||||
|
|
|
||||||
|
|
@ -97,58 +97,104 @@ lp_build_clamped_float_to_unsigned_norm(LLVMBuilderRef builder,
|
||||||
LLVMTypeRef int_vec_type = lp_build_int_vec_type(src_type);
|
LLVMTypeRef int_vec_type = lp_build_int_vec_type(src_type);
|
||||||
LLVMValueRef res;
|
LLVMValueRef res;
|
||||||
unsigned mantissa;
|
unsigned mantissa;
|
||||||
unsigned n;
|
|
||||||
|
assert(src_type.floating);
|
||||||
|
assert(dst_width <= src_type.width);
|
||||||
|
src_type.sign = FALSE;
|
||||||
|
|
||||||
|
mantissa = lp_mantissa(src_type);
|
||||||
|
|
||||||
|
if (dst_width <= mantissa) {
|
||||||
|
/*
|
||||||
|
* Apply magic coefficients that will make the desired result to appear
|
||||||
|
* in the lowest significant bits of the mantissa, with correct rounding.
|
||||||
|
*
|
||||||
|
* This only works if the destination width fits in the mantissa.
|
||||||
|
*/
|
||||||
|
|
||||||
unsigned long long ubound;
|
unsigned long long ubound;
|
||||||
unsigned long long mask;
|
unsigned long long mask;
|
||||||
double scale;
|
double scale;
|
||||||
double bias;
|
double bias;
|
||||||
|
|
||||||
assert(src_type.floating);
|
ubound = (1ULL << dst_width);
|
||||||
|
|
||||||
mantissa = lp_mantissa(src_type);
|
|
||||||
|
|
||||||
/* We cannot carry more bits than the mantissa */
|
|
||||||
n = MIN2(mantissa, dst_width);
|
|
||||||
|
|
||||||
/* This magic coefficients will make the desired result to appear in the
|
|
||||||
* lowest significant bits of the mantissa.
|
|
||||||
*/
|
|
||||||
ubound = ((unsigned long long)1 << n);
|
|
||||||
mask = ubound - 1;
|
mask = ubound - 1;
|
||||||
scale = (double)mask/ubound;
|
scale = (double)mask/ubound;
|
||||||
bias = (double)((unsigned long long)1 << (mantissa - n));
|
bias = (double)(1ULL << (mantissa - dst_width));
|
||||||
|
|
||||||
res = LLVMBuildFMul(builder, src, lp_build_const_vec(src_type, scale), "");
|
res = LLVMBuildFMul(builder, src, lp_build_const_vec(src_type, scale), "");
|
||||||
res = LLVMBuildFAdd(builder, res, lp_build_const_vec(src_type, bias), "");
|
res = LLVMBuildFAdd(builder, res, lp_build_const_vec(src_type, bias), "");
|
||||||
res = LLVMBuildBitCast(builder, res, int_vec_type, "");
|
res = LLVMBuildBitCast(builder, res, int_vec_type, "");
|
||||||
|
|
||||||
if(dst_width > n) {
|
|
||||||
int shift = dst_width - n;
|
|
||||||
res = LLVMBuildShl(builder, res, lp_build_const_int_vec(src_type, shift), "");
|
|
||||||
|
|
||||||
/* TODO: Fill in the empty lower bits for additional precision? */
|
|
||||||
/* YES: this fixes progs/trivial/tri-z-eq.c.
|
|
||||||
* Otherwise vertex Z=1.0 values get converted to something like
|
|
||||||
* 0xfffffb00 and the test for equality with 0xffffffff fails.
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
{
|
|
||||||
LLVMValueRef msb;
|
|
||||||
msb = LLVMBuildLShr(builder, res, lp_build_const_int_vec(src_type, dst_width - 1), "");
|
|
||||||
msb = LLVMBuildShl(builder, msb, lp_build_const_int_vec(src_type, shift), "");
|
|
||||||
msb = LLVMBuildSub(builder, msb, lp_build_const_int_vec(src_type, 1), "");
|
|
||||||
res = LLVMBuildOr(builder, res, msb, "");
|
|
||||||
}
|
|
||||||
#elif 0
|
|
||||||
while(shift > 0) {
|
|
||||||
res = LLVMBuildOr(builder, res, LLVMBuildLShr(builder, res, lp_build_const_int_vec(src_type, n), ""), "");
|
|
||||||
shift -= n;
|
|
||||||
n *= 2;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
res = LLVMBuildAnd(builder, res, lp_build_const_int_vec(src_type, mask), "");
|
res = LLVMBuildAnd(builder, res, lp_build_const_int_vec(src_type, mask), "");
|
||||||
|
}
|
||||||
|
else if (dst_width == (mantissa + 1)) {
|
||||||
|
/*
|
||||||
|
* The destination width matches exactly what can be represented in
|
||||||
|
* floating point (i.e., mantissa + 1 bits). So do a straight
|
||||||
|
* multiplication followed by casting. No further rounding is necessary.
|
||||||
|
*/
|
||||||
|
|
||||||
|
double scale;
|
||||||
|
|
||||||
|
scale = (double)((1ULL << dst_width) - 1);
|
||||||
|
|
||||||
|
res = LLVMBuildFMul(builder, src, lp_build_const_vec(src_type, scale), "");
|
||||||
|
res = LLVMBuildFPToSI(builder, res, int_vec_type, "");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* The destination exceeds what can be represented in the floating point.
|
||||||
|
* So multiply by the largest power two we get away with, and when
|
||||||
|
* subtract the most significant bit to rescale to normalized values.
|
||||||
|
*
|
||||||
|
* The largest power of two factor we can get away is
|
||||||
|
* (1 << (src_type.width - 1)), because we need to use signed . In theory it
|
||||||
|
* should be (1 << (src_type.width - 2)), but IEEE 754 rules states
|
||||||
|
* INT_MIN should be returned in FPToSI, which is the correct result for
|
||||||
|
* values near 1.0!
|
||||||
|
*
|
||||||
|
* This means we get (src_type.width - 1) correct bits for values near 0.0,
|
||||||
|
* and (mantissa + 1) correct bits for values near 1.0. Equally or more
|
||||||
|
* important, we also get exact results for 0.0 and 1.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned n = MIN2(src_type.width - 1, dst_width);
|
||||||
|
|
||||||
|
double scale = (double)(1ULL << n);
|
||||||
|
unsigned lshift = dst_width - n;
|
||||||
|
unsigned rshift = n;
|
||||||
|
LLVMValueRef lshifted;
|
||||||
|
LLVMValueRef rshifted;
|
||||||
|
|
||||||
|
res = LLVMBuildFMul(builder, src, lp_build_const_vec(src_type, scale), "");
|
||||||
|
res = LLVMBuildFPToSI(builder, res, int_vec_type, "");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Align the most significant bit to its final place.
|
||||||
|
*
|
||||||
|
* This will cause 1.0 to overflow to 0, but the later adjustment will
|
||||||
|
* get it right.
|
||||||
|
*/
|
||||||
|
if (lshift) {
|
||||||
|
lshifted = LLVMBuildShl(builder, res,
|
||||||
|
lp_build_const_int_vec(src_type, lshift), "");
|
||||||
|
} else {
|
||||||
|
lshifted = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Align the most significant bit to the right.
|
||||||
|
*/
|
||||||
|
rshifted = LLVMBuildAShr(builder, res,
|
||||||
|
lp_build_const_int_vec(src_type, rshift), "");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Subtract the MSB to the LSB, therefore re-scaling from
|
||||||
|
* (1 << dst_width) to ((1 << dst_width) - 1).
|
||||||
|
*/
|
||||||
|
|
||||||
|
res = LLVMBuildSub(builder, lshifted, rshifted, "");
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
@ -178,6 +224,16 @@ lp_build_unsigned_norm_to_float(LLVMBuilderRef builder,
|
||||||
|
|
||||||
assert(dst_type.floating);
|
assert(dst_type.floating);
|
||||||
|
|
||||||
|
/* Special-case int8->float, though most cases could be handled
|
||||||
|
* this way:
|
||||||
|
*/
|
||||||
|
if (src_width == 8) {
|
||||||
|
scale = 1.0/255.0;
|
||||||
|
res = LLVMBuildSIToFP(builder, src, vec_type, "");
|
||||||
|
res = LLVMBuildFMul(builder, res, lp_build_const_vec(dst_type, scale), "");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
mantissa = lp_mantissa(dst_type);
|
mantissa = lp_mantissa(dst_type);
|
||||||
|
|
||||||
n = MIN2(mantissa, src_width);
|
n = MIN2(mantissa, src_width);
|
||||||
|
|
@ -257,7 +313,9 @@ lp_build_conv(LLVMBuilderRef builder,
|
||||||
dst_type.sign == 0 &&
|
dst_type.sign == 0 &&
|
||||||
dst_type.norm == 1 &&
|
dst_type.norm == 1 &&
|
||||||
dst_type.width == 8 &&
|
dst_type.width == 8 &&
|
||||||
dst_type.length == 16)
|
dst_type.length == 16 &&
|
||||||
|
|
||||||
|
util_cpu_caps.has_sse2)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -296,23 +354,7 @@ lp_build_conv(LLVMBuilderRef builder,
|
||||||
c = LLVMBuildFMul(builder, src[2], const_255f, "");
|
c = LLVMBuildFMul(builder, src[2], const_255f, "");
|
||||||
d = LLVMBuildFMul(builder, src[3], const_255f, "");
|
d = LLVMBuildFMul(builder, src[3], const_255f, "");
|
||||||
|
|
||||||
/* lp_build_round generates excessively general code without
|
{
|
||||||
* sse4, so do rounding manually.
|
|
||||||
*/
|
|
||||||
if (!util_cpu_caps.has_sse4_1) {
|
|
||||||
LLVMValueRef const_half = lp_build_const_vec(src_type, 0.5f);
|
|
||||||
|
|
||||||
a = LLVMBuildFAdd(builder, a, const_half, "");
|
|
||||||
b = LLVMBuildFAdd(builder, b, const_half, "");
|
|
||||||
c = LLVMBuildFAdd(builder, c, const_half, "");
|
|
||||||
d = LLVMBuildFAdd(builder, d, const_half, "");
|
|
||||||
|
|
||||||
src_int0 = LLVMBuildFPToSI(builder, a, int32_vec_type, "");
|
|
||||||
src_int1 = LLVMBuildFPToSI(builder, b, int32_vec_type, "");
|
|
||||||
src_int2 = LLVMBuildFPToSI(builder, c, int32_vec_type, "");
|
|
||||||
src_int3 = LLVMBuildFPToSI(builder, d, int32_vec_type, "");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
struct lp_build_context bld;
|
struct lp_build_context bld;
|
||||||
|
|
||||||
bld.builder = builder;
|
bld.builder = builder;
|
||||||
|
|
@ -329,7 +371,7 @@ lp_build_conv(LLVMBuilderRef builder,
|
||||||
src_int2 = lp_build_iround(&bld, c);
|
src_int2 = lp_build_iround(&bld, c);
|
||||||
src_int3 = lp_build_iround(&bld, d);
|
src_int3 = lp_build_iround(&bld, d);
|
||||||
}
|
}
|
||||||
|
/* relying on clamping behavior of sse2 intrinsics here */
|
||||||
lo = lp_build_pack2(builder, int32_type, int16_type, src_int0, src_int1);
|
lo = lp_build_pack2(builder, int32_type, int16_type, src_int0, src_int1);
|
||||||
hi = lp_build_pack2(builder, int32_type, int16_type, src_int2, src_int3);
|
hi = lp_build_pack2(builder, int32_type, int16_type, src_int2, src_int3);
|
||||||
dst[i] = lp_build_pack2(builder, int16_type, dst_type, lo, hi);
|
dst[i] = lp_build_pack2(builder, int16_type, dst_type, lo, hi);
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@ lp_disassemble(const void* func)
|
||||||
#ifdef HAVE_UDIS86
|
#ifdef HAVE_UDIS86
|
||||||
ud_t ud_obj;
|
ud_t ud_obj;
|
||||||
uint64_t max_jmp_pc;
|
uint64_t max_jmp_pc;
|
||||||
|
uint inst_no;
|
||||||
|
boolean emit_addrs = TRUE, emit_line_nos = FALSE;
|
||||||
|
|
||||||
ud_init(&ud_obj);
|
ud_init(&ud_obj);
|
||||||
|
|
||||||
|
|
@ -76,13 +78,18 @@ lp_disassemble(const void* func)
|
||||||
|
|
||||||
while (ud_disassemble(&ud_obj)) {
|
while (ud_disassemble(&ud_obj)) {
|
||||||
|
|
||||||
|
if (emit_addrs) {
|
||||||
#ifdef PIPE_ARCH_X86
|
#ifdef PIPE_ARCH_X86
|
||||||
debug_printf("0x%08lx:\t", (unsigned long)ud_insn_off(&ud_obj));
|
debug_printf("0x%08lx:\t", (unsigned long)ud_insn_off(&ud_obj));
|
||||||
#endif
|
#endif
|
||||||
#ifdef PIPE_ARCH_X86_64
|
#ifdef PIPE_ARCH_X86_64
|
||||||
debug_printf("0x%016llx:\t", (unsigned long long)ud_insn_off(&ud_obj));
|
debug_printf("0x%016llx:\t", (unsigned long long)ud_insn_off(&ud_obj));
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
else if (emit_line_nos) {
|
||||||
|
debug_printf("%6d:\t", inst_no);
|
||||||
|
inst_no++;
|
||||||
|
}
|
||||||
#if 0
|
#if 0
|
||||||
debug_printf("%-16s ", ud_insn_hex(&ud_obj));
|
debug_printf("%-16s ", ud_insn_hex(&ud_obj));
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -115,8 +122,10 @@ lp_disassemble(const void* func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ud_insn_off(&ud_obj) >= max_jmp_pc && ud_obj.mnemonic == UD_Iret) ||
|
if (ud_obj.mnemonic == UD_Iinvalid ||
|
||||||
ud_obj.mnemonic == UD_Iinvalid)
|
(ud_insn_off(&ud_obj) >= max_jmp_pc &&
|
||||||
|
(ud_obj.mnemonic == UD_Iret ||
|
||||||
|
ud_obj.mnemonic == UD_Ijmp)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,12 @@
|
||||||
#include "util/u_string.h"
|
#include "util/u_string.h"
|
||||||
|
|
||||||
|
|
||||||
#define GALLIVM_DEBUG_TGSI 0x1
|
#define GALLIVM_DEBUG_TGSI (1 << 0)
|
||||||
#define GALLIVM_DEBUG_IR 0x2
|
#define GALLIVM_DEBUG_IR (1 << 1)
|
||||||
#define GALLIVM_DEBUG_ASM 0x4
|
#define GALLIVM_DEBUG_ASM (1 << 2)
|
||||||
#define GALLIVM_DEBUG_NO_OPT 0x8
|
#define GALLIVM_DEBUG_NO_OPT (1 << 3)
|
||||||
#define GALLIVM_DEBUG_PERF 0x10
|
#define GALLIVM_DEBUG_PERF (1 << 4)
|
||||||
|
#define GALLIVM_DEBUG_NO_BRILINEAR (1 << 5)
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
||||||
|
|
@ -38,273 +38,15 @@
|
||||||
#include "lp_bld_flow.h"
|
#include "lp_bld_flow.h"
|
||||||
|
|
||||||
|
|
||||||
#define LP_BUILD_FLOW_MAX_VARIABLES 64
|
|
||||||
#define LP_BUILD_FLOW_MAX_DEPTH 32
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumeration of all possible flow constructs.
|
* Insert a new block, right where builder is pointing to.
|
||||||
*/
|
|
||||||
enum lp_build_flow_construct_kind {
|
|
||||||
LP_BUILD_FLOW_SCOPE,
|
|
||||||
LP_BUILD_FLOW_SKIP,
|
|
||||||
LP_BUILD_FLOW_IF
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Variable declaration scope.
|
|
||||||
*/
|
|
||||||
struct lp_build_flow_scope
|
|
||||||
{
|
|
||||||
/** Number of variables declared in this scope */
|
|
||||||
unsigned num_variables;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Early exit. Useful to skip to the end of a function or block when
|
|
||||||
* the execution mask becomes zero or when there is an error condition.
|
|
||||||
*/
|
|
||||||
struct lp_build_flow_skip
|
|
||||||
{
|
|
||||||
/** Block to skip to */
|
|
||||||
LLVMBasicBlockRef block;
|
|
||||||
|
|
||||||
/** Number of variables declared at the beginning */
|
|
||||||
unsigned num_variables;
|
|
||||||
|
|
||||||
LLVMValueRef *phi; /**< array [num_variables] */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* if/else/endif.
|
|
||||||
*/
|
|
||||||
struct lp_build_flow_if
|
|
||||||
{
|
|
||||||
unsigned num_variables;
|
|
||||||
|
|
||||||
LLVMValueRef *phi; /**< array [num_variables] */
|
|
||||||
|
|
||||||
LLVMValueRef condition;
|
|
||||||
LLVMBasicBlockRef entry_block, true_block, false_block, merge_block;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Union of all possible flow constructs' data
|
|
||||||
*/
|
|
||||||
union lp_build_flow_construct_data
|
|
||||||
{
|
|
||||||
struct lp_build_flow_scope scope;
|
|
||||||
struct lp_build_flow_skip skip;
|
|
||||||
struct lp_build_flow_if ifthen;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Element of the flow construct stack.
|
|
||||||
*/
|
|
||||||
struct lp_build_flow_construct
|
|
||||||
{
|
|
||||||
enum lp_build_flow_construct_kind kind;
|
|
||||||
union lp_build_flow_construct_data data;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All necessary data to generate LLVM control flow constructs.
|
|
||||||
*
|
*
|
||||||
* Besides keeping track of the control flow construct themselves we also
|
* This is useful important not only for aesthetic reasons, but also for
|
||||||
* need to keep track of variables in order to generate SSA Phi values.
|
* performance reasons, as frequently run blocks should be laid out next to
|
||||||
*/
|
* each other and fall-throughs maximized.
|
||||||
struct lp_build_flow_context
|
|
||||||
{
|
|
||||||
LLVMBuilderRef builder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Control flow stack.
|
|
||||||
*/
|
|
||||||
struct lp_build_flow_construct constructs[LP_BUILD_FLOW_MAX_DEPTH];
|
|
||||||
unsigned num_constructs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Variable stack
|
|
||||||
*/
|
|
||||||
LLVMValueRef *variables[LP_BUILD_FLOW_MAX_VARIABLES];
|
|
||||||
unsigned num_variables;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct lp_build_flow_context *
|
|
||||||
lp_build_flow_create(LLVMBuilderRef builder)
|
|
||||||
{
|
|
||||||
struct lp_build_flow_context *flow;
|
|
||||||
|
|
||||||
flow = CALLOC_STRUCT(lp_build_flow_context);
|
|
||||||
if(!flow)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
flow->builder = builder;
|
|
||||||
|
|
||||||
return flow;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
lp_build_flow_destroy(struct lp_build_flow_context *flow)
|
|
||||||
{
|
|
||||||
assert(flow->num_constructs == 0);
|
|
||||||
assert(flow->num_variables == 0);
|
|
||||||
FREE(flow);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Begin/push a new flow control construct, such as a loop, skip block
|
|
||||||
* or variable scope.
|
|
||||||
*/
|
|
||||||
static union lp_build_flow_construct_data *
|
|
||||||
lp_build_flow_push(struct lp_build_flow_context *flow,
|
|
||||||
enum lp_build_flow_construct_kind kind)
|
|
||||||
{
|
|
||||||
assert(flow->num_constructs < LP_BUILD_FLOW_MAX_DEPTH);
|
|
||||||
if(flow->num_constructs >= LP_BUILD_FLOW_MAX_DEPTH)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
flow->constructs[flow->num_constructs].kind = kind;
|
|
||||||
return &flow->constructs[flow->num_constructs++].data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the current/top flow control construct on the stack.
|
|
||||||
* \param kind the expected type of the top-most construct
|
|
||||||
*/
|
|
||||||
static union lp_build_flow_construct_data *
|
|
||||||
lp_build_flow_peek(struct lp_build_flow_context *flow,
|
|
||||||
enum lp_build_flow_construct_kind kind)
|
|
||||||
{
|
|
||||||
assert(flow->num_constructs);
|
|
||||||
if(!flow->num_constructs)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
assert(flow->constructs[flow->num_constructs - 1].kind == kind);
|
|
||||||
if(flow->constructs[flow->num_constructs - 1].kind != kind)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return &flow->constructs[flow->num_constructs - 1].data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* End/pop the current/top flow control construct on the stack.
|
|
||||||
* \param kind the expected type of the top-most construct
|
|
||||||
*/
|
|
||||||
static union lp_build_flow_construct_data *
|
|
||||||
lp_build_flow_pop(struct lp_build_flow_context *flow,
|
|
||||||
enum lp_build_flow_construct_kind kind)
|
|
||||||
{
|
|
||||||
assert(flow->num_constructs);
|
|
||||||
if(!flow->num_constructs)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
assert(flow->constructs[flow->num_constructs - 1].kind == kind);
|
|
||||||
if(flow->constructs[flow->num_constructs - 1].kind != kind)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return &flow->constructs[--flow->num_constructs].data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Begin a variable scope.
|
|
||||||
*
|
*
|
||||||
|
* See also llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp.
|
||||||
*
|
*
|
||||||
*/
|
|
||||||
void
|
|
||||||
lp_build_flow_scope_begin(struct lp_build_flow_context *flow)
|
|
||||||
{
|
|
||||||
struct lp_build_flow_scope *scope;
|
|
||||||
|
|
||||||
scope = &lp_build_flow_push(flow, LP_BUILD_FLOW_SCOPE)->scope;
|
|
||||||
if(!scope)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scope->num_variables = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Declare a variable.
|
|
||||||
*
|
|
||||||
* A variable is a named entity which can have different LLVMValueRef's at
|
|
||||||
* different points of the program. This is relevant for control flow because
|
|
||||||
* when there are multiple branches to a same location we need to replace
|
|
||||||
* the variable's value with a Phi function as explained in
|
|
||||||
* http://en.wikipedia.org/wiki/Static_single_assignment_form .
|
|
||||||
*
|
|
||||||
* We keep track of variables by keeping around a pointer to where they're
|
|
||||||
* current.
|
|
||||||
*
|
|
||||||
* There are a few cautions to observe:
|
|
||||||
*
|
|
||||||
* - Variable's value must not be NULL. If there is no initial value then
|
|
||||||
* LLVMGetUndef() should be used.
|
|
||||||
*
|
|
||||||
* - Variable's value must be kept up-to-date. If the variable is going to be
|
|
||||||
* modified by a function then a pointer should be passed so that its value
|
|
||||||
* is accurate. Failure to do this will cause some of the variables'
|
|
||||||
* transient values to be lost, leading to wrong results.
|
|
||||||
*
|
|
||||||
* - A program should be written from top to bottom, by always appending
|
|
||||||
* instructions to the bottom with a single LLVMBuilderRef. Inserting and/or
|
|
||||||
* modifying existing statements will most likely lead to wrong results.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
lp_build_flow_scope_declare(struct lp_build_flow_context *flow,
|
|
||||||
LLVMValueRef *variable)
|
|
||||||
{
|
|
||||||
struct lp_build_flow_scope *scope;
|
|
||||||
|
|
||||||
scope = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SCOPE)->scope;
|
|
||||||
if(!scope)
|
|
||||||
return;
|
|
||||||
|
|
||||||
assert(*variable);
|
|
||||||
if(!*variable)
|
|
||||||
return;
|
|
||||||
|
|
||||||
assert(flow->num_variables < LP_BUILD_FLOW_MAX_VARIABLES);
|
|
||||||
if(flow->num_variables >= LP_BUILD_FLOW_MAX_VARIABLES)
|
|
||||||
return;
|
|
||||||
|
|
||||||
flow->variables[flow->num_variables++] = variable;
|
|
||||||
++scope->num_variables;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
lp_build_flow_scope_end(struct lp_build_flow_context *flow)
|
|
||||||
{
|
|
||||||
struct lp_build_flow_scope *scope;
|
|
||||||
|
|
||||||
scope = &lp_build_flow_pop(flow, LP_BUILD_FLOW_SCOPE)->scope;
|
|
||||||
if(!scope)
|
|
||||||
return;
|
|
||||||
|
|
||||||
assert(flow->num_variables >= scope->num_variables);
|
|
||||||
if(flow->num_variables < scope->num_variables) {
|
|
||||||
flow->num_variables = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
flow->num_variables -= scope->num_variables;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: this function has no dependencies on the flow code and could
|
* Note: this function has no dependencies on the flow code and could
|
||||||
* be used elsewhere.
|
* be used elsewhere.
|
||||||
*/
|
*/
|
||||||
|
|
@ -334,52 +76,18 @@ lp_build_insert_new_block(LLVMBuilderRef builder, const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static LLVMBasicBlockRef
|
|
||||||
lp_build_flow_insert_block(struct lp_build_flow_context *flow)
|
|
||||||
{
|
|
||||||
return lp_build_insert_new_block(flow->builder, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begin a "skip" block. Inside this block we can test a condition and
|
* Begin a "skip" block. Inside this block we can test a condition and
|
||||||
* skip to the end of the block if the condition is false.
|
* skip to the end of the block if the condition is false.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
|
lp_build_flow_skip_begin(struct lp_build_skip_context *skip,
|
||||||
|
LLVMBuilderRef builder)
|
||||||
{
|
{
|
||||||
struct lp_build_flow_skip *skip;
|
skip->builder = builder;
|
||||||
LLVMBuilderRef builder;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
skip = &lp_build_flow_push(flow, LP_BUILD_FLOW_SKIP)->skip;
|
|
||||||
if(!skip)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* create new basic block */
|
/* create new basic block */
|
||||||
skip->block = lp_build_flow_insert_block(flow);
|
skip->block = lp_build_insert_new_block(skip->builder, "skip");
|
||||||
|
|
||||||
skip->num_variables = flow->num_variables;
|
|
||||||
if(!skip->num_variables) {
|
|
||||||
skip->phi = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate a Phi node for each variable in this skip scope */
|
|
||||||
skip->phi = MALLOC(skip->num_variables * sizeof *skip->phi);
|
|
||||||
if(!skip->phi) {
|
|
||||||
skip->num_variables = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
builder = LLVMCreateBuilder();
|
|
||||||
LLVMPositionBuilderAtEnd(builder, skip->block);
|
|
||||||
|
|
||||||
/* create a Phi node for each variable */
|
|
||||||
for(i = 0; i < skip->num_variables; ++i)
|
|
||||||
skip->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
|
|
||||||
|
|
||||||
LLVMDisposeBuilder(builder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -388,83 +96,50 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
|
||||||
* skip block if the condition is true.
|
* skip block if the condition is true.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
|
lp_build_flow_skip_cond_break(struct lp_build_skip_context *skip,
|
||||||
LLVMValueRef cond)
|
LLVMValueRef cond)
|
||||||
{
|
{
|
||||||
struct lp_build_flow_skip *skip;
|
|
||||||
LLVMBasicBlockRef current_block;
|
|
||||||
LLVMBasicBlockRef new_block;
|
LLVMBasicBlockRef new_block;
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
skip = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SKIP)->skip;
|
new_block = lp_build_insert_new_block(skip->builder, "");
|
||||||
if(!skip)
|
|
||||||
return;
|
|
||||||
|
|
||||||
current_block = LLVMGetInsertBlock(flow->builder);
|
|
||||||
|
|
||||||
new_block = lp_build_flow_insert_block(flow);
|
|
||||||
|
|
||||||
/* for each variable, update the Phi node with a (variable, block) pair */
|
|
||||||
for(i = 0; i < skip->num_variables; ++i) {
|
|
||||||
assert(*flow->variables[i]);
|
|
||||||
assert(LLVMTypeOf(skip->phi[i]) == LLVMTypeOf(*flow->variables[i]));
|
|
||||||
LLVMAddIncoming(skip->phi[i], flow->variables[i], ¤t_block, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if cond is true, goto skip->block, else goto new_block */
|
/* if cond is true, goto skip->block, else goto new_block */
|
||||||
LLVMBuildCondBr(flow->builder, cond, skip->block, new_block);
|
LLVMBuildCondBr(skip->builder, cond, skip->block, new_block);
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(flow->builder, new_block);
|
LLVMPositionBuilderAtEnd(skip->builder, new_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_flow_skip_end(struct lp_build_flow_context *flow)
|
lp_build_flow_skip_end(struct lp_build_skip_context *skip)
|
||||||
{
|
{
|
||||||
struct lp_build_flow_skip *skip;
|
|
||||||
LLVMBasicBlockRef current_block;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
skip = &lp_build_flow_pop(flow, LP_BUILD_FLOW_SKIP)->skip;
|
|
||||||
if(!skip)
|
|
||||||
return;
|
|
||||||
|
|
||||||
current_block = LLVMGetInsertBlock(flow->builder);
|
|
||||||
|
|
||||||
/* add (variable, block) tuples to the phi nodes */
|
|
||||||
for(i = 0; i < skip->num_variables; ++i) {
|
|
||||||
assert(*flow->variables[i]);
|
|
||||||
assert(LLVMTypeOf(skip->phi[i]) == LLVMTypeOf(*flow->variables[i]));
|
|
||||||
LLVMAddIncoming(skip->phi[i], flow->variables[i], ¤t_block, 1);
|
|
||||||
*flow->variables[i] = skip->phi[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* goto block */
|
/* goto block */
|
||||||
LLVMBuildBr(flow->builder, skip->block);
|
LLVMBuildBr(skip->builder, skip->block);
|
||||||
LLVMPositionBuilderAtEnd(flow->builder, skip->block);
|
LLVMPositionBuilderAtEnd(skip->builder, skip->block);
|
||||||
|
|
||||||
FREE(skip->phi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the mask predicate is zero. If so, jump to the end of the block.
|
* Check if the mask predicate is zero. If so, jump to the end of the block.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
lp_build_mask_check(struct lp_build_mask_context *mask)
|
lp_build_mask_check(struct lp_build_mask_context *mask)
|
||||||
{
|
{
|
||||||
LLVMBuilderRef builder = mask->flow->builder;
|
LLVMBuilderRef builder = mask->skip.builder;
|
||||||
|
LLVMValueRef value;
|
||||||
LLVMValueRef cond;
|
LLVMValueRef cond;
|
||||||
|
|
||||||
|
value = lp_build_mask_value(mask);
|
||||||
|
|
||||||
/* cond = (mask == 0) */
|
/* cond = (mask == 0) */
|
||||||
cond = LLVMBuildICmp(builder,
|
cond = LLVMBuildICmp(builder,
|
||||||
LLVMIntEQ,
|
LLVMIntEQ,
|
||||||
LLVMBuildBitCast(builder, mask->value, mask->reg_type, ""),
|
LLVMBuildBitCast(builder, value, mask->reg_type, ""),
|
||||||
LLVMConstNull(mask->reg_type),
|
LLVMConstNull(mask->reg_type),
|
||||||
"");
|
"");
|
||||||
|
|
||||||
/* if cond, goto end of block */
|
/* if cond, goto end of block */
|
||||||
lp_build_flow_skip_cond_break(mask->flow, cond);
|
lp_build_flow_skip_cond_break(&mask->skip, cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -477,21 +152,27 @@ lp_build_mask_check(struct lp_build_mask_context *mask)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
lp_build_mask_begin(struct lp_build_mask_context *mask,
|
lp_build_mask_begin(struct lp_build_mask_context *mask,
|
||||||
struct lp_build_flow_context *flow,
|
LLVMBuilderRef builder,
|
||||||
struct lp_type type,
|
struct lp_type type,
|
||||||
LLVMValueRef value)
|
LLVMValueRef value)
|
||||||
{
|
{
|
||||||
memset(mask, 0, sizeof *mask);
|
memset(mask, 0, sizeof *mask);
|
||||||
|
|
||||||
mask->flow = flow;
|
|
||||||
mask->reg_type = LLVMIntType(type.width * type.length);
|
mask->reg_type = LLVMIntType(type.width * type.length);
|
||||||
mask->value = value;
|
mask->var = lp_build_alloca(builder,
|
||||||
|
lp_build_int_vec_type(type),
|
||||||
|
"execution_mask");
|
||||||
|
|
||||||
lp_build_flow_scope_begin(flow);
|
LLVMBuildStore(builder, value, mask->var);
|
||||||
lp_build_flow_scope_declare(flow, &mask->value);
|
|
||||||
lp_build_flow_skip_begin(flow);
|
|
||||||
|
|
||||||
lp_build_mask_check(mask);
|
lp_build_flow_skip_begin(&mask->skip, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LLVMValueRef
|
||||||
|
lp_build_mask_value(struct lp_build_mask_context *mask)
|
||||||
|
{
|
||||||
|
return LLVMBuildLoad(mask->skip.builder, mask->var, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -504,9 +185,10 @@ void
|
||||||
lp_build_mask_update(struct lp_build_mask_context *mask,
|
lp_build_mask_update(struct lp_build_mask_context *mask,
|
||||||
LLVMValueRef value)
|
LLVMValueRef value)
|
||||||
{
|
{
|
||||||
mask->value = LLVMBuildAnd( mask->flow->builder, mask->value, value, "");
|
value = LLVMBuildAnd(mask->skip.builder,
|
||||||
|
lp_build_mask_value(mask),
|
||||||
lp_build_mask_check(mask);
|
value, "");
|
||||||
|
LLVMBuildStore(mask->skip.builder, value, mask->var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -516,9 +198,8 @@ lp_build_mask_update(struct lp_build_mask_context *mask,
|
||||||
LLVMValueRef
|
LLVMValueRef
|
||||||
lp_build_mask_end(struct lp_build_mask_context *mask)
|
lp_build_mask_end(struct lp_build_mask_context *mask)
|
||||||
{
|
{
|
||||||
lp_build_flow_skip_end(mask->flow);
|
lp_build_flow_skip_end(&mask->skip);
|
||||||
lp_build_flow_scope_end(mask->flow);
|
return lp_build_mask_value(mask);
|
||||||
return mask->value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -528,19 +209,47 @@ lp_build_loop_begin(LLVMBuilderRef builder,
|
||||||
LLVMValueRef start,
|
LLVMValueRef start,
|
||||||
struct lp_build_loop_state *state)
|
struct lp_build_loop_state *state)
|
||||||
{
|
{
|
||||||
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
|
state->block = lp_build_insert_new_block(builder, "loop_begin");
|
||||||
LLVMValueRef function = LLVMGetBasicBlockParent(block);
|
|
||||||
|
|
||||||
state->block = LLVMAppendBasicBlock(function, "loop");
|
state->counter_var = lp_build_alloca(builder, LLVMTypeOf(start), "loop_counter");
|
||||||
|
|
||||||
|
LLVMBuildStore(builder, start, state->counter_var);
|
||||||
|
|
||||||
LLVMBuildBr(builder, state->block);
|
LLVMBuildBr(builder, state->block);
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(builder, state->block);
|
LLVMPositionBuilderAtEnd(builder, state->block);
|
||||||
|
|
||||||
state->counter = LLVMBuildPhi(builder, LLVMTypeOf(start), "");
|
state->counter = LLVMBuildLoad(builder, state->counter_var, "");
|
||||||
|
}
|
||||||
|
|
||||||
LLVMAddIncoming(state->counter, &start, &block, 1);
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_loop_end_cond(LLVMBuilderRef builder,
|
||||||
|
LLVMValueRef end,
|
||||||
|
LLVMValueRef step,
|
||||||
|
LLVMIntPredicate llvm_cond,
|
||||||
|
struct lp_build_loop_state *state)
|
||||||
|
{
|
||||||
|
LLVMValueRef next;
|
||||||
|
LLVMValueRef cond;
|
||||||
|
LLVMBasicBlockRef after_block;
|
||||||
|
|
||||||
|
if (!step)
|
||||||
|
step = LLVMConstInt(LLVMTypeOf(end), 1, 0);
|
||||||
|
|
||||||
|
next = LLVMBuildAdd(builder, state->counter, step, "");
|
||||||
|
|
||||||
|
LLVMBuildStore(builder, next, state->counter_var);
|
||||||
|
|
||||||
|
cond = LLVMBuildICmp(builder, llvm_cond, next, end, "");
|
||||||
|
|
||||||
|
after_block = lp_build_insert_new_block(builder, "loop_end");
|
||||||
|
|
||||||
|
LLVMBuildCondBr(builder, cond, after_block, state->block);
|
||||||
|
|
||||||
|
LLVMPositionBuilderAtEnd(builder, after_block);
|
||||||
|
|
||||||
|
state->counter = LLVMBuildLoad(builder, state->counter_var, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -550,55 +259,7 @@ lp_build_loop_end(LLVMBuilderRef builder,
|
||||||
LLVMValueRef step,
|
LLVMValueRef step,
|
||||||
struct lp_build_loop_state *state)
|
struct lp_build_loop_state *state)
|
||||||
{
|
{
|
||||||
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
|
lp_build_loop_end_cond(builder, end, step, LLVMIntNE, state);
|
||||||
LLVMValueRef function = LLVMGetBasicBlockParent(block);
|
|
||||||
LLVMValueRef next;
|
|
||||||
LLVMValueRef cond;
|
|
||||||
LLVMBasicBlockRef after_block;
|
|
||||||
|
|
||||||
if (!step)
|
|
||||||
step = LLVMConstInt(LLVMTypeOf(end), 1, 0);
|
|
||||||
|
|
||||||
next = LLVMBuildAdd(builder, state->counter, step, "");
|
|
||||||
|
|
||||||
cond = LLVMBuildICmp(builder, LLVMIntNE, next, end, "");
|
|
||||||
|
|
||||||
after_block = LLVMAppendBasicBlock(function, "");
|
|
||||||
|
|
||||||
LLVMBuildCondBr(builder, cond, after_block, state->block);
|
|
||||||
|
|
||||||
LLVMAddIncoming(state->counter, &next, &block, 1);
|
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(builder, after_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lp_build_loop_end_cond(LLVMBuilderRef builder,
|
|
||||||
LLVMValueRef end,
|
|
||||||
LLVMValueRef step,
|
|
||||||
int llvm_cond,
|
|
||||||
struct lp_build_loop_state *state)
|
|
||||||
{
|
|
||||||
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
|
|
||||||
LLVMValueRef function = LLVMGetBasicBlockParent(block);
|
|
||||||
LLVMValueRef next;
|
|
||||||
LLVMValueRef cond;
|
|
||||||
LLVMBasicBlockRef after_block;
|
|
||||||
|
|
||||||
if (!step)
|
|
||||||
step = LLVMConstInt(LLVMTypeOf(end), 1, 0);
|
|
||||||
|
|
||||||
next = LLVMBuildAdd(builder, state->counter, step, "");
|
|
||||||
|
|
||||||
cond = LLVMBuildICmp(builder, llvm_cond, next, end, "");
|
|
||||||
|
|
||||||
after_block = LLVMAppendBasicBlock(function, "");
|
|
||||||
|
|
||||||
LLVMBuildCondBr(builder, cond, after_block, state->block);
|
|
||||||
|
|
||||||
LLVMAddIncoming(state->counter, &next, &block, 1);
|
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(builder, after_block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -616,24 +277,16 @@ lp_build_loop_end_cond(LLVMBuilderRef builder,
|
||||||
|
|
||||||
Is built with:
|
Is built with:
|
||||||
|
|
||||||
LLVMValueRef x = LLVMGetUndef(); // or something else
|
// x needs an alloca variable
|
||||||
|
x = lp_build_alloca(builder, type, "x");
|
||||||
|
|
||||||
flow = lp_build_flow_create(builder);
|
|
||||||
|
|
||||||
lp_build_flow_scope_begin(flow);
|
lp_build_if(ctx, builder, cond);
|
||||||
|
LLVMBuildStore(LLVMBuildAdd(1, 2), x);
|
||||||
// x needs a phi node
|
|
||||||
lp_build_flow_scope_declare(flow, &x);
|
|
||||||
|
|
||||||
lp_build_if(ctx, flow, builder, cond);
|
|
||||||
x = LLVMAdd(1, 2);
|
|
||||||
lp_build_else(ctx);
|
lp_build_else(ctx);
|
||||||
x = LLVMAdd(2, 3);
|
LLVMBuildStore(LLVMBuildAdd(2, 3). x);
|
||||||
lp_build_endif(ctx);
|
lp_build_endif(ctx);
|
||||||
|
|
||||||
lp_build_flow_scope_end(flow);
|
|
||||||
|
|
||||||
lp_build_flow_destroy(flow);
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -642,47 +295,19 @@ lp_build_loop_end_cond(LLVMBuilderRef builder,
|
||||||
* Begin an if/else/endif construct.
|
* Begin an if/else/endif construct.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
lp_build_if(struct lp_build_if_state *ctx,
|
lp_build_if(struct lp_build_if_state *ifthen,
|
||||||
struct lp_build_flow_context *flow,
|
|
||||||
LLVMBuilderRef builder,
|
LLVMBuilderRef builder,
|
||||||
LLVMValueRef condition)
|
LLVMValueRef condition)
|
||||||
{
|
{
|
||||||
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
|
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
|
||||||
struct lp_build_flow_if *ifthen;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
memset(ctx, 0, sizeof(*ctx));
|
memset(ifthen, 0, sizeof *ifthen);
|
||||||
ctx->builder = builder;
|
ifthen->builder = builder;
|
||||||
ctx->flow = flow;
|
|
||||||
|
|
||||||
/* push/create new scope */
|
|
||||||
ifthen = &lp_build_flow_push(flow, LP_BUILD_FLOW_IF)->ifthen;
|
|
||||||
assert(ifthen);
|
|
||||||
|
|
||||||
ifthen->num_variables = flow->num_variables;
|
|
||||||
ifthen->condition = condition;
|
ifthen->condition = condition;
|
||||||
ifthen->entry_block = block;
|
ifthen->entry_block = block;
|
||||||
|
|
||||||
/* create a Phi node for each variable in this flow scope */
|
|
||||||
ifthen->phi = MALLOC(ifthen->num_variables * sizeof(*ifthen->phi));
|
|
||||||
if (!ifthen->phi) {
|
|
||||||
ifthen->num_variables = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create endif/merge basic block for the phi functions */
|
/* create endif/merge basic block for the phi functions */
|
||||||
ifthen->merge_block = lp_build_insert_new_block(builder, "endif-block");
|
ifthen->merge_block = lp_build_insert_new_block(builder, "endif-block");
|
||||||
LLVMPositionBuilderAtEnd(builder, ifthen->merge_block);
|
|
||||||
|
|
||||||
/* create a phi node for each variable */
|
|
||||||
for (i = 0; i < flow->num_variables; i++) {
|
|
||||||
ifthen->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
|
|
||||||
|
|
||||||
/* add add the initial value of the var from the entry block */
|
|
||||||
if (!LLVMIsUndef(*flow->variables[i]))
|
|
||||||
LLVMAddIncoming(ifthen->phi[i], flow->variables[i],
|
|
||||||
&ifthen->entry_block, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create/insert true_block before merge_block */
|
/* create/insert true_block before merge_block */
|
||||||
ifthen->true_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-true-block");
|
ifthen->true_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-true-block");
|
||||||
|
|
@ -696,27 +321,16 @@ lp_build_if(struct lp_build_if_state *ctx,
|
||||||
* Begin else-part of a conditional
|
* Begin else-part of a conditional
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
lp_build_else(struct lp_build_if_state *ctx)
|
lp_build_else(struct lp_build_if_state *ifthen)
|
||||||
{
|
{
|
||||||
struct lp_build_flow_context *flow = ctx->flow;
|
/* Append an unconditional Br(anch) instruction on the true_block */
|
||||||
struct lp_build_flow_if *ifthen;
|
LLVMBuildBr(ifthen->builder, ifthen->merge_block);
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
ifthen = &lp_build_flow_peek(flow, LP_BUILD_FLOW_IF)->ifthen;
|
|
||||||
assert(ifthen);
|
|
||||||
|
|
||||||
/* for each variable, update the Phi node with a (variable, block) pair */
|
|
||||||
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
|
|
||||||
for (i = 0; i < flow->num_variables; i++) {
|
|
||||||
assert(*flow->variables[i]);
|
|
||||||
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create/insert false_block before the merge block */
|
/* create/insert false_block before the merge block */
|
||||||
ifthen->false_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-false-block");
|
ifthen->false_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-false-block");
|
||||||
|
|
||||||
/* successive code goes into the else block */
|
/* successive code goes into the else block */
|
||||||
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block);
|
LLVMPositionBuilderAtEnd(ifthen->builder, ifthen->false_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -724,75 +338,30 @@ lp_build_else(struct lp_build_if_state *ctx)
|
||||||
* End a conditional.
|
* End a conditional.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
lp_build_endif(struct lp_build_if_state *ctx)
|
lp_build_endif(struct lp_build_if_state *ifthen)
|
||||||
{
|
{
|
||||||
struct lp_build_flow_context *flow = ctx->flow;
|
|
||||||
struct lp_build_flow_if *ifthen;
|
|
||||||
LLVMBasicBlockRef curBlock = LLVMGetInsertBlock(ctx->builder);
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
ifthen = &lp_build_flow_pop(flow, LP_BUILD_FLOW_IF)->ifthen;
|
|
||||||
assert(ifthen);
|
|
||||||
|
|
||||||
/* Insert branch to the merge block from current block */
|
/* Insert branch to the merge block from current block */
|
||||||
LLVMBuildBr(ctx->builder, ifthen->merge_block);
|
LLVMBuildBr(ifthen->builder, ifthen->merge_block);
|
||||||
|
|
||||||
if (ifthen->false_block) {
|
/*
|
||||||
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
|
* Now patch in the various branch instructions.
|
||||||
/* for each variable, update the Phi node with a (variable, block) pair */
|
*/
|
||||||
for (i = 0; i < flow->num_variables; i++) {
|
|
||||||
assert(*flow->variables[i]);
|
|
||||||
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &curBlock, 1);
|
|
||||||
/* replace the variable ref with the phi function */
|
|
||||||
*flow->variables[i] = ifthen->phi[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* no else clause */
|
|
||||||
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
|
|
||||||
for (i = 0; i < flow->num_variables; i++) {
|
|
||||||
assert(*flow->variables[i]);
|
|
||||||
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
|
|
||||||
|
|
||||||
/* replace the variable ref with the phi function */
|
|
||||||
*flow->variables[i] = ifthen->phi[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FREE(ifthen->phi);
|
|
||||||
|
|
||||||
/***
|
|
||||||
*** Now patch in the various branch instructions.
|
|
||||||
***/
|
|
||||||
|
|
||||||
/* Insert the conditional branch instruction at the end of entry_block */
|
/* Insert the conditional branch instruction at the end of entry_block */
|
||||||
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->entry_block);
|
LLVMPositionBuilderAtEnd(ifthen->builder, ifthen->entry_block);
|
||||||
if (ifthen->false_block) {
|
if (ifthen->false_block) {
|
||||||
/* we have an else clause */
|
/* we have an else clause */
|
||||||
LLVMBuildCondBr(ctx->builder, ifthen->condition,
|
LLVMBuildCondBr(ifthen->builder, ifthen->condition,
|
||||||
ifthen->true_block, ifthen->false_block);
|
ifthen->true_block, ifthen->false_block);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* no else clause */
|
/* no else clause */
|
||||||
LLVMBuildCondBr(ctx->builder, ifthen->condition,
|
LLVMBuildCondBr(ifthen->builder, ifthen->condition,
|
||||||
ifthen->true_block, ifthen->merge_block);
|
ifthen->true_block, ifthen->merge_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert branch from end of true_block to merge_block */
|
|
||||||
if (ifthen->false_block) {
|
|
||||||
/* Append an unconditional Br(anch) instruction on the true_block */
|
|
||||||
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->true_block);
|
|
||||||
LLVMBuildBr(ctx->builder, ifthen->merge_block);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* No else clause.
|
|
||||||
* Note that we've already inserted the branch at the end of
|
|
||||||
* true_block. See the very first LLVMBuildBr() call in this function.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume building code at end of the ifthen->merge_block */
|
/* Resume building code at end of the ifthen->merge_block */
|
||||||
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
|
LLVMPositionBuilderAtEnd(ifthen->builder, ifthen->merge_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -830,6 +399,7 @@ lp_build_alloca(LLVMBuilderRef builder,
|
||||||
}
|
}
|
||||||
|
|
||||||
res = LLVMBuildAlloca(first_builder, type, name);
|
res = LLVMBuildAlloca(first_builder, type, name);
|
||||||
|
LLVMBuildStore(builder, LLVMConstNull(type), res);
|
||||||
|
|
||||||
LLVMDisposeBuilder(first_builder);
|
LLVMDisposeBuilder(first_builder);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,52 +41,49 @@
|
||||||
struct lp_type;
|
struct lp_type;
|
||||||
|
|
||||||
|
|
||||||
struct lp_build_flow_context;
|
/**
|
||||||
|
* Early exit. Useful to skip to the end of a function or block when
|
||||||
|
* the execution mask becomes zero or when there is an error condition.
|
||||||
|
*/
|
||||||
|
struct lp_build_skip_context
|
||||||
|
{
|
||||||
|
LLVMBuilderRef builder;
|
||||||
|
|
||||||
|
/** Block to skip to */
|
||||||
struct lp_build_flow_context *
|
LLVMBasicBlockRef block;
|
||||||
lp_build_flow_create(LLVMBuilderRef builder);
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_flow_destroy(struct lp_build_flow_context *flow);
|
lp_build_flow_skip_begin(struct lp_build_skip_context *ctx,
|
||||||
|
LLVMBuilderRef builder);
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_flow_scope_begin(struct lp_build_flow_context *flow);
|
lp_build_flow_skip_cond_break(struct lp_build_skip_context *ctx,
|
||||||
|
|
||||||
void
|
|
||||||
lp_build_flow_scope_declare(struct lp_build_flow_context *flow,
|
|
||||||
LLVMValueRef *variable);
|
|
||||||
|
|
||||||
void
|
|
||||||
lp_build_flow_scope_end(struct lp_build_flow_context *flow);
|
|
||||||
|
|
||||||
void
|
|
||||||
lp_build_flow_skip_begin(struct lp_build_flow_context *flow);
|
|
||||||
|
|
||||||
void
|
|
||||||
lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
|
|
||||||
LLVMValueRef cond);
|
LLVMValueRef cond);
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_flow_skip_end(struct lp_build_flow_context *flow);
|
lp_build_flow_skip_end(struct lp_build_skip_context *ctx);
|
||||||
|
|
||||||
|
|
||||||
struct lp_build_mask_context
|
struct lp_build_mask_context
|
||||||
{
|
{
|
||||||
struct lp_build_flow_context *flow;
|
struct lp_build_skip_context skip;
|
||||||
|
|
||||||
LLVMTypeRef reg_type;
|
LLVMTypeRef reg_type;
|
||||||
|
|
||||||
LLVMValueRef value;
|
LLVMValueRef var;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_mask_begin(struct lp_build_mask_context *mask,
|
lp_build_mask_begin(struct lp_build_mask_context *mask,
|
||||||
struct lp_build_flow_context *flow,
|
LLVMBuilderRef builder,
|
||||||
struct lp_type type,
|
struct lp_type type,
|
||||||
LLVMValueRef value);
|
LLVMValueRef value);
|
||||||
|
|
||||||
|
LLVMValueRef
|
||||||
|
lp_build_mask_value(struct lp_build_mask_context *mask);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bitwise AND the mask with the given value, if a previous mask was set.
|
* Bitwise AND the mask with the given value, if a previous mask was set.
|
||||||
*/
|
*/
|
||||||
|
|
@ -94,6 +91,9 @@ void
|
||||||
lp_build_mask_update(struct lp_build_mask_context *mask,
|
lp_build_mask_update(struct lp_build_mask_context *mask,
|
||||||
LLVMValueRef value);
|
LLVMValueRef value);
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_mask_check(struct lp_build_mask_context *mask);
|
||||||
|
|
||||||
LLVMValueRef
|
LLVMValueRef
|
||||||
lp_build_mask_end(struct lp_build_mask_context *mask);
|
lp_build_mask_end(struct lp_build_mask_context *mask);
|
||||||
|
|
||||||
|
|
@ -108,6 +108,7 @@ lp_build_mask_end(struct lp_build_mask_context *mask);
|
||||||
struct lp_build_loop_state
|
struct lp_build_loop_state
|
||||||
{
|
{
|
||||||
LLVMBasicBlockRef block;
|
LLVMBasicBlockRef block;
|
||||||
|
LLVMValueRef counter_var;
|
||||||
LLVMValueRef counter;
|
LLVMValueRef counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -128,22 +129,28 @@ void
|
||||||
lp_build_loop_end_cond(LLVMBuilderRef builder,
|
lp_build_loop_end_cond(LLVMBuilderRef builder,
|
||||||
LLVMValueRef end,
|
LLVMValueRef end,
|
||||||
LLVMValueRef step,
|
LLVMValueRef step,
|
||||||
int cond, /* LLVM condition */
|
LLVMIntPredicate cond,
|
||||||
struct lp_build_loop_state *state);
|
struct lp_build_loop_state *state);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if/else/endif.
|
||||||
|
*/
|
||||||
struct lp_build_if_state
|
struct lp_build_if_state
|
||||||
{
|
{
|
||||||
LLVMBuilderRef builder;
|
LLVMBuilderRef builder;
|
||||||
struct lp_build_flow_context *flow;
|
LLVMValueRef condition;
|
||||||
|
LLVMBasicBlockRef entry_block;
|
||||||
|
LLVMBasicBlockRef true_block;
|
||||||
|
LLVMBasicBlockRef false_block;
|
||||||
|
LLVMBasicBlockRef merge_block;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_if(struct lp_build_if_state *ctx,
|
lp_build_if(struct lp_build_if_state *ctx,
|
||||||
struct lp_build_flow_context *flow,
|
|
||||||
LLVMBuilderRef builder,
|
LLVMBuilderRef builder,
|
||||||
LLVMValueRef condition);
|
LLVMValueRef condition);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ static const struct debug_named_value lp_bld_debug_flags[] = {
|
||||||
{ "asm", GALLIVM_DEBUG_ASM, NULL },
|
{ "asm", GALLIVM_DEBUG_ASM, NULL },
|
||||||
{ "nopt", GALLIVM_DEBUG_NO_OPT, NULL },
|
{ "nopt", GALLIVM_DEBUG_NO_OPT, NULL },
|
||||||
{ "perf", GALLIVM_DEBUG_PERF, NULL },
|
{ "perf", GALLIVM_DEBUG_PERF, NULL },
|
||||||
|
{ "no_brilinear", GALLIVM_DEBUG_NO_BRILINEAR, NULL },
|
||||||
DEBUG_NAMED_VALUE_END
|
DEBUG_NAMED_VALUE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,4 +47,10 @@ lp_build_init(void);
|
||||||
extern void
|
extern void
|
||||||
lp_func_delete_body(LLVMValueRef func);
|
lp_func_delete_body(LLVMValueRef func);
|
||||||
|
|
||||||
|
|
||||||
|
extern LLVMValueRef
|
||||||
|
lp_build_load_volatile(LLVMBuilderRef B, LLVMValueRef PointerVal,
|
||||||
|
const char *Name);
|
||||||
|
|
||||||
|
|
||||||
#endif /* !LP_BLD_INIT_H */
|
#endif /* !LP_BLD_INIT_H */
|
||||||
|
|
|
||||||
|
|
@ -462,10 +462,12 @@ lp_build_select(struct lp_build_context *bld,
|
||||||
LLVMTypeRef arg_type;
|
LLVMTypeRef arg_type;
|
||||||
LLVMValueRef args[3];
|
LLVMValueRef args[3];
|
||||||
|
|
||||||
if (type.width == 64) {
|
if (type.floating &&
|
||||||
|
type.width == 64) {
|
||||||
intrinsic = "llvm.x86.sse41.blendvpd";
|
intrinsic = "llvm.x86.sse41.blendvpd";
|
||||||
arg_type = LLVMVectorType(LLVMDoubleType(), 2);
|
arg_type = LLVMVectorType(LLVMDoubleType(), 2);
|
||||||
} else if (type.width == 32) {
|
} else if (type.floating &&
|
||||||
|
type.width == 32) {
|
||||||
intrinsic = "llvm.x86.sse41.blendvps";
|
intrinsic = "llvm.x86.sse41.blendvps";
|
||||||
arg_type = LLVMVectorType(LLVMFloatType(), 4);
|
arg_type = LLVMVectorType(LLVMFloatType(), 4);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -178,3 +178,13 @@ lp_func_delete_body(LLVMValueRef FF)
|
||||||
llvm::Function *func = llvm::unwrap<llvm::Function>(FF);
|
llvm::Function *func = llvm::unwrap<llvm::Function>(FF);
|
||||||
func->deleteBody();
|
func->deleteBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
LLVMValueRef
|
||||||
|
lp_build_load_volatile(LLVMBuilderRef B, LLVMValueRef PointerVal,
|
||||||
|
const char *Name)
|
||||||
|
{
|
||||||
|
return llvm::wrap(llvm::unwrap(B)->CreateLoad(llvm::unwrap(PointerVal), true, Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
#include "util/u_debug.h"
|
#include "util/u_debug.h"
|
||||||
#include "util/u_memory.h"
|
#include "util/u_memory.h"
|
||||||
|
#include "util/u_string.h"
|
||||||
|
#include "lp_bld_const.h"
|
||||||
#include "lp_bld_printf.h"
|
#include "lp_bld_printf.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -119,3 +121,22 @@ lp_build_printf(LLVMBuilderRef builder, const char *fmt, ...)
|
||||||
return LLVMBuildCall(builder, func_printf, params, argcount + 1, "");
|
return LLVMBuildCall(builder, func_printf, params, argcount + 1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a float[4] vector.
|
||||||
|
*/
|
||||||
|
LLVMValueRef
|
||||||
|
lp_build_print_vec4(LLVMBuilderRef builder, const char *msg, LLVMValueRef vec)
|
||||||
|
{
|
||||||
|
char format[1000];
|
||||||
|
LLVMValueRef x, y, z, w;
|
||||||
|
|
||||||
|
x = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(0), "");
|
||||||
|
y = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(1), "");
|
||||||
|
z = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(2), "");
|
||||||
|
w = LLVMBuildExtractElement(builder, vec, lp_build_const_int32(3), "");
|
||||||
|
|
||||||
|
util_snprintf(format, sizeof(format), "%s %%f %%f %%f %%f\n", msg);
|
||||||
|
return lp_build_printf(builder, format, x, y, z, w);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,5 +35,9 @@
|
||||||
LLVMValueRef lp_build_const_string_variable(LLVMModuleRef module, const char *str, int len);
|
LLVMValueRef lp_build_const_string_variable(LLVMModuleRef module, const char *str, int len);
|
||||||
LLVMValueRef lp_build_printf(LLVMBuilderRef builder, const char *fmt, ...);
|
LLVMValueRef lp_build_printf(LLVMBuilderRef builder, const char *fmt, ...);
|
||||||
|
|
||||||
|
LLVMValueRef
|
||||||
|
lp_build_print_vec4(LLVMBuilderRef builder, const char *msg, LLVMValueRef vec);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,11 +81,15 @@ LLVMValueRef
|
||||||
lp_build_scalar_ddx(struct lp_build_context *bld,
|
lp_build_scalar_ddx(struct lp_build_context *bld,
|
||||||
LLVMValueRef a)
|
LLVMValueRef a)
|
||||||
{
|
{
|
||||||
LLVMValueRef idx_left = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_TOP_LEFT, 0);
|
LLVMTypeRef i32t = LLVMInt32Type();
|
||||||
LLVMValueRef idx_right = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_TOP_RIGHT, 0);
|
LLVMValueRef idx_left = LLVMConstInt(i32t, LP_BLD_QUAD_TOP_LEFT, 0);
|
||||||
LLVMValueRef a_left = LLVMBuildExtractElement(bld->builder, a, idx_left, "");
|
LLVMValueRef idx_right = LLVMConstInt(i32t, LP_BLD_QUAD_TOP_RIGHT, 0);
|
||||||
LLVMValueRef a_right = LLVMBuildExtractElement(bld->builder, a, idx_right, "");
|
LLVMValueRef a_left = LLVMBuildExtractElement(bld->builder, a, idx_left, "left");
|
||||||
return lp_build_sub(bld, a_right, a_left);
|
LLVMValueRef a_right = LLVMBuildExtractElement(bld->builder, a, idx_right, "right");
|
||||||
|
if (bld->type.floating)
|
||||||
|
return LLVMBuildFSub(bld->builder, a_right, a_left, "ddx");
|
||||||
|
else
|
||||||
|
return LLVMBuildSub(bld->builder, a_right, a_left, "ddx");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -93,9 +97,13 @@ LLVMValueRef
|
||||||
lp_build_scalar_ddy(struct lp_build_context *bld,
|
lp_build_scalar_ddy(struct lp_build_context *bld,
|
||||||
LLVMValueRef a)
|
LLVMValueRef a)
|
||||||
{
|
{
|
||||||
LLVMValueRef idx_top = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_TOP_LEFT, 0);
|
LLVMTypeRef i32t = LLVMInt32Type();
|
||||||
LLVMValueRef idx_bottom = LLVMConstInt(LLVMInt32Type(), LP_BLD_QUAD_BOTTOM_LEFT, 0);
|
LLVMValueRef idx_top = LLVMConstInt(i32t, LP_BLD_QUAD_TOP_LEFT, 0);
|
||||||
LLVMValueRef a_top = LLVMBuildExtractElement(bld->builder, a, idx_top, "");
|
LLVMValueRef idx_bottom = LLVMConstInt(i32t, LP_BLD_QUAD_BOTTOM_LEFT, 0);
|
||||||
LLVMValueRef a_bottom = LLVMBuildExtractElement(bld->builder, a, idx_bottom, "");
|
LLVMValueRef a_top = LLVMBuildExtractElement(bld->builder, a, idx_top, "top");
|
||||||
return lp_build_sub(bld, a_bottom, a_top);
|
LLVMValueRef a_bottom = LLVMBuildExtractElement(bld->builder, a, idx_bottom, "bottom");
|
||||||
|
if (bld->type.floating)
|
||||||
|
return LLVMBuildFSub(bld->builder, a_bottom, a_top, "ddy");
|
||||||
|
else
|
||||||
|
return LLVMBuildSub(bld->builder, a_bottom, a_top, "ddy");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,7 @@
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bri-linear factor. Use zero or any other number less than one to force
|
* Bri-linear factor. Should be greater than one.
|
||||||
* tri-linear filtering.
|
|
||||||
*/
|
*/
|
||||||
#define BRILINEAR_FACTOR 2
|
#define BRILINEAR_FACTOR 2
|
||||||
|
|
||||||
|
|
@ -201,8 +200,8 @@ lp_build_rho(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef float_size;
|
LLVMValueRef float_size;
|
||||||
LLVMValueRef rho;
|
LLVMValueRef rho;
|
||||||
|
|
||||||
dsdx = LLVMBuildExtractElement(bld->builder, ddx[0], index0, "dsdx");
|
dsdx = ddx[0];
|
||||||
dsdy = LLVMBuildExtractElement(bld->builder, ddy[0], index0, "dsdy");
|
dsdy = ddy[0];
|
||||||
|
|
||||||
if (dims <= 1) {
|
if (dims <= 1) {
|
||||||
rho_x = dsdx;
|
rho_x = dsdx;
|
||||||
|
|
@ -215,15 +214,15 @@ lp_build_rho(struct lp_build_sample_context *bld,
|
||||||
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, dsdx, index0, "");
|
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, dsdx, index0, "");
|
||||||
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, dsdy, index0, "");
|
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, dsdy, index0, "");
|
||||||
|
|
||||||
dtdx = LLVMBuildExtractElement(bld->builder, ddx[1], index0, "dtdx");
|
dtdx = ddx[1];
|
||||||
dtdy = LLVMBuildExtractElement(bld->builder, ddy[1], index0, "dtdy");
|
dtdy = ddy[1];
|
||||||
|
|
||||||
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, dtdx, index1, "");
|
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, dtdx, index1, "");
|
||||||
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, dtdy, index1, "");
|
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, dtdy, index1, "");
|
||||||
|
|
||||||
if (dims >= 3) {
|
if (dims >= 3) {
|
||||||
drdx = LLVMBuildExtractElement(bld->builder, ddx[2], index0, "drdx");
|
drdx = ddx[2];
|
||||||
drdy = LLVMBuildExtractElement(bld->builder, ddy[2], index0, "drdy");
|
drdy = ddy[2];
|
||||||
|
|
||||||
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, drdx, index2, "");
|
rho_x = LLVMBuildInsertElement(bld->builder, rho_x, drdx, index2, "");
|
||||||
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, drdy, index2, "");
|
rho_y = LLVMBuildInsertElement(bld->builder, rho_y, drdy, index2, "");
|
||||||
|
|
@ -294,31 +293,30 @@ lp_build_rho(struct lp_build_sample_context *bld,
|
||||||
* TODO: This could be done in fixed point, where applicable.
|
* TODO: This could be done in fixed point, where applicable.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
lp_build_brilinear_lod(struct lp_build_sample_context *bld,
|
lp_build_brilinear_lod(struct lp_build_context *bld,
|
||||||
LLVMValueRef lod,
|
LLVMValueRef lod,
|
||||||
double factor,
|
double factor,
|
||||||
LLVMValueRef *out_lod_ipart,
|
LLVMValueRef *out_lod_ipart,
|
||||||
LLVMValueRef *out_lod_fpart)
|
LLVMValueRef *out_lod_fpart)
|
||||||
{
|
{
|
||||||
struct lp_build_context *float_bld = &bld->float_bld;
|
|
||||||
LLVMValueRef lod_fpart;
|
LLVMValueRef lod_fpart;
|
||||||
float pre_offset = (factor - 0.5)/factor - 0.5;
|
double pre_offset = (factor - 0.5)/factor - 0.5;
|
||||||
float post_offset = 1 - factor;
|
double post_offset = 1 - factor;
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
lp_build_printf(bld->builder, "lod = %f\n", lod);
|
lp_build_printf(bld->builder, "lod = %f\n", lod);
|
||||||
}
|
}
|
||||||
|
|
||||||
lod = lp_build_add(float_bld, lod,
|
lod = lp_build_add(bld, lod,
|
||||||
lp_build_const_vec(float_bld->type, pre_offset));
|
lp_build_const_vec(bld->type, pre_offset));
|
||||||
|
|
||||||
lp_build_ifloor_fract(float_bld, lod, out_lod_ipart, &lod_fpart);
|
lp_build_ifloor_fract(bld, lod, out_lod_ipart, &lod_fpart);
|
||||||
|
|
||||||
lod_fpart = lp_build_mul(float_bld, lod_fpart,
|
lod_fpart = lp_build_mul(bld, lod_fpart,
|
||||||
lp_build_const_vec(float_bld->type, factor));
|
lp_build_const_vec(bld->type, factor));
|
||||||
|
|
||||||
lod_fpart = lp_build_add(float_bld, lod_fpart,
|
lod_fpart = lp_build_add(bld, lod_fpart,
|
||||||
lp_build_const_vec(float_bld->type, post_offset));
|
lp_build_const_vec(bld->type, post_offset));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's not necessary to clamp lod_fpart since:
|
* It's not necessary to clamp lod_fpart since:
|
||||||
|
|
@ -335,6 +333,61 @@ lp_build_brilinear_lod(struct lp_build_sample_context *bld,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Combined log2 and brilinear lod computation.
|
||||||
|
*
|
||||||
|
* It's in all identical to calling lp_build_fast_log2() and
|
||||||
|
* lp_build_brilinear_lod() above, but by combining we can compute the interger
|
||||||
|
* and fractional part independently.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
lp_build_brilinear_rho(struct lp_build_context *bld,
|
||||||
|
LLVMValueRef rho,
|
||||||
|
double factor,
|
||||||
|
LLVMValueRef *out_lod_ipart,
|
||||||
|
LLVMValueRef *out_lod_fpart)
|
||||||
|
{
|
||||||
|
LLVMValueRef lod_ipart;
|
||||||
|
LLVMValueRef lod_fpart;
|
||||||
|
|
||||||
|
const double pre_factor = (2*factor - 0.5)/(M_SQRT2*factor);
|
||||||
|
const double post_offset = 1 - 2*factor;
|
||||||
|
|
||||||
|
assert(bld->type.floating);
|
||||||
|
|
||||||
|
assert(lp_check_value(bld->type, rho));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The pre factor will make the intersections with the exact powers of two
|
||||||
|
* happen precisely where we want then to be, which means that the integer
|
||||||
|
* part will not need any post adjustments.
|
||||||
|
*/
|
||||||
|
rho = lp_build_mul(bld, rho,
|
||||||
|
lp_build_const_vec(bld->type, pre_factor));
|
||||||
|
|
||||||
|
/* ipart = ifloor(log2(rho)) */
|
||||||
|
lod_ipart = lp_build_extract_exponent(bld, rho, 0);
|
||||||
|
|
||||||
|
/* fpart = rho / 2**ipart */
|
||||||
|
lod_fpart = lp_build_extract_mantissa(bld, rho);
|
||||||
|
|
||||||
|
lod_fpart = lp_build_mul(bld, lod_fpart,
|
||||||
|
lp_build_const_vec(bld->type, factor));
|
||||||
|
|
||||||
|
lod_fpart = lp_build_add(bld, lod_fpart,
|
||||||
|
lp_build_const_vec(bld->type, post_offset));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like lp_build_brilinear_lod, it's not necessary to clamp lod_fpart since:
|
||||||
|
* - the above expression will never produce numbers greater than one.
|
||||||
|
* - the mip filtering branch is only taken if lod_fpart is positive
|
||||||
|
*/
|
||||||
|
|
||||||
|
*out_lod_ipart = lod_ipart;
|
||||||
|
*out_lod_fpart = lod_fpart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate code to compute texture level of detail (lambda).
|
* Generate code to compute texture level of detail (lambda).
|
||||||
* \param ddx partial derivatives of (s, t, r, q) with respect to X
|
* \param ddx partial derivatives of (s, t, r, q) with respect to X
|
||||||
|
|
@ -389,17 +442,33 @@ lp_build_lod_selector(struct lp_build_sample_context *bld,
|
||||||
|
|
||||||
rho = lp_build_rho(bld, ddx, ddy);
|
rho = lp_build_rho(bld, ddx, ddy);
|
||||||
|
|
||||||
/* compute lod = log2(rho) */
|
/*
|
||||||
if ((mip_filter == PIPE_TEX_MIPFILTER_NONE ||
|
* Compute lod = log2(rho)
|
||||||
mip_filter == PIPE_TEX_MIPFILTER_NEAREST) &&
|
*/
|
||||||
!lod_bias &&
|
|
||||||
|
if (!lod_bias &&
|
||||||
!bld->static_state->lod_bias_non_zero &&
|
!bld->static_state->lod_bias_non_zero &&
|
||||||
!bld->static_state->apply_max_lod &&
|
!bld->static_state->apply_max_lod &&
|
||||||
!bld->static_state->apply_min_lod) {
|
!bld->static_state->apply_min_lod) {
|
||||||
|
/*
|
||||||
|
* Special case when there are no post-log2 adjustments, which
|
||||||
|
* saves instructions but keeping the integer and fractional lod
|
||||||
|
* computations separate from the start.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (mip_filter == PIPE_TEX_MIPFILTER_NONE ||
|
||||||
|
mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
|
||||||
*out_lod_ipart = lp_build_ilog2(float_bld, rho);
|
*out_lod_ipart = lp_build_ilog2(float_bld, rho);
|
||||||
*out_lod_fpart = bld->float_bld.zero;
|
*out_lod_fpart = bld->float_bld.zero;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR &&
|
||||||
|
!(gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR)) {
|
||||||
|
lp_build_brilinear_rho(float_bld, rho, BRILINEAR_FACTOR,
|
||||||
|
out_lod_ipart, out_lod_fpart);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
lod = lp_build_log2(float_bld, rho);
|
lod = lp_build_log2(float_bld, rho);
|
||||||
|
|
@ -437,21 +506,22 @@ lp_build_lod_selector(struct lp_build_sample_context *bld,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
|
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
|
||||||
if (BRILINEAR_FACTOR > 1.0) {
|
if (!(gallivm_debug & GALLIVM_DEBUG_NO_BRILINEAR)) {
|
||||||
lp_build_brilinear_lod(bld, lod, BRILINEAR_FACTOR,
|
lp_build_brilinear_lod(float_bld, lod, BRILINEAR_FACTOR,
|
||||||
out_lod_ipart, out_lod_fpart);
|
out_lod_ipart, out_lod_fpart);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lp_build_ifloor_fract(float_bld, lod, out_lod_ipart, out_lod_fpart);
|
lp_build_ifloor_fract(float_bld, lod, out_lod_ipart, out_lod_fpart);
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_build_name(*out_lod_ipart, "lod_ipart");
|
|
||||||
lp_build_name(*out_lod_fpart, "lod_fpart");
|
lp_build_name(*out_lod_fpart, "lod_fpart");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*out_lod_ipart = lp_build_iround(float_bld, lod);
|
*out_lod_ipart = lp_build_iround(float_bld, lod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lp_build_name(*out_lod_ipart, "lod_ipart");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -630,37 +700,21 @@ lp_build_get_level_stride_vec(struct lp_build_sample_context *bld,
|
||||||
void
|
void
|
||||||
lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
|
lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef ilevel,
|
LLVMValueRef ilevel,
|
||||||
LLVMValueRef *out_width_vec,
|
LLVMValueRef *out_size,
|
||||||
LLVMValueRef *out_height_vec,
|
|
||||||
LLVMValueRef *out_depth_vec,
|
|
||||||
LLVMValueRef *row_stride_vec,
|
LLVMValueRef *row_stride_vec,
|
||||||
LLVMValueRef *img_stride_vec)
|
LLVMValueRef *img_stride_vec)
|
||||||
{
|
{
|
||||||
const unsigned dims = bld->dims;
|
const unsigned dims = bld->dims;
|
||||||
LLVMValueRef ilevel_vec;
|
LLVMValueRef ilevel_vec;
|
||||||
LLVMValueRef size_vec;
|
|
||||||
LLVMTypeRef i32t = LLVMInt32Type();
|
|
||||||
|
|
||||||
ilevel_vec = lp_build_broadcast_scalar(&bld->int_size_bld, ilevel);
|
ilevel_vec = lp_build_broadcast_scalar(&bld->int_size_bld, ilevel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute width, height, depth at mipmap level 'ilevel'
|
* Compute width, height, depth at mipmap level 'ilevel'
|
||||||
*/
|
*/
|
||||||
size_vec = lp_build_minify(&bld->int_size_bld, bld->int_size, ilevel_vec);
|
*out_size = lp_build_minify(&bld->int_size_bld, bld->int_size, ilevel_vec);
|
||||||
|
|
||||||
*out_width_vec = lp_build_extract_broadcast(bld->builder,
|
|
||||||
bld->int_size_type,
|
|
||||||
bld->int_coord_type,
|
|
||||||
size_vec,
|
|
||||||
LLVMConstInt(i32t, 0, 0));
|
|
||||||
if (dims >= 2) {
|
if (dims >= 2) {
|
||||||
|
|
||||||
*out_height_vec = lp_build_extract_broadcast(bld->builder,
|
|
||||||
bld->int_size_type,
|
|
||||||
bld->int_coord_type,
|
|
||||||
size_vec,
|
|
||||||
LLVMConstInt(i32t, 1, 0));
|
|
||||||
|
|
||||||
*row_stride_vec = lp_build_get_level_stride_vec(bld,
|
*row_stride_vec = lp_build_get_level_stride_vec(bld,
|
||||||
bld->row_stride_array,
|
bld->row_stride_array,
|
||||||
ilevel);
|
ilevel);
|
||||||
|
|
@ -668,18 +722,90 @@ lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
|
||||||
*img_stride_vec = lp_build_get_level_stride_vec(bld,
|
*img_stride_vec = lp_build_get_level_stride_vec(bld,
|
||||||
bld->img_stride_array,
|
bld->img_stride_array,
|
||||||
ilevel);
|
ilevel);
|
||||||
if (dims == 3) {
|
|
||||||
*out_depth_vec = lp_build_extract_broadcast(bld->builder,
|
|
||||||
bld->int_size_type,
|
|
||||||
bld->int_coord_type,
|
|
||||||
size_vec,
|
|
||||||
LLVMConstInt(i32t, 2, 0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract and broadcast texture size.
|
||||||
|
*
|
||||||
|
* @param size_type type of the texture size vector (either
|
||||||
|
* bld->int_size_type or bld->float_size_type)
|
||||||
|
* @param coord_type type of the texture size vector (either
|
||||||
|
* bld->int_coord_type or bld->coord_type)
|
||||||
|
* @param int_size vector with the integer texture size (width, height,
|
||||||
|
* depth)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lp_build_extract_image_sizes(struct lp_build_sample_context *bld,
|
||||||
|
struct lp_type size_type,
|
||||||
|
struct lp_type coord_type,
|
||||||
|
LLVMValueRef size,
|
||||||
|
LLVMValueRef *out_width,
|
||||||
|
LLVMValueRef *out_height,
|
||||||
|
LLVMValueRef *out_depth)
|
||||||
|
{
|
||||||
|
const unsigned dims = bld->dims;
|
||||||
|
LLVMTypeRef i32t = LLVMInt32Type();
|
||||||
|
|
||||||
|
*out_width = lp_build_extract_broadcast(bld->builder,
|
||||||
|
size_type,
|
||||||
|
coord_type,
|
||||||
|
size,
|
||||||
|
LLVMConstInt(i32t, 0, 0));
|
||||||
|
if (dims >= 2) {
|
||||||
|
*out_height = lp_build_extract_broadcast(bld->builder,
|
||||||
|
size_type,
|
||||||
|
coord_type,
|
||||||
|
size,
|
||||||
|
LLVMConstInt(i32t, 1, 0));
|
||||||
|
if (dims == 3) {
|
||||||
|
*out_depth = lp_build_extract_broadcast(bld->builder,
|
||||||
|
size_type,
|
||||||
|
coord_type,
|
||||||
|
size,
|
||||||
|
LLVMConstInt(i32t, 2, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unnormalize coords.
|
||||||
|
*
|
||||||
|
* @param int_size vector with the integer texture size (width, height, depth)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lp_build_unnormalized_coords(struct lp_build_sample_context *bld,
|
||||||
|
LLVMValueRef flt_size,
|
||||||
|
LLVMValueRef *s,
|
||||||
|
LLVMValueRef *t,
|
||||||
|
LLVMValueRef *r)
|
||||||
|
{
|
||||||
|
const unsigned dims = bld->dims;
|
||||||
|
LLVMValueRef width;
|
||||||
|
LLVMValueRef height;
|
||||||
|
LLVMValueRef depth;
|
||||||
|
|
||||||
|
lp_build_extract_image_sizes(bld,
|
||||||
|
bld->float_size_type,
|
||||||
|
bld->coord_type,
|
||||||
|
flt_size,
|
||||||
|
&width,
|
||||||
|
&height,
|
||||||
|
&depth);
|
||||||
|
|
||||||
|
/* s = s * width, t = t * height */
|
||||||
|
*s = lp_build_mul(&bld->coord_bld, *s, width);
|
||||||
|
if (dims >= 2) {
|
||||||
|
*t = lp_build_mul(&bld->coord_bld, *t, height);
|
||||||
|
if (dims >= 3) {
|
||||||
|
*r = lp_build_mul(&bld->coord_bld, *r, depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Helper used by lp_build_cube_lookup() */
|
/** Helper used by lp_build_cube_lookup() */
|
||||||
static LLVMValueRef
|
static LLVMValueRef
|
||||||
|
|
@ -798,25 +924,16 @@ lp_build_cube_lookup(struct lp_build_sample_context *bld,
|
||||||
rz_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, rz, float_bld->zero, "");
|
rz_pos = LLVMBuildFCmp(bld->builder, LLVMRealUGE, rz, float_bld->zero, "");
|
||||||
|
|
||||||
{
|
{
|
||||||
struct lp_build_flow_context *flow_ctx;
|
|
||||||
struct lp_build_if_state if_ctx;
|
struct lp_build_if_state if_ctx;
|
||||||
|
LLVMValueRef face_s_var;
|
||||||
|
LLVMValueRef face_t_var;
|
||||||
|
LLVMValueRef face_var;
|
||||||
|
|
||||||
flow_ctx = lp_build_flow_create(bld->builder);
|
face_s_var = lp_build_alloca(bld->builder, bld->coord_bld.vec_type, "face_s_var");
|
||||||
lp_build_flow_scope_begin(flow_ctx);
|
face_t_var = lp_build_alloca(bld->builder, bld->coord_bld.vec_type, "face_t_var");
|
||||||
|
face_var = lp_build_alloca(bld->builder, bld->int_bld.vec_type, "face_var");
|
||||||
|
|
||||||
*face_s = bld->coord_bld.undef;
|
lp_build_if(&if_ctx, bld->builder, arx_ge_ary_arz);
|
||||||
*face_t = bld->coord_bld.undef;
|
|
||||||
*face = bld->int_bld.undef;
|
|
||||||
|
|
||||||
lp_build_name(*face_s, "face_s");
|
|
||||||
lp_build_name(*face_t, "face_t");
|
|
||||||
lp_build_name(*face, "face");
|
|
||||||
|
|
||||||
lp_build_flow_scope_declare(flow_ctx, face_s);
|
|
||||||
lp_build_flow_scope_declare(flow_ctx, face_t);
|
|
||||||
lp_build_flow_scope_declare(flow_ctx, face);
|
|
||||||
|
|
||||||
lp_build_if(&if_ctx, flow_ctx, bld->builder, arx_ge_ary_arz);
|
|
||||||
{
|
{
|
||||||
/* +/- X face */
|
/* +/- X face */
|
||||||
LLVMValueRef sign = lp_build_sgn(float_bld, rx);
|
LLVMValueRef sign = lp_build_sgn(float_bld, rx);
|
||||||
|
|
@ -826,57 +943,52 @@ lp_build_cube_lookup(struct lp_build_sample_context *bld,
|
||||||
*face = lp_build_cube_face(bld, rx,
|
*face = lp_build_cube_face(bld, rx,
|
||||||
PIPE_TEX_FACE_POS_X,
|
PIPE_TEX_FACE_POS_X,
|
||||||
PIPE_TEX_FACE_NEG_X);
|
PIPE_TEX_FACE_NEG_X);
|
||||||
|
LLVMBuildStore(bld->builder, *face_s, face_s_var);
|
||||||
|
LLVMBuildStore(bld->builder, *face_t, face_t_var);
|
||||||
|
LLVMBuildStore(bld->builder, *face, face_var);
|
||||||
}
|
}
|
||||||
lp_build_else(&if_ctx);
|
lp_build_else(&if_ctx);
|
||||||
{
|
{
|
||||||
struct lp_build_flow_context *flow_ctx2;
|
|
||||||
struct lp_build_if_state if_ctx2;
|
struct lp_build_if_state if_ctx2;
|
||||||
|
|
||||||
LLVMValueRef face_s2 = bld->coord_bld.undef;
|
|
||||||
LLVMValueRef face_t2 = bld->coord_bld.undef;
|
|
||||||
LLVMValueRef face2 = bld->int_bld.undef;
|
|
||||||
|
|
||||||
flow_ctx2 = lp_build_flow_create(bld->builder);
|
|
||||||
lp_build_flow_scope_begin(flow_ctx2);
|
|
||||||
lp_build_flow_scope_declare(flow_ctx2, &face_s2);
|
|
||||||
lp_build_flow_scope_declare(flow_ctx2, &face_t2);
|
|
||||||
lp_build_flow_scope_declare(flow_ctx2, &face2);
|
|
||||||
|
|
||||||
ary_ge_arx_arz = LLVMBuildAnd(bld->builder, ary_ge_arx, ary_ge_arz, "");
|
ary_ge_arx_arz = LLVMBuildAnd(bld->builder, ary_ge_arx, ary_ge_arz, "");
|
||||||
|
|
||||||
lp_build_if(&if_ctx2, flow_ctx2, bld->builder, ary_ge_arx_arz);
|
lp_build_if(&if_ctx2, bld->builder, ary_ge_arx_arz);
|
||||||
{
|
{
|
||||||
/* +/- Y face */
|
/* +/- Y face */
|
||||||
LLVMValueRef sign = lp_build_sgn(float_bld, ry);
|
LLVMValueRef sign = lp_build_sgn(float_bld, ry);
|
||||||
LLVMValueRef ima = lp_build_cube_ima(coord_bld, t);
|
LLVMValueRef ima = lp_build_cube_ima(coord_bld, t);
|
||||||
face_s2 = lp_build_cube_coord(coord_bld, NULL, -1, s, ima);
|
*face_s = lp_build_cube_coord(coord_bld, NULL, -1, s, ima);
|
||||||
face_t2 = lp_build_cube_coord(coord_bld, sign, -1, r, ima);
|
*face_t = lp_build_cube_coord(coord_bld, sign, -1, r, ima);
|
||||||
face2 = lp_build_cube_face(bld, ry,
|
*face = lp_build_cube_face(bld, ry,
|
||||||
PIPE_TEX_FACE_POS_Y,
|
PIPE_TEX_FACE_POS_Y,
|
||||||
PIPE_TEX_FACE_NEG_Y);
|
PIPE_TEX_FACE_NEG_Y);
|
||||||
|
LLVMBuildStore(bld->builder, *face_s, face_s_var);
|
||||||
|
LLVMBuildStore(bld->builder, *face_t, face_t_var);
|
||||||
|
LLVMBuildStore(bld->builder, *face, face_var);
|
||||||
}
|
}
|
||||||
lp_build_else(&if_ctx2);
|
lp_build_else(&if_ctx2);
|
||||||
{
|
{
|
||||||
/* +/- Z face */
|
/* +/- Z face */
|
||||||
LLVMValueRef sign = lp_build_sgn(float_bld, rz);
|
LLVMValueRef sign = lp_build_sgn(float_bld, rz);
|
||||||
LLVMValueRef ima = lp_build_cube_ima(coord_bld, r);
|
LLVMValueRef ima = lp_build_cube_ima(coord_bld, r);
|
||||||
face_s2 = lp_build_cube_coord(coord_bld, sign, -1, s, ima);
|
*face_s = lp_build_cube_coord(coord_bld, sign, -1, s, ima);
|
||||||
face_t2 = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
|
*face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
|
||||||
face2 = lp_build_cube_face(bld, rz,
|
*face = lp_build_cube_face(bld, rz,
|
||||||
PIPE_TEX_FACE_POS_Z,
|
PIPE_TEX_FACE_POS_Z,
|
||||||
PIPE_TEX_FACE_NEG_Z);
|
PIPE_TEX_FACE_NEG_Z);
|
||||||
|
LLVMBuildStore(bld->builder, *face_s, face_s_var);
|
||||||
|
LLVMBuildStore(bld->builder, *face_t, face_t_var);
|
||||||
|
LLVMBuildStore(bld->builder, *face, face_var);
|
||||||
}
|
}
|
||||||
lp_build_endif(&if_ctx2);
|
lp_build_endif(&if_ctx2);
|
||||||
lp_build_flow_scope_end(flow_ctx2);
|
|
||||||
lp_build_flow_destroy(flow_ctx2);
|
|
||||||
*face_s = face_s2;
|
|
||||||
*face_t = face_t2;
|
|
||||||
*face = face2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_build_endif(&if_ctx);
|
lp_build_endif(&if_ctx);
|
||||||
lp_build_flow_scope_end(flow_ctx);
|
|
||||||
lp_build_flow_destroy(flow_ctx);
|
*face_s = LLVMBuildLoad(bld->builder, face_s_var, "face_s");
|
||||||
|
*face_t = LLVMBuildLoad(bld->builder, face_t_var, "face_t");
|
||||||
|
*face = LLVMBuildLoad(bld->builder, face_var, "face");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -197,10 +197,6 @@ struct lp_build_sample_context
|
||||||
struct lp_type coord_type;
|
struct lp_type coord_type;
|
||||||
struct lp_build_context coord_bld;
|
struct lp_build_context coord_bld;
|
||||||
|
|
||||||
/** Unsigned integer coordinates */
|
|
||||||
struct lp_type uint_coord_type;
|
|
||||||
struct lp_build_context uint_coord_bld;
|
|
||||||
|
|
||||||
/** Signed integer coordinates */
|
/** Signed integer coordinates */
|
||||||
struct lp_type int_coord_type;
|
struct lp_type int_coord_type;
|
||||||
struct lp_build_context int_coord_bld;
|
struct lp_build_context int_coord_bld;
|
||||||
|
|
@ -333,13 +329,29 @@ lp_build_get_const_mipmap_level(struct lp_build_sample_context *bld,
|
||||||
void
|
void
|
||||||
lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
|
lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef ilevel,
|
LLVMValueRef ilevel,
|
||||||
LLVMValueRef *out_width_vec,
|
LLVMValueRef *out_size_vec,
|
||||||
LLVMValueRef *out_height_vec,
|
|
||||||
LLVMValueRef *out_depth_vec,
|
|
||||||
LLVMValueRef *row_stride_vec,
|
LLVMValueRef *row_stride_vec,
|
||||||
LLVMValueRef *img_stride_vec);
|
LLVMValueRef *img_stride_vec);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_extract_image_sizes(struct lp_build_sample_context *bld,
|
||||||
|
struct lp_type size_type,
|
||||||
|
struct lp_type coord_type,
|
||||||
|
LLVMValueRef size,
|
||||||
|
LLVMValueRef *out_width,
|
||||||
|
LLVMValueRef *out_height,
|
||||||
|
LLVMValueRef *out_depth);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_unnormalized_coords(struct lp_build_sample_context *bld,
|
||||||
|
LLVMValueRef flt_size,
|
||||||
|
LLVMValueRef *s,
|
||||||
|
LLVMValueRef *t,
|
||||||
|
LLVMValueRef *r);
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_cube_lookup(struct lp_build_sample_context *bld,
|
lp_build_cube_lookup(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef s,
|
LLVMValueRef s,
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
#include "lp_bld_const.h"
|
#include "lp_bld_const.h"
|
||||||
#include "lp_bld_conv.h"
|
#include "lp_bld_conv.h"
|
||||||
#include "lp_bld_arit.h"
|
#include "lp_bld_arit.h"
|
||||||
|
#include "lp_bld_bitarit.h"
|
||||||
#include "lp_bld_logic.h"
|
#include "lp_bld_logic.h"
|
||||||
#include "lp_bld_swizzle.h"
|
#include "lp_bld_swizzle.h"
|
||||||
#include "lp_bld_pack.h"
|
#include "lp_bld_pack.h"
|
||||||
|
|
@ -80,11 +81,10 @@ lp_build_sample_wrap_nearest_int(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef *out_offset,
|
LLVMValueRef *out_offset,
|
||||||
LLVMValueRef *out_i)
|
LLVMValueRef *out_i)
|
||||||
{
|
{
|
||||||
struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
|
|
||||||
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
||||||
LLVMValueRef length_minus_one;
|
LLVMValueRef length_minus_one;
|
||||||
|
|
||||||
length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one);
|
length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
|
||||||
|
|
||||||
switch(wrap_mode) {
|
switch(wrap_mode) {
|
||||||
case PIPE_TEX_WRAP_REPEAT:
|
case PIPE_TEX_WRAP_REPEAT:
|
||||||
|
|
@ -92,7 +92,7 @@ lp_build_sample_wrap_nearest_int(struct lp_build_sample_context *bld,
|
||||||
coord = LLVMBuildAnd(bld->builder, coord, length_minus_one, "");
|
coord = LLVMBuildAnd(bld->builder, coord, length_minus_one, "");
|
||||||
else {
|
else {
|
||||||
/* Add a bias to the texcoord to handle negative coords */
|
/* Add a bias to the texcoord to handle negative coords */
|
||||||
LLVMValueRef bias = lp_build_mul_imm(uint_coord_bld, length, 1024);
|
LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
|
||||||
coord = LLVMBuildAdd(bld->builder, coord, bias, "");
|
coord = LLVMBuildAdd(bld->builder, coord, bias, "");
|
||||||
coord = LLVMBuildURem(bld->builder, coord, length, "");
|
coord = LLVMBuildURem(bld->builder, coord, length, "");
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +113,7 @@ lp_build_sample_wrap_nearest_int(struct lp_build_sample_context *bld,
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_build_sample_partial_offset(uint_coord_bld, block_length, coord, stride,
|
lp_build_sample_partial_offset(int_coord_bld, block_length, coord, stride,
|
||||||
out_offset, out_i);
|
out_offset, out_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,7 +146,6 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef *i0,
|
LLVMValueRef *i0,
|
||||||
LLVMValueRef *i1)
|
LLVMValueRef *i1)
|
||||||
{
|
{
|
||||||
struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
|
|
||||||
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
||||||
LLVMValueRef length_minus_one;
|
LLVMValueRef length_minus_one;
|
||||||
LLVMValueRef lmask, umask, mask;
|
LLVMValueRef lmask, umask, mask;
|
||||||
|
|
@ -188,8 +187,8 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
|
||||||
* multiplication.
|
* multiplication.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
*i0 = uint_coord_bld->zero;
|
*i0 = int_coord_bld->zero;
|
||||||
*i1 = uint_coord_bld->zero;
|
*i1 = int_coord_bld->zero;
|
||||||
|
|
||||||
length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
|
length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
|
||||||
|
|
||||||
|
|
@ -200,7 +199,7 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Add a bias to the texcoord to handle negative coords */
|
/* Add a bias to the texcoord to handle negative coords */
|
||||||
LLVMValueRef bias = lp_build_mul_imm(uint_coord_bld, length, 1024);
|
LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
|
||||||
coord0 = LLVMBuildAdd(bld->builder, coord0, bias, "");
|
coord0 = LLVMBuildAdd(bld->builder, coord0, bias, "");
|
||||||
coord0 = LLVMBuildURem(bld->builder, coord0, length, "");
|
coord0 = LLVMBuildURem(bld->builder, coord0, length, "");
|
||||||
}
|
}
|
||||||
|
|
@ -208,9 +207,9 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
|
||||||
mask = lp_build_compare(bld->builder, int_coord_bld->type,
|
mask = lp_build_compare(bld->builder, int_coord_bld->type,
|
||||||
PIPE_FUNC_NOTEQUAL, coord0, length_minus_one);
|
PIPE_FUNC_NOTEQUAL, coord0, length_minus_one);
|
||||||
|
|
||||||
*offset0 = lp_build_mul(uint_coord_bld, coord0, stride);
|
*offset0 = lp_build_mul(int_coord_bld, coord0, stride);
|
||||||
*offset1 = LLVMBuildAnd(bld->builder,
|
*offset1 = LLVMBuildAnd(bld->builder,
|
||||||
lp_build_add(uint_coord_bld, *offset0, stride),
|
lp_build_add(int_coord_bld, *offset0, stride),
|
||||||
mask, "");
|
mask, "");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -225,8 +224,8 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
|
||||||
|
|
||||||
mask = LLVMBuildAnd(bld->builder, lmask, umask, "");
|
mask = LLVMBuildAnd(bld->builder, lmask, umask, "");
|
||||||
|
|
||||||
*offset0 = lp_build_mul(uint_coord_bld, coord0, stride);
|
*offset0 = lp_build_mul(int_coord_bld, coord0, stride);
|
||||||
*offset1 = lp_build_add(uint_coord_bld,
|
*offset1 = lp_build_add(int_coord_bld,
|
||||||
*offset0,
|
*offset0,
|
||||||
LLVMBuildAnd(bld->builder, stride, mask, ""));
|
LLVMBuildAnd(bld->builder, stride, mask, ""));
|
||||||
break;
|
break;
|
||||||
|
|
@ -239,8 +238,8 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
|
||||||
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
|
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
*offset0 = uint_coord_bld->zero;
|
*offset0 = int_coord_bld->zero;
|
||||||
*offset1 = uint_coord_bld->zero;
|
*offset1 = int_coord_bld->zero;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -253,9 +252,7 @@ lp_build_sample_wrap_linear_int(struct lp_build_sample_context *bld,
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef width_vec,
|
LLVMValueRef int_size,
|
||||||
LLVMValueRef height_vec,
|
|
||||||
LLVMValueRef depth_vec,
|
|
||||||
LLVMValueRef row_stride_vec,
|
LLVMValueRef row_stride_vec,
|
||||||
LLVMValueRef img_stride_vec,
|
LLVMValueRef img_stride_vec,
|
||||||
LLVMValueRef data_ptr,
|
LLVMValueRef data_ptr,
|
||||||
|
|
@ -270,7 +267,8 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
struct lp_build_context i32, h16, u8n;
|
struct lp_build_context i32, h16, u8n;
|
||||||
LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type;
|
LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type;
|
||||||
LLVMValueRef i32_c8;
|
LLVMValueRef i32_c8;
|
||||||
LLVMValueRef s_ipart, t_ipart, r_ipart;
|
LLVMValueRef width_vec, height_vec, depth_vec;
|
||||||
|
LLVMValueRef s_ipart, t_ipart = NULL, r_ipart = NULL;
|
||||||
LLVMValueRef x_stride;
|
LLVMValueRef x_stride;
|
||||||
LLVMValueRef x_offset, offset;
|
LLVMValueRef x_offset, offset;
|
||||||
LLVMValueRef x_subcoord, y_subcoord, z_subcoord;
|
LLVMValueRef x_subcoord, y_subcoord, z_subcoord;
|
||||||
|
|
@ -283,30 +281,33 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
h16_vec_type = lp_build_vec_type(h16.type);
|
h16_vec_type = lp_build_vec_type(h16.type);
|
||||||
u8n_vec_type = lp_build_vec_type(u8n.type);
|
u8n_vec_type = lp_build_vec_type(u8n.type);
|
||||||
|
|
||||||
if (bld->static_state->normalized_coords) {
|
lp_build_extract_image_sizes(bld,
|
||||||
/* s = s * width, t = t * height */
|
bld->int_size_type,
|
||||||
LLVMTypeRef coord_vec_type = lp_build_vec_type(bld->coord_type);
|
bld->int_coord_type,
|
||||||
LLVMValueRef fp_width = LLVMBuildSIToFP(bld->builder, width_vec,
|
int_size,
|
||||||
coord_vec_type, "");
|
&width_vec,
|
||||||
s = lp_build_mul(&bld->coord_bld, s, fp_width);
|
&height_vec,
|
||||||
if (dims >= 2) {
|
&depth_vec);
|
||||||
LLVMValueRef fp_height = LLVMBuildSIToFP(bld->builder, height_vec,
|
|
||||||
coord_vec_type, "");
|
|
||||||
t = lp_build_mul(&bld->coord_bld, t, fp_height);
|
|
||||||
if (dims >= 3) {
|
|
||||||
LLVMValueRef fp_depth = LLVMBuildSIToFP(bld->builder, depth_vec,
|
|
||||||
coord_vec_type, "");
|
|
||||||
r = lp_build_mul(&bld->coord_bld, r, fp_depth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (bld->static_state->normalized_coords) {
|
||||||
|
LLVMValueRef scaled_size;
|
||||||
|
LLVMValueRef flt_size;
|
||||||
|
|
||||||
|
/* scale size by 256 (8 fractional bits) */
|
||||||
|
scaled_size = lp_build_shl_imm(&bld->int_size_bld, int_size, 8);
|
||||||
|
|
||||||
|
flt_size = lp_build_int_to_float(&bld->float_size_bld, scaled_size);
|
||||||
|
|
||||||
|
lp_build_unnormalized_coords(bld, flt_size, &s, &t, &r);
|
||||||
|
}
|
||||||
|
else {
|
||||||
/* scale coords by 256 (8 fractional bits) */
|
/* scale coords by 256 (8 fractional bits) */
|
||||||
s = lp_build_mul_imm(&bld->coord_bld, s, 256);
|
s = lp_build_mul_imm(&bld->coord_bld, s, 256);
|
||||||
if (dims >= 2)
|
if (dims >= 2)
|
||||||
t = lp_build_mul_imm(&bld->coord_bld, t, 256);
|
t = lp_build_mul_imm(&bld->coord_bld, t, 256);
|
||||||
if (dims >= 3)
|
if (dims >= 3)
|
||||||
r = lp_build_mul_imm(&bld->coord_bld, r, 256);
|
r = lp_build_mul_imm(&bld->coord_bld, r, 256);
|
||||||
|
}
|
||||||
|
|
||||||
/* convert float to int */
|
/* convert float to int */
|
||||||
s = LLVMBuildFPToSI(builder, s, i32_vec_type, "");
|
s = LLVMBuildFPToSI(builder, s, i32_vec_type, "");
|
||||||
|
|
@ -324,7 +325,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
r_ipart = LLVMBuildAShr(builder, r, i32_c8, "");
|
r_ipart = LLVMBuildAShr(builder, r, i32_c8, "");
|
||||||
|
|
||||||
/* get pixel, row, image strides */
|
/* get pixel, row, image strides */
|
||||||
x_stride = lp_build_const_vec(bld->uint_coord_bld.type,
|
x_stride = lp_build_const_vec(bld->int_coord_bld.type,
|
||||||
bld->format_desc->block.bits/8);
|
bld->format_desc->block.bits/8);
|
||||||
|
|
||||||
/* Do texcoord wrapping, compute texel offset */
|
/* Do texcoord wrapping, compute texel offset */
|
||||||
|
|
@ -343,7 +344,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
bld->static_state->pot_height,
|
bld->static_state->pot_height,
|
||||||
bld->static_state->wrap_t,
|
bld->static_state->wrap_t,
|
||||||
&y_offset, &y_subcoord);
|
&y_offset, &y_subcoord);
|
||||||
offset = lp_build_add(&bld->uint_coord_bld, offset, y_offset);
|
offset = lp_build_add(&bld->int_coord_bld, offset, y_offset);
|
||||||
if (dims >= 3) {
|
if (dims >= 3) {
|
||||||
LLVMValueRef z_offset;
|
LLVMValueRef z_offset;
|
||||||
lp_build_sample_wrap_nearest_int(bld,
|
lp_build_sample_wrap_nearest_int(bld,
|
||||||
|
|
@ -352,13 +353,13 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
bld->static_state->pot_height,
|
bld->static_state->pot_height,
|
||||||
bld->static_state->wrap_r,
|
bld->static_state->wrap_r,
|
||||||
&z_offset, &z_subcoord);
|
&z_offset, &z_subcoord);
|
||||||
offset = lp_build_add(&bld->uint_coord_bld, offset, z_offset);
|
offset = lp_build_add(&bld->int_coord_bld, offset, z_offset);
|
||||||
}
|
}
|
||||||
else if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
|
else if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
|
||||||
LLVMValueRef z_offset;
|
LLVMValueRef z_offset;
|
||||||
/* The r coord is the cube face in [0,5] */
|
/* The r coord is the cube face in [0,5] */
|
||||||
z_offset = lp_build_mul(&bld->uint_coord_bld, r, img_stride_vec);
|
z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
|
||||||
offset = lp_build_add(&bld->uint_coord_bld, offset, z_offset);
|
offset = lp_build_add(&bld->int_coord_bld, offset, z_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,9 +418,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef width_vec,
|
LLVMValueRef int_size,
|
||||||
LLVMValueRef height_vec,
|
|
||||||
LLVMValueRef depth_vec,
|
|
||||||
LLVMValueRef row_stride_vec,
|
LLVMValueRef row_stride_vec,
|
||||||
LLVMValueRef img_stride_vec,
|
LLVMValueRef img_stride_vec,
|
||||||
LLVMValueRef data_ptr,
|
LLVMValueRef data_ptr,
|
||||||
|
|
@ -434,9 +433,10 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
struct lp_build_context i32, h16, u8n;
|
struct lp_build_context i32, h16, u8n;
|
||||||
LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type;
|
LLVMTypeRef i32_vec_type, h16_vec_type, u8n_vec_type;
|
||||||
LLVMValueRef i32_c8, i32_c128, i32_c255;
|
LLVMValueRef i32_c8, i32_c128, i32_c255;
|
||||||
|
LLVMValueRef width_vec, height_vec, depth_vec;
|
||||||
LLVMValueRef s_ipart, s_fpart, s_fpart_lo, s_fpart_hi;
|
LLVMValueRef s_ipart, s_fpart, s_fpart_lo, s_fpart_hi;
|
||||||
LLVMValueRef t_ipart, t_fpart, t_fpart_lo, t_fpart_hi;
|
LLVMValueRef t_ipart = NULL, t_fpart = NULL, t_fpart_lo = NULL, t_fpart_hi = NULL;
|
||||||
LLVMValueRef r_ipart, r_fpart, r_fpart_lo, r_fpart_hi;
|
LLVMValueRef r_ipart = NULL, r_fpart = NULL, r_fpart_lo = NULL, r_fpart_hi = NULL;
|
||||||
LLVMValueRef x_stride, y_stride, z_stride;
|
LLVMValueRef x_stride, y_stride, z_stride;
|
||||||
LLVMValueRef x_offset0, x_offset1;
|
LLVMValueRef x_offset0, x_offset1;
|
||||||
LLVMValueRef y_offset0, y_offset1;
|
LLVMValueRef y_offset0, y_offset1;
|
||||||
|
|
@ -458,30 +458,33 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
h16_vec_type = lp_build_vec_type(h16.type);
|
h16_vec_type = lp_build_vec_type(h16.type);
|
||||||
u8n_vec_type = lp_build_vec_type(u8n.type);
|
u8n_vec_type = lp_build_vec_type(u8n.type);
|
||||||
|
|
||||||
if (bld->static_state->normalized_coords) {
|
lp_build_extract_image_sizes(bld,
|
||||||
/* s = s * width, t = t * height */
|
bld->int_size_type,
|
||||||
LLVMTypeRef coord_vec_type = lp_build_vec_type(bld->coord_type);
|
bld->int_coord_type,
|
||||||
LLVMValueRef fp_width = LLVMBuildSIToFP(bld->builder, width_vec,
|
int_size,
|
||||||
coord_vec_type, "");
|
&width_vec,
|
||||||
s = lp_build_mul(&bld->coord_bld, s, fp_width);
|
&height_vec,
|
||||||
if (dims >= 2) {
|
&depth_vec);
|
||||||
LLVMValueRef fp_height = LLVMBuildSIToFP(bld->builder, height_vec,
|
|
||||||
coord_vec_type, "");
|
|
||||||
t = lp_build_mul(&bld->coord_bld, t, fp_height);
|
|
||||||
}
|
|
||||||
if (dims >= 3) {
|
|
||||||
LLVMValueRef fp_depth = LLVMBuildSIToFP(bld->builder, depth_vec,
|
|
||||||
coord_vec_type, "");
|
|
||||||
r = lp_build_mul(&bld->coord_bld, r, fp_depth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (bld->static_state->normalized_coords) {
|
||||||
|
LLVMValueRef scaled_size;
|
||||||
|
LLVMValueRef flt_size;
|
||||||
|
|
||||||
|
/* scale size by 256 (8 fractional bits) */
|
||||||
|
scaled_size = lp_build_shl_imm(&bld->int_size_bld, int_size, 8);
|
||||||
|
|
||||||
|
flt_size = lp_build_int_to_float(&bld->float_size_bld, scaled_size);
|
||||||
|
|
||||||
|
lp_build_unnormalized_coords(bld, flt_size, &s, &t, &r);
|
||||||
|
}
|
||||||
|
else {
|
||||||
/* scale coords by 256 (8 fractional bits) */
|
/* scale coords by 256 (8 fractional bits) */
|
||||||
s = lp_build_mul_imm(&bld->coord_bld, s, 256);
|
s = lp_build_mul_imm(&bld->coord_bld, s, 256);
|
||||||
if (dims >= 2)
|
if (dims >= 2)
|
||||||
t = lp_build_mul_imm(&bld->coord_bld, t, 256);
|
t = lp_build_mul_imm(&bld->coord_bld, t, 256);
|
||||||
if (dims >= 3)
|
if (dims >= 3)
|
||||||
r = lp_build_mul_imm(&bld->coord_bld, r, 256);
|
r = lp_build_mul_imm(&bld->coord_bld, r, 256);
|
||||||
|
}
|
||||||
|
|
||||||
/* convert float to int */
|
/* convert float to int */
|
||||||
s = LLVMBuildFPToSI(builder, s, i32_vec_type, "");
|
s = LLVMBuildFPToSI(builder, s, i32_vec_type, "");
|
||||||
|
|
@ -517,7 +520,7 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
r_fpart = LLVMBuildAnd(builder, r, i32_c255, "");
|
r_fpart = LLVMBuildAnd(builder, r, i32_c255, "");
|
||||||
|
|
||||||
/* get pixel, row and image strides */
|
/* get pixel, row and image strides */
|
||||||
x_stride = lp_build_const_vec(bld->uint_coord_bld.type,
|
x_stride = lp_build_const_vec(bld->int_coord_bld.type,
|
||||||
bld->format_desc->block.bits/8);
|
bld->format_desc->block.bits/8);
|
||||||
y_stride = row_stride_vec;
|
y_stride = row_stride_vec;
|
||||||
z_stride = img_stride_vec;
|
z_stride = img_stride_vec;
|
||||||
|
|
@ -548,9 +551,9 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
|
|
||||||
for (z = 0; z < 2; z++) {
|
for (z = 0; z < 2; z++) {
|
||||||
for (x = 0; x < 2; x++) {
|
for (x = 0; x < 2; x++) {
|
||||||
offset[z][0][x] = lp_build_add(&bld->uint_coord_bld,
|
offset[z][0][x] = lp_build_add(&bld->int_coord_bld,
|
||||||
offset[z][0][x], y_offset0);
|
offset[z][0][x], y_offset0);
|
||||||
offset[z][1][x] = lp_build_add(&bld->uint_coord_bld,
|
offset[z][1][x] = lp_build_add(&bld->int_coord_bld,
|
||||||
offset[z][1][x], y_offset1);
|
offset[z][1][x], y_offset1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -566,20 +569,20 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
&z_subcoord[0], &z_subcoord[1]);
|
&z_subcoord[0], &z_subcoord[1]);
|
||||||
for (y = 0; y < 2; y++) {
|
for (y = 0; y < 2; y++) {
|
||||||
for (x = 0; x < 2; x++) {
|
for (x = 0; x < 2; x++) {
|
||||||
offset[0][y][x] = lp_build_add(&bld->uint_coord_bld,
|
offset[0][y][x] = lp_build_add(&bld->int_coord_bld,
|
||||||
offset[0][y][x], z_offset0);
|
offset[0][y][x], z_offset0);
|
||||||
offset[1][y][x] = lp_build_add(&bld->uint_coord_bld,
|
offset[1][y][x] = lp_build_add(&bld->int_coord_bld,
|
||||||
offset[1][y][x], z_offset1);
|
offset[1][y][x], z_offset1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
|
else if (bld->static_state->target == PIPE_TEXTURE_CUBE) {
|
||||||
LLVMValueRef z_offset;
|
LLVMValueRef z_offset;
|
||||||
z_offset = lp_build_mul(&bld->uint_coord_bld, r, img_stride_vec);
|
z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
|
||||||
for (y = 0; y < 2; y++) {
|
for (y = 0; y < 2; y++) {
|
||||||
for (x = 0; x < 2; x++) {
|
for (x = 0; x < 2; x++) {
|
||||||
/* The r coord is the cube face in [0,5] */
|
/* The r coord is the cube face in [0,5] */
|
||||||
offset[0][y][x] = lp_build_add(&bld->uint_coord_bld,
|
offset[0][y][x] = lp_build_add(&bld->int_coord_bld,
|
||||||
offset[0][y][x], z_offset);
|
offset[0][y][x], z_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -788,12 +791,8 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef colors_hi_var)
|
LLVMValueRef colors_hi_var)
|
||||||
{
|
{
|
||||||
LLVMBuilderRef builder = bld->builder;
|
LLVMBuilderRef builder = bld->builder;
|
||||||
LLVMValueRef width0_vec;
|
LLVMValueRef size0;
|
||||||
LLVMValueRef width1_vec;
|
LLVMValueRef size1;
|
||||||
LLVMValueRef height0_vec;
|
|
||||||
LLVMValueRef height1_vec;
|
|
||||||
LLVMValueRef depth0_vec;
|
|
||||||
LLVMValueRef depth1_vec;
|
|
||||||
LLVMValueRef row_stride0_vec;
|
LLVMValueRef row_stride0_vec;
|
||||||
LLVMValueRef row_stride1_vec;
|
LLVMValueRef row_stride1_vec;
|
||||||
LLVMValueRef img_stride0_vec;
|
LLVMValueRef img_stride0_vec;
|
||||||
|
|
@ -806,12 +805,12 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
|
|
||||||
/* sample the first mipmap level */
|
/* sample the first mipmap level */
|
||||||
lp_build_mipmap_level_sizes(bld, ilevel0,
|
lp_build_mipmap_level_sizes(bld, ilevel0,
|
||||||
&width0_vec, &height0_vec, &depth0_vec,
|
&size0,
|
||||||
&row_stride0_vec, &img_stride0_vec);
|
&row_stride0_vec, &img_stride0_vec);
|
||||||
data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
|
data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
|
||||||
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
|
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
|
||||||
lp_build_sample_image_nearest(bld,
|
lp_build_sample_image_nearest(bld,
|
||||||
width0_vec, height0_vec, depth0_vec,
|
size0,
|
||||||
row_stride0_vec, img_stride0_vec,
|
row_stride0_vec, img_stride0_vec,
|
||||||
data_ptr0, s, t, r,
|
data_ptr0, s, t, r,
|
||||||
&colors0_lo, &colors0_hi);
|
&colors0_lo, &colors0_hi);
|
||||||
|
|
@ -819,7 +818,7 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
else {
|
else {
|
||||||
assert(img_filter == PIPE_TEX_FILTER_LINEAR);
|
assert(img_filter == PIPE_TEX_FILTER_LINEAR);
|
||||||
lp_build_sample_image_linear(bld,
|
lp_build_sample_image_linear(bld,
|
||||||
width0_vec, height0_vec, depth0_vec,
|
size0,
|
||||||
row_stride0_vec, img_stride0_vec,
|
row_stride0_vec, img_stride0_vec,
|
||||||
data_ptr0, s, t, r,
|
data_ptr0, s, t, r,
|
||||||
&colors0_lo, &colors0_hi);
|
&colors0_lo, &colors0_hi);
|
||||||
|
|
@ -832,12 +831,9 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
|
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
|
||||||
LLVMValueRef h16_scale = LLVMConstReal(LLVMFloatType(), 256.0);
|
LLVMValueRef h16_scale = LLVMConstReal(LLVMFloatType(), 256.0);
|
||||||
LLVMTypeRef i32_type = LLVMIntType(32);
|
LLVMTypeRef i32_type = LLVMIntType(32);
|
||||||
struct lp_build_flow_context *flow_ctx;
|
|
||||||
struct lp_build_if_state if_ctx;
|
struct lp_build_if_state if_ctx;
|
||||||
LLVMValueRef need_lerp;
|
LLVMValueRef need_lerp;
|
||||||
|
|
||||||
flow_ctx = lp_build_flow_create(builder);
|
|
||||||
|
|
||||||
lod_fpart = LLVMBuildFMul(builder, lod_fpart, h16_scale, "");
|
lod_fpart = LLVMBuildFMul(builder, lod_fpart, h16_scale, "");
|
||||||
lod_fpart = LLVMBuildFPToSI(builder, lod_fpart, i32_type, "lod_fpart.fixed16");
|
lod_fpart = LLVMBuildFPToSI(builder, lod_fpart, i32_type, "lod_fpart.fixed16");
|
||||||
|
|
||||||
|
|
@ -846,7 +842,7 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
lod_fpart, LLVMConstNull(i32_type),
|
lod_fpart, LLVMConstNull(i32_type),
|
||||||
"need_lerp");
|
"need_lerp");
|
||||||
|
|
||||||
lp_build_if(&if_ctx, flow_ctx, builder, need_lerp);
|
lp_build_if(&if_ctx, builder, need_lerp);
|
||||||
{
|
{
|
||||||
struct lp_build_context h16_bld;
|
struct lp_build_context h16_bld;
|
||||||
|
|
||||||
|
|
@ -854,19 +850,19 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
|
|
||||||
/* sample the second mipmap level */
|
/* sample the second mipmap level */
|
||||||
lp_build_mipmap_level_sizes(bld, ilevel1,
|
lp_build_mipmap_level_sizes(bld, ilevel1,
|
||||||
&width1_vec, &height1_vec, &depth1_vec,
|
&size1,
|
||||||
&row_stride1_vec, &img_stride1_vec);
|
&row_stride1_vec, &img_stride1_vec);
|
||||||
data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
|
data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
|
||||||
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
|
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
|
||||||
lp_build_sample_image_nearest(bld,
|
lp_build_sample_image_nearest(bld,
|
||||||
width1_vec, height1_vec, depth1_vec,
|
size1,
|
||||||
row_stride1_vec, img_stride1_vec,
|
row_stride1_vec, img_stride1_vec,
|
||||||
data_ptr1, s, t, r,
|
data_ptr1, s, t, r,
|
||||||
&colors1_lo, &colors1_hi);
|
&colors1_lo, &colors1_hi);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lp_build_sample_image_linear(bld,
|
lp_build_sample_image_linear(bld,
|
||||||
width1_vec, height1_vec, depth1_vec,
|
size1,
|
||||||
row_stride1_vec, img_stride1_vec,
|
row_stride1_vec, img_stride1_vec,
|
||||||
data_ptr1, s, t, r,
|
data_ptr1, s, t, r,
|
||||||
&colors1_lo, &colors1_hi);
|
&colors1_lo, &colors1_hi);
|
||||||
|
|
@ -877,6 +873,26 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
lod_fpart = LLVMBuildTrunc(builder, lod_fpart, h16_bld.elem_type, "");
|
lod_fpart = LLVMBuildTrunc(builder, lod_fpart, h16_bld.elem_type, "");
|
||||||
lod_fpart = lp_build_broadcast_scalar(&h16_bld, lod_fpart);
|
lod_fpart = lp_build_broadcast_scalar(&h16_bld, lod_fpart);
|
||||||
|
|
||||||
|
#if HAVE_LLVM == 0x208
|
||||||
|
/* This is a work-around for a bug in LLVM 2.8.
|
||||||
|
* Evidently, something goes wrong in the construction of the
|
||||||
|
* lod_fpart short[8] vector. Adding this no-effect shuffle seems
|
||||||
|
* to force the vector to be properly constructed.
|
||||||
|
* Tested with mesa-demos/src/tests/mipmap_limits.c (press t, f).
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
LLVMValueRef shuffles[8], shuffle;
|
||||||
|
int i;
|
||||||
|
assert(h16_bld.type.length <= Elements(shuffles));
|
||||||
|
for (i = 0; i < h16_bld.type.length; i++)
|
||||||
|
shuffles[i] = lp_build_const_int32(2 * (i & 1));
|
||||||
|
shuffle = LLVMConstVector(shuffles, h16_bld.type.length);
|
||||||
|
lod_fpart = LLVMBuildShuffleVector(builder,
|
||||||
|
lod_fpart, lod_fpart,
|
||||||
|
shuffle, "");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
colors0_lo = lp_build_lerp(&h16_bld, lod_fpart,
|
colors0_lo = lp_build_lerp(&h16_bld, lod_fpart,
|
||||||
colors0_lo, colors1_lo);
|
colors0_lo, colors1_lo);
|
||||||
colors0_hi = lp_build_lerp(&h16_bld, lod_fpart,
|
colors0_hi = lp_build_lerp(&h16_bld, lod_fpart,
|
||||||
|
|
@ -886,8 +902,6 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
LLVMBuildStore(builder, colors0_hi, colors_hi_var);
|
LLVMBuildStore(builder, colors0_hi, colors_hi_var);
|
||||||
}
|
}
|
||||||
lp_build_endif(&if_ctx);
|
lp_build_endif(&if_ctx);
|
||||||
|
|
||||||
lp_build_flow_destroy(flow_ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -946,12 +960,12 @@ lp_build_sample_aos(struct lp_build_sample_context *bld,
|
||||||
r = lp_build_broadcast_scalar(&bld->int_coord_bld, face); /* vec */
|
r = lp_build_broadcast_scalar(&bld->int_coord_bld, face); /* vec */
|
||||||
|
|
||||||
/* recompute ddx, ddy using the new (s,t) face texcoords */
|
/* recompute ddx, ddy using the new (s,t) face texcoords */
|
||||||
face_ddx[0] = lp_build_ddx(&bld->coord_bld, s);
|
face_ddx[0] = lp_build_scalar_ddx(&bld->coord_bld, s);
|
||||||
face_ddx[1] = lp_build_ddx(&bld->coord_bld, t);
|
face_ddx[1] = lp_build_scalar_ddx(&bld->coord_bld, t);
|
||||||
face_ddx[2] = NULL;
|
face_ddx[2] = NULL;
|
||||||
face_ddx[3] = NULL;
|
face_ddx[3] = NULL;
|
||||||
face_ddy[0] = lp_build_ddy(&bld->coord_bld, s);
|
face_ddy[0] = lp_build_scalar_ddy(&bld->coord_bld, s);
|
||||||
face_ddy[1] = lp_build_ddy(&bld->coord_bld, t);
|
face_ddy[1] = lp_build_scalar_ddy(&bld->coord_bld, t);
|
||||||
face_ddy[2] = NULL;
|
face_ddy[2] = NULL;
|
||||||
face_ddy[3] = NULL;
|
face_ddy[3] = NULL;
|
||||||
ddx = face_ddx;
|
ddx = face_ddx;
|
||||||
|
|
@ -1027,17 +1041,14 @@ lp_build_sample_aos(struct lp_build_sample_context *bld,
|
||||||
/* Emit conditional to choose min image filter or mag image filter
|
/* Emit conditional to choose min image filter or mag image filter
|
||||||
* depending on the lod being > 0 or <= 0, respectively.
|
* depending on the lod being > 0 or <= 0, respectively.
|
||||||
*/
|
*/
|
||||||
struct lp_build_flow_context *flow_ctx;
|
|
||||||
struct lp_build_if_state if_ctx;
|
struct lp_build_if_state if_ctx;
|
||||||
LLVMValueRef minify;
|
LLVMValueRef minify;
|
||||||
|
|
||||||
flow_ctx = lp_build_flow_create(builder);
|
|
||||||
|
|
||||||
/* minify = lod >= 0.0 */
|
/* minify = lod >= 0.0 */
|
||||||
minify = LLVMBuildICmp(builder, LLVMIntSGE,
|
minify = LLVMBuildICmp(builder, LLVMIntSGE,
|
||||||
lod_ipart, int_bld->zero, "");
|
lod_ipart, int_bld->zero, "");
|
||||||
|
|
||||||
lp_build_if(&if_ctx, flow_ctx, builder, minify);
|
lp_build_if(&if_ctx, builder, minify);
|
||||||
{
|
{
|
||||||
/* Use the minification filter */
|
/* Use the minification filter */
|
||||||
lp_build_sample_mipmap(bld,
|
lp_build_sample_mipmap(bld,
|
||||||
|
|
@ -1056,8 +1067,6 @@ lp_build_sample_aos(struct lp_build_sample_context *bld,
|
||||||
packed_lo, packed_hi);
|
packed_lo, packed_hi);
|
||||||
}
|
}
|
||||||
lp_build_endif(&if_ctx);
|
lp_build_endif(&if_ctx);
|
||||||
|
|
||||||
lp_build_flow_destroy(flow_ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert x,y,z coords to linear offset from start of texture, in bytes */
|
/* convert x,y,z coords to linear offset from start of texture, in bytes */
|
||||||
lp_build_sample_offset(&bld->uint_coord_bld,
|
lp_build_sample_offset(&bld->int_coord_bld,
|
||||||
bld->format_desc,
|
bld->format_desc,
|
||||||
x, y, z, y_stride, z_stride,
|
x, y, z, y_stride, z_stride,
|
||||||
&offset, &i, &j);
|
&offset, &i, &j);
|
||||||
|
|
@ -145,7 +145,7 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld,
|
||||||
* coords which are out of bounds to become zero. Zero's guaranteed
|
* coords which are out of bounds to become zero. Zero's guaranteed
|
||||||
* to be inside the texture image.
|
* to be inside the texture image.
|
||||||
*/
|
*/
|
||||||
offset = lp_build_andnot(&bld->uint_coord_bld, offset, use_border);
|
offset = lp_build_andnot(&bld->int_coord_bld, offset, use_border);
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_build_fetch_rgba_soa(bld->builder,
|
lp_build_fetch_rgba_soa(bld->builder,
|
||||||
|
|
@ -202,11 +202,7 @@ lp_build_coord_mirror(struct lp_build_sample_context *bld,
|
||||||
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
||||||
LLVMValueRef fract, flr, isOdd;
|
LLVMValueRef fract, flr, isOdd;
|
||||||
|
|
||||||
/* fract = coord - floor(coord) */
|
lp_build_ifloor_fract(coord_bld, coord, &flr, &fract);
|
||||||
fract = lp_build_sub(coord_bld, coord, lp_build_floor(coord_bld, coord));
|
|
||||||
|
|
||||||
/* flr = ifloor(coord); */
|
|
||||||
flr = lp_build_ifloor(coord_bld, coord);
|
|
||||||
|
|
||||||
/* isOdd = flr & 1 */
|
/* isOdd = flr & 1 */
|
||||||
isOdd = LLVMBuildAnd(bld->builder, flr, int_coord_bld->one, "");
|
isOdd = LLVMBuildAnd(bld->builder, flr, int_coord_bld->one, "");
|
||||||
|
|
@ -234,6 +230,7 @@ static void
|
||||||
lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
|
lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef coord,
|
LLVMValueRef coord,
|
||||||
LLVMValueRef length,
|
LLVMValueRef length,
|
||||||
|
LLVMValueRef length_f,
|
||||||
boolean is_pot,
|
boolean is_pot,
|
||||||
unsigned wrap_mode,
|
unsigned wrap_mode,
|
||||||
LLVMValueRef *x0_out,
|
LLVMValueRef *x0_out,
|
||||||
|
|
@ -242,10 +239,8 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
|
||||||
{
|
{
|
||||||
struct lp_build_context *coord_bld = &bld->coord_bld;
|
struct lp_build_context *coord_bld = &bld->coord_bld;
|
||||||
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
||||||
struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
|
|
||||||
LLVMValueRef half = lp_build_const_vec(coord_bld->type, 0.5);
|
LLVMValueRef half = lp_build_const_vec(coord_bld->type, 0.5);
|
||||||
LLVMValueRef length_f = lp_build_int_to_float(coord_bld, length);
|
LLVMValueRef length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
|
||||||
LLVMValueRef length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one);
|
|
||||||
LLVMValueRef coord0, coord1, weight;
|
LLVMValueRef coord0, coord1, weight;
|
||||||
|
|
||||||
switch(wrap_mode) {
|
switch(wrap_mode) {
|
||||||
|
|
@ -255,19 +250,23 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
|
||||||
coord = lp_build_sub(coord_bld, coord, half);
|
coord = lp_build_sub(coord_bld, coord, half);
|
||||||
/* convert to int, compute lerp weight */
|
/* convert to int, compute lerp weight */
|
||||||
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
|
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
|
||||||
coord1 = lp_build_add(uint_coord_bld, coord0, uint_coord_bld->one);
|
|
||||||
/* repeat wrap */
|
/* repeat wrap */
|
||||||
if (is_pot) {
|
if (is_pot) {
|
||||||
|
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
|
||||||
coord0 = LLVMBuildAnd(bld->builder, coord0, length_minus_one, "");
|
coord0 = LLVMBuildAnd(bld->builder, coord0, length_minus_one, "");
|
||||||
coord1 = LLVMBuildAnd(bld->builder, coord1, length_minus_one, "");
|
coord1 = LLVMBuildAnd(bld->builder, coord1, length_minus_one, "");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Add a bias to the texcoord to handle negative coords */
|
/* Add a bias to the texcoord to handle negative coords */
|
||||||
LLVMValueRef bias = lp_build_mul_imm(uint_coord_bld, length, 1024);
|
LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
|
||||||
|
LLVMValueRef mask;
|
||||||
coord0 = LLVMBuildAdd(bld->builder, coord0, bias, "");
|
coord0 = LLVMBuildAdd(bld->builder, coord0, bias, "");
|
||||||
coord1 = LLVMBuildAdd(bld->builder, coord1, bias, "");
|
|
||||||
coord0 = LLVMBuildURem(bld->builder, coord0, length, "");
|
coord0 = LLVMBuildURem(bld->builder, coord0, length, "");
|
||||||
coord1 = LLVMBuildURem(bld->builder, coord1, length, "");
|
mask = lp_build_compare(bld->builder, int_coord_bld->type,
|
||||||
|
PIPE_FUNC_NOTEQUAL, coord0, length_minus_one);
|
||||||
|
coord1 = LLVMBuildAnd(bld->builder,
|
||||||
|
lp_build_add(int_coord_bld, coord0, int_coord_bld->one),
|
||||||
|
mask, "");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -288,41 +287,39 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
|
case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
|
||||||
|
{
|
||||||
|
struct lp_build_context abs_coord_bld = bld->coord_bld;
|
||||||
|
abs_coord_bld.type.sign = FALSE;
|
||||||
|
|
||||||
if (bld->static_state->normalized_coords) {
|
if (bld->static_state->normalized_coords) {
|
||||||
/* clamp to [0,1] */
|
/* mul by tex size */
|
||||||
coord = lp_build_clamp(coord_bld, coord, coord_bld->zero, coord_bld->one);
|
|
||||||
/* mul by tex size and subtract 0.5 */
|
|
||||||
coord = lp_build_mul(coord_bld, coord, length_f);
|
coord = lp_build_mul(coord_bld, coord, length_f);
|
||||||
|
}
|
||||||
|
/* clamp to length max */
|
||||||
|
coord = lp_build_min(coord_bld, coord, length_f);
|
||||||
|
/* subtract 0.5 */
|
||||||
coord = lp_build_sub(coord_bld, coord, half);
|
coord = lp_build_sub(coord_bld, coord, half);
|
||||||
}
|
/* clamp to [0, length - 0.5] */
|
||||||
else {
|
coord = lp_build_max(coord_bld, coord, coord_bld->zero);
|
||||||
LLVMValueRef min, max;
|
|
||||||
/* clamp to [0.5, length - 0.5] */
|
|
||||||
min = half;
|
|
||||||
max = lp_build_sub(coord_bld, length_f, min);
|
|
||||||
coord = lp_build_clamp(coord_bld, coord, min, max);
|
|
||||||
}
|
|
||||||
/* convert to int, compute lerp weight */
|
/* convert to int, compute lerp weight */
|
||||||
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
|
lp_build_ifloor_fract(&abs_coord_bld, coord, &coord0, &weight);
|
||||||
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
|
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
|
||||||
/* coord0 = max(coord0, 0) */
|
|
||||||
coord0 = lp_build_max(int_coord_bld, coord0, int_coord_bld->zero);
|
|
||||||
/* coord1 = min(coord1, length-1) */
|
/* coord1 = min(coord1, length-1) */
|
||||||
coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
|
coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
|
case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
|
||||||
{
|
{
|
||||||
LLVMValueRef min, max;
|
LLVMValueRef min;
|
||||||
if (bld->static_state->normalized_coords) {
|
if (bld->static_state->normalized_coords) {
|
||||||
/* scale coord to length */
|
/* scale coord to length */
|
||||||
coord = lp_build_mul(coord_bld, coord, length_f);
|
coord = lp_build_mul(coord_bld, coord, length_f);
|
||||||
}
|
}
|
||||||
/* clamp to [-0.5, length + 0.5] */
|
/* was: clamp to [-0.5, length + 0.5], then sub 0.5 */
|
||||||
min = lp_build_const_vec(coord_bld->type, -0.5F);
|
|
||||||
max = lp_build_sub(coord_bld, length_f, min);
|
|
||||||
coord = lp_build_clamp(coord_bld, coord, min, max);
|
|
||||||
coord = lp_build_sub(coord_bld, coord, half);
|
coord = lp_build_sub(coord_bld, coord, half);
|
||||||
|
min = lp_build_const_vec(coord_bld->type, -1.0F);
|
||||||
|
coord = lp_build_clamp(coord_bld, coord, min, length_f);
|
||||||
/* convert to int, compute lerp weight */
|
/* convert to int, compute lerp weight */
|
||||||
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
|
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
|
||||||
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
|
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
|
||||||
|
|
@ -368,7 +365,8 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
|
||||||
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
|
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
|
||||||
{
|
{
|
||||||
LLVMValueRef min, max;
|
LLVMValueRef min, max;
|
||||||
|
struct lp_build_context abs_coord_bld = bld->coord_bld;
|
||||||
|
abs_coord_bld.type.sign = FALSE;
|
||||||
coord = lp_build_abs(coord_bld, coord);
|
coord = lp_build_abs(coord_bld, coord);
|
||||||
|
|
||||||
if (bld->static_state->normalized_coords) {
|
if (bld->static_state->normalized_coords) {
|
||||||
|
|
@ -384,15 +382,13 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
|
||||||
coord = lp_build_sub(coord_bld, coord, half);
|
coord = lp_build_sub(coord_bld, coord, half);
|
||||||
|
|
||||||
/* convert to int, compute lerp weight */
|
/* convert to int, compute lerp weight */
|
||||||
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
|
lp_build_ifloor_fract(&abs_coord_bld, coord, &coord0, &weight);
|
||||||
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
|
coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
|
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
|
||||||
{
|
{
|
||||||
LLVMValueRef min, max;
|
|
||||||
|
|
||||||
coord = lp_build_abs(coord_bld, coord);
|
coord = lp_build_abs(coord_bld, coord);
|
||||||
|
|
||||||
if (bld->static_state->normalized_coords) {
|
if (bld->static_state->normalized_coords) {
|
||||||
|
|
@ -400,12 +396,10 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
|
||||||
coord = lp_build_mul(coord_bld, coord, length_f);
|
coord = lp_build_mul(coord_bld, coord, length_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clamp to [-0.5, length + 0.5] */
|
/* was: clamp to [-0.5, length + 0.5] then sub 0.5 */
|
||||||
min = lp_build_negate(coord_bld, half);
|
/* skip -0.5 clamp (always positive), do sub first */
|
||||||
max = lp_build_sub(coord_bld, length_f, min);
|
|
||||||
coord = lp_build_clamp(coord_bld, coord, min, max);
|
|
||||||
|
|
||||||
coord = lp_build_sub(coord_bld, coord, half);
|
coord = lp_build_sub(coord_bld, coord, half);
|
||||||
|
coord = lp_build_min(coord_bld, coord, length_f);
|
||||||
|
|
||||||
/* convert to int, compute lerp weight */
|
/* convert to int, compute lerp weight */
|
||||||
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
|
lp_build_ifloor_fract(coord_bld, coord, &coord0, &weight);
|
||||||
|
|
@ -437,14 +431,13 @@ static LLVMValueRef
|
||||||
lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
|
lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef coord,
|
LLVMValueRef coord,
|
||||||
LLVMValueRef length,
|
LLVMValueRef length,
|
||||||
|
LLVMValueRef length_f,
|
||||||
boolean is_pot,
|
boolean is_pot,
|
||||||
unsigned wrap_mode)
|
unsigned wrap_mode)
|
||||||
{
|
{
|
||||||
struct lp_build_context *coord_bld = &bld->coord_bld;
|
struct lp_build_context *coord_bld = &bld->coord_bld;
|
||||||
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
|
||||||
struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld;
|
LLVMValueRef length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one);
|
||||||
LLVMValueRef length_f = lp_build_int_to_float(coord_bld, length);
|
|
||||||
LLVMValueRef length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one);
|
|
||||||
LLVMValueRef icoord;
|
LLVMValueRef icoord;
|
||||||
|
|
||||||
switch(wrap_mode) {
|
switch(wrap_mode) {
|
||||||
|
|
@ -455,7 +448,7 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
|
||||||
icoord = LLVMBuildAnd(bld->builder, icoord, length_minus_one, "");
|
icoord = LLVMBuildAnd(bld->builder, icoord, length_minus_one, "");
|
||||||
else {
|
else {
|
||||||
/* Add a bias to the texcoord to handle negative coords */
|
/* Add a bias to the texcoord to handle negative coords */
|
||||||
LLVMValueRef bias = lp_build_mul_imm(uint_coord_bld, length, 1024);
|
LLVMValueRef bias = lp_build_mul_imm(int_coord_bld, length, 1024);
|
||||||
icoord = LLVMBuildAdd(bld->builder, icoord, bias, "");
|
icoord = LLVMBuildAdd(bld->builder, icoord, bias, "");
|
||||||
icoord = LLVMBuildURem(bld->builder, icoord, length, "");
|
icoord = LLVMBuildURem(bld->builder, icoord, length, "");
|
||||||
}
|
}
|
||||||
|
|
@ -469,7 +462,8 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* floor */
|
/* floor */
|
||||||
icoord = lp_build_ifloor(coord_bld, coord);
|
/* use itrunc instead since we clamp to 0 anyway */
|
||||||
|
icoord = lp_build_itrunc(coord_bld, coord);
|
||||||
|
|
||||||
/* clamp to [0, length - 1]. */
|
/* clamp to [0, length - 1]. */
|
||||||
icoord = lp_build_clamp(int_coord_bld, icoord, int_coord_bld->zero,
|
icoord = lp_build_clamp(int_coord_bld, icoord, int_coord_bld->zero,
|
||||||
|
|
@ -503,7 +497,8 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
|
||||||
assert(bld->static_state->normalized_coords);
|
assert(bld->static_state->normalized_coords);
|
||||||
coord = lp_build_mul(coord_bld, coord, length_f);
|
coord = lp_build_mul(coord_bld, coord, length_f);
|
||||||
|
|
||||||
icoord = lp_build_ifloor(coord_bld, coord);
|
/* itrunc == ifloor here */
|
||||||
|
icoord = lp_build_itrunc(coord_bld, coord);
|
||||||
|
|
||||||
/* clamp to [0, length - 1] */
|
/* clamp to [0, length - 1] */
|
||||||
icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
|
icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
|
||||||
|
|
@ -518,7 +513,8 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
|
||||||
coord = lp_build_mul(coord_bld, coord, length_f);
|
coord = lp_build_mul(coord_bld, coord, length_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
icoord = lp_build_ifloor(coord_bld, coord);
|
/* itrunc == ifloor here */
|
||||||
|
icoord = lp_build_itrunc(coord_bld, coord);
|
||||||
|
|
||||||
/* clamp to [0, length - 1] */
|
/* clamp to [0, length - 1] */
|
||||||
icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
|
icoord = lp_build_min(int_coord_bld, icoord, length_minus_one);
|
||||||
|
|
@ -532,7 +528,8 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
|
||||||
coord = lp_build_mul(coord_bld, coord, length_f);
|
coord = lp_build_mul(coord_bld, coord, length_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
icoord = lp_build_ifloor(coord_bld, coord);
|
/* itrunc == ifloor here */
|
||||||
|
icoord = lp_build_itrunc(coord_bld, coord);
|
||||||
|
|
||||||
/* clamp to [0, length] */
|
/* clamp to [0, length] */
|
||||||
icoord = lp_build_min(int_coord_bld, icoord, length);
|
icoord = lp_build_min(int_coord_bld, icoord, length);
|
||||||
|
|
@ -554,9 +551,7 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
|
||||||
static void
|
static void
|
||||||
lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
unsigned unit,
|
unsigned unit,
|
||||||
LLVMValueRef width_vec,
|
LLVMValueRef size,
|
||||||
LLVMValueRef height_vec,
|
|
||||||
LLVMValueRef depth_vec,
|
|
||||||
LLVMValueRef row_stride_vec,
|
LLVMValueRef row_stride_vec,
|
||||||
LLVMValueRef img_stride_vec,
|
LLVMValueRef img_stride_vec,
|
||||||
LLVMValueRef data_ptr,
|
LLVMValueRef data_ptr,
|
||||||
|
|
@ -566,24 +561,45 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef colors_out[4])
|
LLVMValueRef colors_out[4])
|
||||||
{
|
{
|
||||||
const unsigned dims = bld->dims;
|
const unsigned dims = bld->dims;
|
||||||
|
LLVMValueRef width_vec;
|
||||||
|
LLVMValueRef height_vec;
|
||||||
|
LLVMValueRef depth_vec;
|
||||||
|
LLVMValueRef flt_size;
|
||||||
|
LLVMValueRef flt_width_vec;
|
||||||
|
LLVMValueRef flt_height_vec;
|
||||||
|
LLVMValueRef flt_depth_vec;
|
||||||
LLVMValueRef x, y, z;
|
LLVMValueRef x, y, z;
|
||||||
|
|
||||||
|
lp_build_extract_image_sizes(bld,
|
||||||
|
bld->int_size_type,
|
||||||
|
bld->int_coord_type,
|
||||||
|
size,
|
||||||
|
&width_vec, &height_vec, &depth_vec);
|
||||||
|
|
||||||
|
flt_size = lp_build_int_to_float(&bld->float_size_bld, size);
|
||||||
|
|
||||||
|
lp_build_extract_image_sizes(bld,
|
||||||
|
bld->float_size_type,
|
||||||
|
bld->coord_type,
|
||||||
|
flt_size,
|
||||||
|
&flt_width_vec, &flt_height_vec, &flt_depth_vec);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute integer texcoords.
|
* Compute integer texcoords.
|
||||||
*/
|
*/
|
||||||
x = lp_build_sample_wrap_nearest(bld, s, width_vec,
|
x = lp_build_sample_wrap_nearest(bld, s, width_vec, flt_width_vec,
|
||||||
bld->static_state->pot_width,
|
bld->static_state->pot_width,
|
||||||
bld->static_state->wrap_s);
|
bld->static_state->wrap_s);
|
||||||
lp_build_name(x, "tex.x.wrapped");
|
lp_build_name(x, "tex.x.wrapped");
|
||||||
|
|
||||||
if (dims >= 2) {
|
if (dims >= 2) {
|
||||||
y = lp_build_sample_wrap_nearest(bld, t, height_vec,
|
y = lp_build_sample_wrap_nearest(bld, t, height_vec, flt_height_vec,
|
||||||
bld->static_state->pot_height,
|
bld->static_state->pot_height,
|
||||||
bld->static_state->wrap_t);
|
bld->static_state->wrap_t);
|
||||||
lp_build_name(y, "tex.y.wrapped");
|
lp_build_name(y, "tex.y.wrapped");
|
||||||
|
|
||||||
if (dims == 3) {
|
if (dims == 3) {
|
||||||
z = lp_build_sample_wrap_nearest(bld, r, depth_vec,
|
z = lp_build_sample_wrap_nearest(bld, r, depth_vec, flt_depth_vec,
|
||||||
bld->static_state->pot_depth,
|
bld->static_state->pot_depth,
|
||||||
bld->static_state->wrap_r);
|
bld->static_state->wrap_r);
|
||||||
lp_build_name(z, "tex.z.wrapped");
|
lp_build_name(z, "tex.z.wrapped");
|
||||||
|
|
@ -617,9 +633,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
|
||||||
static void
|
static void
|
||||||
lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
unsigned unit,
|
unsigned unit,
|
||||||
LLVMValueRef width_vec,
|
LLVMValueRef size,
|
||||||
LLVMValueRef height_vec,
|
|
||||||
LLVMValueRef depth_vec,
|
|
||||||
LLVMValueRef row_stride_vec,
|
LLVMValueRef row_stride_vec,
|
||||||
LLVMValueRef img_stride_vec,
|
LLVMValueRef img_stride_vec,
|
||||||
LLVMValueRef data_ptr,
|
LLVMValueRef data_ptr,
|
||||||
|
|
@ -629,15 +643,36 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef colors_out[4])
|
LLVMValueRef colors_out[4])
|
||||||
{
|
{
|
||||||
const unsigned dims = bld->dims;
|
const unsigned dims = bld->dims;
|
||||||
|
LLVMValueRef width_vec;
|
||||||
|
LLVMValueRef height_vec;
|
||||||
|
LLVMValueRef depth_vec;
|
||||||
|
LLVMValueRef flt_size;
|
||||||
|
LLVMValueRef flt_width_vec;
|
||||||
|
LLVMValueRef flt_height_vec;
|
||||||
|
LLVMValueRef flt_depth_vec;
|
||||||
LLVMValueRef x0, y0, z0, x1, y1, z1;
|
LLVMValueRef x0, y0, z0, x1, y1, z1;
|
||||||
LLVMValueRef s_fpart, t_fpart, r_fpart;
|
LLVMValueRef s_fpart, t_fpart, r_fpart;
|
||||||
LLVMValueRef neighbors[2][2][4];
|
LLVMValueRef neighbors[2][2][4];
|
||||||
int chan;
|
int chan;
|
||||||
|
|
||||||
|
lp_build_extract_image_sizes(bld,
|
||||||
|
bld->int_size_type,
|
||||||
|
bld->int_coord_type,
|
||||||
|
size,
|
||||||
|
&width_vec, &height_vec, &depth_vec);
|
||||||
|
|
||||||
|
flt_size = lp_build_int_to_float(&bld->float_size_bld, size);
|
||||||
|
|
||||||
|
lp_build_extract_image_sizes(bld,
|
||||||
|
bld->float_size_type,
|
||||||
|
bld->coord_type,
|
||||||
|
flt_size,
|
||||||
|
&flt_width_vec, &flt_height_vec, &flt_depth_vec);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute integer texcoords.
|
* Compute integer texcoords.
|
||||||
*/
|
*/
|
||||||
lp_build_sample_wrap_linear(bld, s, width_vec,
|
lp_build_sample_wrap_linear(bld, s, width_vec, flt_width_vec,
|
||||||
bld->static_state->pot_width,
|
bld->static_state->pot_width,
|
||||||
bld->static_state->wrap_s,
|
bld->static_state->wrap_s,
|
||||||
&x0, &x1, &s_fpart);
|
&x0, &x1, &s_fpart);
|
||||||
|
|
@ -645,7 +680,7 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
lp_build_name(x1, "tex.x1.wrapped");
|
lp_build_name(x1, "tex.x1.wrapped");
|
||||||
|
|
||||||
if (dims >= 2) {
|
if (dims >= 2) {
|
||||||
lp_build_sample_wrap_linear(bld, t, height_vec,
|
lp_build_sample_wrap_linear(bld, t, height_vec, flt_height_vec,
|
||||||
bld->static_state->pot_height,
|
bld->static_state->pot_height,
|
||||||
bld->static_state->wrap_t,
|
bld->static_state->wrap_t,
|
||||||
&y0, &y1, &t_fpart);
|
&y0, &y1, &t_fpart);
|
||||||
|
|
@ -653,7 +688,7 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
|
||||||
lp_build_name(y1, "tex.y1.wrapped");
|
lp_build_name(y1, "tex.y1.wrapped");
|
||||||
|
|
||||||
if (dims == 3) {
|
if (dims == 3) {
|
||||||
lp_build_sample_wrap_linear(bld, r, depth_vec,
|
lp_build_sample_wrap_linear(bld, r, depth_vec, flt_depth_vec,
|
||||||
bld->static_state->pot_depth,
|
bld->static_state->pot_depth,
|
||||||
bld->static_state->wrap_r,
|
bld->static_state->wrap_r,
|
||||||
&z0, &z1, &r_fpart);
|
&z0, &z1, &r_fpart);
|
||||||
|
|
@ -796,12 +831,8 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
LLVMValueRef *colors_out)
|
LLVMValueRef *colors_out)
|
||||||
{
|
{
|
||||||
LLVMBuilderRef builder = bld->builder;
|
LLVMBuilderRef builder = bld->builder;
|
||||||
LLVMValueRef width0_vec;
|
LLVMValueRef size0;
|
||||||
LLVMValueRef width1_vec;
|
LLVMValueRef size1;
|
||||||
LLVMValueRef height0_vec;
|
|
||||||
LLVMValueRef height1_vec;
|
|
||||||
LLVMValueRef depth0_vec;
|
|
||||||
LLVMValueRef depth1_vec;
|
|
||||||
LLVMValueRef row_stride0_vec;
|
LLVMValueRef row_stride0_vec;
|
||||||
LLVMValueRef row_stride1_vec;
|
LLVMValueRef row_stride1_vec;
|
||||||
LLVMValueRef img_stride0_vec;
|
LLVMValueRef img_stride0_vec;
|
||||||
|
|
@ -813,12 +844,12 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
|
|
||||||
/* sample the first mipmap level */
|
/* sample the first mipmap level */
|
||||||
lp_build_mipmap_level_sizes(bld, ilevel0,
|
lp_build_mipmap_level_sizes(bld, ilevel0,
|
||||||
&width0_vec, &height0_vec, &depth0_vec,
|
&size0,
|
||||||
&row_stride0_vec, &img_stride0_vec);
|
&row_stride0_vec, &img_stride0_vec);
|
||||||
data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
|
data_ptr0 = lp_build_get_mipmap_level(bld, ilevel0);
|
||||||
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
|
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
|
||||||
lp_build_sample_image_nearest(bld, unit,
|
lp_build_sample_image_nearest(bld, unit,
|
||||||
width0_vec, height0_vec, depth0_vec,
|
size0,
|
||||||
row_stride0_vec, img_stride0_vec,
|
row_stride0_vec, img_stride0_vec,
|
||||||
data_ptr0, s, t, r,
|
data_ptr0, s, t, r,
|
||||||
colors0);
|
colors0);
|
||||||
|
|
@ -826,7 +857,7 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
else {
|
else {
|
||||||
assert(img_filter == PIPE_TEX_FILTER_LINEAR);
|
assert(img_filter == PIPE_TEX_FILTER_LINEAR);
|
||||||
lp_build_sample_image_linear(bld, unit,
|
lp_build_sample_image_linear(bld, unit,
|
||||||
width0_vec, height0_vec, depth0_vec,
|
size0,
|
||||||
row_stride0_vec, img_stride0_vec,
|
row_stride0_vec, img_stride0_vec,
|
||||||
data_ptr0, s, t, r,
|
data_ptr0, s, t, r,
|
||||||
colors0);
|
colors0);
|
||||||
|
|
@ -838,35 +869,32 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
|
if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
|
||||||
struct lp_build_flow_context *flow_ctx;
|
|
||||||
struct lp_build_if_state if_ctx;
|
struct lp_build_if_state if_ctx;
|
||||||
LLVMValueRef need_lerp;
|
LLVMValueRef need_lerp;
|
||||||
|
|
||||||
flow_ctx = lp_build_flow_create(builder);
|
|
||||||
|
|
||||||
/* need_lerp = lod_fpart > 0 */
|
/* need_lerp = lod_fpart > 0 */
|
||||||
need_lerp = LLVMBuildFCmp(builder, LLVMRealUGT,
|
need_lerp = LLVMBuildFCmp(builder, LLVMRealUGT,
|
||||||
lod_fpart,
|
lod_fpart,
|
||||||
bld->float_bld.zero,
|
bld->float_bld.zero,
|
||||||
"need_lerp");
|
"need_lerp");
|
||||||
|
|
||||||
lp_build_if(&if_ctx, flow_ctx, builder, need_lerp);
|
lp_build_if(&if_ctx, builder, need_lerp);
|
||||||
{
|
{
|
||||||
/* sample the second mipmap level */
|
/* sample the second mipmap level */
|
||||||
lp_build_mipmap_level_sizes(bld, ilevel1,
|
lp_build_mipmap_level_sizes(bld, ilevel1,
|
||||||
&width1_vec, &height1_vec, &depth1_vec,
|
&size1,
|
||||||
&row_stride1_vec, &img_stride1_vec);
|
&row_stride1_vec, &img_stride1_vec);
|
||||||
data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
|
data_ptr1 = lp_build_get_mipmap_level(bld, ilevel1);
|
||||||
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
|
if (img_filter == PIPE_TEX_FILTER_NEAREST) {
|
||||||
lp_build_sample_image_nearest(bld, unit,
|
lp_build_sample_image_nearest(bld, unit,
|
||||||
width1_vec, height1_vec, depth1_vec,
|
size1,
|
||||||
row_stride1_vec, img_stride1_vec,
|
row_stride1_vec, img_stride1_vec,
|
||||||
data_ptr1, s, t, r,
|
data_ptr1, s, t, r,
|
||||||
colors1);
|
colors1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lp_build_sample_image_linear(bld, unit,
|
lp_build_sample_image_linear(bld, unit,
|
||||||
width1_vec, height1_vec, depth1_vec,
|
size1,
|
||||||
row_stride1_vec, img_stride1_vec,
|
row_stride1_vec, img_stride1_vec,
|
||||||
data_ptr1, s, t, r,
|
data_ptr1, s, t, r,
|
||||||
colors1);
|
colors1);
|
||||||
|
|
@ -883,8 +911,6 @@ lp_build_sample_mipmap(struct lp_build_sample_context *bld,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lp_build_endif(&if_ctx);
|
lp_build_endif(&if_ctx);
|
||||||
|
|
||||||
lp_build_flow_destroy(flow_ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -937,12 +963,12 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
|
||||||
r = lp_build_broadcast_scalar(&bld->int_coord_bld, face); /* vec */
|
r = lp_build_broadcast_scalar(&bld->int_coord_bld, face); /* vec */
|
||||||
|
|
||||||
/* recompute ddx, ddy using the new (s,t) face texcoords */
|
/* recompute ddx, ddy using the new (s,t) face texcoords */
|
||||||
face_ddx[0] = lp_build_ddx(&bld->coord_bld, s);
|
face_ddx[0] = lp_build_scalar_ddx(&bld->coord_bld, s);
|
||||||
face_ddx[1] = lp_build_ddx(&bld->coord_bld, t);
|
face_ddx[1] = lp_build_scalar_ddx(&bld->coord_bld, t);
|
||||||
face_ddx[2] = NULL;
|
face_ddx[2] = NULL;
|
||||||
face_ddx[3] = NULL;
|
face_ddx[3] = NULL;
|
||||||
face_ddy[0] = lp_build_ddy(&bld->coord_bld, s);
|
face_ddy[0] = lp_build_scalar_ddy(&bld->coord_bld, s);
|
||||||
face_ddy[1] = lp_build_ddy(&bld->coord_bld, t);
|
face_ddy[1] = lp_build_scalar_ddy(&bld->coord_bld, t);
|
||||||
face_ddy[2] = NULL;
|
face_ddy[2] = NULL;
|
||||||
face_ddy[3] = NULL;
|
face_ddy[3] = NULL;
|
||||||
ddx = face_ddx;
|
ddx = face_ddx;
|
||||||
|
|
@ -1020,17 +1046,14 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
|
||||||
/* Emit conditional to choose min image filter or mag image filter
|
/* Emit conditional to choose min image filter or mag image filter
|
||||||
* depending on the lod being > 0 or <= 0, respectively.
|
* depending on the lod being > 0 or <= 0, respectively.
|
||||||
*/
|
*/
|
||||||
struct lp_build_flow_context *flow_ctx;
|
|
||||||
struct lp_build_if_state if_ctx;
|
struct lp_build_if_state if_ctx;
|
||||||
LLVMValueRef minify;
|
LLVMValueRef minify;
|
||||||
|
|
||||||
flow_ctx = lp_build_flow_create(builder);
|
|
||||||
|
|
||||||
/* minify = lod >= 0.0 */
|
/* minify = lod >= 0.0 */
|
||||||
minify = LLVMBuildICmp(builder, LLVMIntSGE,
|
minify = LLVMBuildICmp(builder, LLVMIntSGE,
|
||||||
lod_ipart, int_bld->zero, "");
|
lod_ipart, int_bld->zero, "");
|
||||||
|
|
||||||
lp_build_if(&if_ctx, flow_ctx, builder, minify);
|
lp_build_if(&if_ctx, builder, minify);
|
||||||
{
|
{
|
||||||
/* Use the minification filter */
|
/* Use the minification filter */
|
||||||
lp_build_sample_mipmap(bld, unit,
|
lp_build_sample_mipmap(bld, unit,
|
||||||
|
|
@ -1049,8 +1072,6 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
|
||||||
texels);
|
texels);
|
||||||
}
|
}
|
||||||
lp_build_endif(&if_ctx);
|
lp_build_endif(&if_ctx);
|
||||||
|
|
||||||
lp_build_flow_destroy(flow_ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (chan = 0; chan < 4; ++chan) {
|
for (chan = 0; chan < 4; ++chan) {
|
||||||
|
|
@ -1166,7 +1187,6 @@ lp_build_sample_soa(LLVMBuilderRef builder,
|
||||||
bld.float_type = lp_type_float(32);
|
bld.float_type = lp_type_float(32);
|
||||||
bld.int_type = lp_type_int(32);
|
bld.int_type = lp_type_int(32);
|
||||||
bld.coord_type = type;
|
bld.coord_type = type;
|
||||||
bld.uint_coord_type = lp_uint_type(type);
|
|
||||||
bld.int_coord_type = lp_int_type(type);
|
bld.int_coord_type = lp_int_type(type);
|
||||||
bld.float_size_type = lp_type_float(32);
|
bld.float_size_type = lp_type_float(32);
|
||||||
bld.float_size_type.length = dims > 1 ? 4 : 1;
|
bld.float_size_type.length = dims > 1 ? 4 : 1;
|
||||||
|
|
@ -1179,7 +1199,6 @@ lp_build_sample_soa(LLVMBuilderRef builder,
|
||||||
lp_build_context_init(&bld.float_vec_bld, builder, float_vec_type);
|
lp_build_context_init(&bld.float_vec_bld, builder, float_vec_type);
|
||||||
lp_build_context_init(&bld.int_bld, builder, bld.int_type);
|
lp_build_context_init(&bld.int_bld, builder, bld.int_type);
|
||||||
lp_build_context_init(&bld.coord_bld, builder, bld.coord_type);
|
lp_build_context_init(&bld.coord_bld, builder, bld.coord_type);
|
||||||
lp_build_context_init(&bld.uint_coord_bld, builder, bld.uint_coord_type);
|
|
||||||
lp_build_context_init(&bld.int_coord_bld, builder, bld.int_coord_type);
|
lp_build_context_init(&bld.int_coord_bld, builder, bld.int_coord_type);
|
||||||
lp_build_context_init(&bld.int_size_bld, builder, bld.int_size_type);
|
lp_build_context_init(&bld.int_size_bld, builder, bld.int_size_type);
|
||||||
lp_build_context_init(&bld.float_size_bld, builder, bld.float_size_type);
|
lp_build_context_init(&bld.float_size_bld, builder, bld.float_size_type);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@
|
||||||
#define LP_BLD_TGSI_H
|
#define LP_BLD_TGSI_H
|
||||||
|
|
||||||
#include "gallivm/lp_bld.h"
|
#include "gallivm/lp_bld.h"
|
||||||
|
#include "pipe/p_compiler.h"
|
||||||
|
#include "pipe/p_state.h"
|
||||||
|
#include "tgsi/tgsi_scan.h"
|
||||||
|
|
||||||
|
|
||||||
struct tgsi_token;
|
struct tgsi_token;
|
||||||
|
|
@ -54,6 +57,75 @@ enum lp_build_tex_modifier {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe a channel of a register.
|
||||||
|
*
|
||||||
|
* The value can be a:
|
||||||
|
* - immediate value (i.e. derived from a IMM register)
|
||||||
|
* - CONST[n].x/y/z/w
|
||||||
|
* - IN[n].x/y/z/w
|
||||||
|
* - undetermined (when .file == TGSI_FILE_NULL)
|
||||||
|
*
|
||||||
|
* This is one of the analysis results, and is used to described
|
||||||
|
* the output color in terms of inputs.
|
||||||
|
*/
|
||||||
|
struct lp_tgsi_channel_info
|
||||||
|
{
|
||||||
|
unsigned file:4; /* TGSI_FILE_* */
|
||||||
|
unsigned swizzle:3; /* PIPE_SWIZZLE_x */
|
||||||
|
union {
|
||||||
|
uint32_t index;
|
||||||
|
float value; /* for TGSI_FILE_IMMEDIATE */
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe a texture sampler interpolator.
|
||||||
|
*
|
||||||
|
* The interpolation is described in terms of regular inputs.
|
||||||
|
*/
|
||||||
|
struct lp_tgsi_texture_info
|
||||||
|
{
|
||||||
|
struct lp_tgsi_channel_info coord[4];
|
||||||
|
unsigned target:8; /* TGSI_TEXTURE_* */
|
||||||
|
unsigned unit:8; /* Sampler unit */
|
||||||
|
unsigned modifier:8; /* LP_BLD_TEX_MODIFIER_* */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct lp_tgsi_info
|
||||||
|
{
|
||||||
|
struct tgsi_shader_info base;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Whether any of the texture opcodes access a register file other than
|
||||||
|
* TGSI_FILE_INPUT.
|
||||||
|
*
|
||||||
|
* We could also handle TGSI_FILE_CONST/IMMEDIATE here, but there is little
|
||||||
|
* benefit.
|
||||||
|
*/
|
||||||
|
unsigned indirect_textures:1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Texture opcode description. Aimed at detecting and described direct
|
||||||
|
* texture opcodes.
|
||||||
|
*/
|
||||||
|
unsigned num_texs;
|
||||||
|
struct lp_tgsi_texture_info tex[PIPE_MAX_SAMPLERS];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output description. Aimed at detecting and describing simple blit
|
||||||
|
* shaders.
|
||||||
|
*/
|
||||||
|
struct lp_tgsi_channel_info output[PIPE_MAX_SHADER_OUTPUTS][4];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shortcut pointers into the above (for fragment shaders).
|
||||||
|
*/
|
||||||
|
const struct lp_tgsi_channel_info *cbuf[PIPE_MAX_COLOR_BUFS];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sampler code generation interface.
|
* Sampler code generation interface.
|
||||||
*
|
*
|
||||||
|
|
@ -96,6 +168,11 @@ struct lp_build_sampler_aos
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_tgsi_info(const struct tgsi_token *tokens,
|
||||||
|
struct lp_tgsi_info *info);
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_tgsi_soa(LLVMBuilderRef builder,
|
lp_build_tgsi_soa(LLVMBuilderRef builder,
|
||||||
const struct tgsi_token *tokens,
|
const struct tgsi_token *tokens,
|
||||||
|
|
|
||||||
|
|
@ -513,7 +513,7 @@ emit_instruction(
|
||||||
{
|
{
|
||||||
LLVMValueRef src0, src1, src2;
|
LLVMValueRef src0, src1, src2;
|
||||||
LLVMValueRef tmp0, tmp1;
|
LLVMValueRef tmp0, tmp1;
|
||||||
LLVMValueRef dst0;
|
LLVMValueRef dst0 = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stores and write masks are handled in a general fashion after the long
|
* Stores and write masks are handled in a general fashion after the long
|
||||||
|
|
|
||||||
479
src/gallium/auxiliary/gallivm/lp_bld_tgsi_info.c
Normal file
479
src/gallium/auxiliary/gallivm/lp_bld_tgsi_info.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -887,21 +887,25 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
|
if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
|
||||||
|
LLVMTypeRef i32t = LLVMInt32Type();
|
||||||
|
LLVMValueRef index0 = LLVMConstInt(i32t, 0, 0);
|
||||||
for (i = 0; i < num_coords; i++) {
|
for (i = 0; i < num_coords; i++) {
|
||||||
ddx[i] = emit_fetch( bld, inst, 1, i );
|
LLVMValueRef src1 = emit_fetch( bld, inst, 1, i );
|
||||||
ddy[i] = emit_fetch( bld, inst, 2, i );
|
LLVMValueRef src2 = emit_fetch( bld, inst, 2, i );
|
||||||
|
ddx[i] = LLVMBuildExtractElement(bld->base.builder, src1, index0, "");
|
||||||
|
ddy[i] = LLVMBuildExtractElement(bld->base.builder, src2, index0, "");
|
||||||
}
|
}
|
||||||
unit = inst->Src[3].Register.Index;
|
unit = inst->Src[3].Register.Index;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < num_coords; i++) {
|
for (i = 0; i < num_coords; i++) {
|
||||||
ddx[i] = lp_build_ddx( &bld->base, coords[i] );
|
ddx[i] = lp_build_scalar_ddx( &bld->base, coords[i] );
|
||||||
ddy[i] = lp_build_ddy( &bld->base, coords[i] );
|
ddy[i] = lp_build_scalar_ddy( &bld->base, coords[i] );
|
||||||
}
|
}
|
||||||
unit = inst->Src[1].Register.Index;
|
unit = inst->Src[1].Register.Index;
|
||||||
}
|
}
|
||||||
for (i = num_coords; i < 3; i++) {
|
for (i = num_coords; i < 3; i++) {
|
||||||
ddx[i] = bld->base.undef;
|
ddx[i] = LLVMGetUndef(bld->base.elem_type);
|
||||||
ddy[i] = bld->base.undef;
|
ddy[i] = LLVMGetUndef(bld->base.elem_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
bld->sampler->emit_fetch_texel(bld->sampler,
|
bld->sampler->emit_fetch_texel(bld->sampler,
|
||||||
|
|
@ -913,6 +917,43 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
|
||||||
texel);
|
texel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean
|
||||||
|
near_end_of_shader(struct lp_build_tgsi_soa_context *bld,
|
||||||
|
int pc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
unsigned opcode;
|
||||||
|
|
||||||
|
if (pc + i >= bld->info->num_instructions)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
opcode = bld->instructions[pc + i].Instruction.Opcode;
|
||||||
|
|
||||||
|
if (opcode == TGSI_OPCODE_END)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (opcode == TGSI_OPCODE_TEX ||
|
||||||
|
opcode == TGSI_OPCODE_TXP ||
|
||||||
|
opcode == TGSI_OPCODE_TXD ||
|
||||||
|
opcode == TGSI_OPCODE_TXB ||
|
||||||
|
opcode == TGSI_OPCODE_TXL ||
|
||||||
|
opcode == TGSI_OPCODE_TXF ||
|
||||||
|
opcode == TGSI_OPCODE_TXQ ||
|
||||||
|
opcode == TGSI_OPCODE_CAL ||
|
||||||
|
opcode == TGSI_OPCODE_CALLNZ ||
|
||||||
|
opcode == TGSI_OPCODE_IF ||
|
||||||
|
opcode == TGSI_OPCODE_IFC ||
|
||||||
|
opcode == TGSI_OPCODE_BGNLOOP ||
|
||||||
|
opcode == TGSI_OPCODE_SWITCH)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kill fragment if any of the src register values are negative.
|
* Kill fragment if any of the src register values are negative.
|
||||||
|
|
@ -920,7 +961,8 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
|
||||||
static void
|
static void
|
||||||
emit_kil(
|
emit_kil(
|
||||||
struct lp_build_tgsi_soa_context *bld,
|
struct lp_build_tgsi_soa_context *bld,
|
||||||
const struct tgsi_full_instruction *inst )
|
const struct tgsi_full_instruction *inst,
|
||||||
|
int pc)
|
||||||
{
|
{
|
||||||
const struct tgsi_full_src_register *reg = &inst->Src[0];
|
const struct tgsi_full_src_register *reg = &inst->Src[0];
|
||||||
LLVMValueRef terms[NUM_CHANNELS];
|
LLVMValueRef terms[NUM_CHANNELS];
|
||||||
|
|
@ -959,8 +1001,12 @@ emit_kil(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mask)
|
if(mask) {
|
||||||
lp_build_mask_update(bld->mask, mask);
|
lp_build_mask_update(bld->mask, mask);
|
||||||
|
|
||||||
|
if (!near_end_of_shader(bld, pc))
|
||||||
|
lp_build_mask_check(bld->mask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -972,7 +1018,8 @@ emit_kil(
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
emit_kilp(struct lp_build_tgsi_soa_context *bld,
|
emit_kilp(struct lp_build_tgsi_soa_context *bld,
|
||||||
const struct tgsi_full_instruction *inst)
|
const struct tgsi_full_instruction *inst,
|
||||||
|
int pc)
|
||||||
{
|
{
|
||||||
LLVMValueRef mask;
|
LLVMValueRef mask;
|
||||||
|
|
||||||
|
|
@ -983,10 +1030,14 @@ emit_kilp(struct lp_build_tgsi_soa_context *bld,
|
||||||
mask = LLVMBuildNot(bld->base.builder, bld->exec_mask.exec_mask, "kilp");
|
mask = LLVMBuildNot(bld->base.builder, bld->exec_mask.exec_mask, "kilp");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mask = bld->base.zero;
|
LLVMValueRef zero = LLVMConstNull(bld->base.int_vec_type);
|
||||||
|
mask = zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_build_mask_update(bld->mask, mask);
|
lp_build_mask_update(bld->mask, mask);
|
||||||
|
|
||||||
|
if (!near_end_of_shader(bld, pc))
|
||||||
|
lp_build_mask_check(bld->mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -1535,12 +1586,12 @@ emit_instruction(
|
||||||
|
|
||||||
case TGSI_OPCODE_KILP:
|
case TGSI_OPCODE_KILP:
|
||||||
/* predicated kill */
|
/* predicated kill */
|
||||||
emit_kilp( bld, inst );
|
emit_kilp( bld, inst, (*pc)-1 );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TGSI_OPCODE_KIL:
|
case TGSI_OPCODE_KIL:
|
||||||
/* conditional kill */
|
/* conditional kill */
|
||||||
emit_kil( bld, inst );
|
emit_kil( bld, inst, (*pc)-1 );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TGSI_OPCODE_PK2H:
|
case TGSI_OPCODE_PK2H:
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ void (*ppc_get_func(struct ppc_function *p))(void)
|
||||||
return (void (*)(void)) NULL;
|
return (void (*)(void)) NULL;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
return (void (*)(void)) p->store;
|
return (void (*)(void)) pointer_to_func(p->store);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,25 +23,12 @@
|
||||||
#include "cell/ppu/cell_public.h"
|
#include "cell/ppu/cell_public.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static INLINE struct pipe_screen *
|
static INLINE struct pipe_screen *
|
||||||
sw_screen_create(struct sw_winsys *winsys)
|
sw_screen_create_named(struct sw_winsys *winsys, const char *driver)
|
||||||
{
|
{
|
||||||
const char *default_driver;
|
|
||||||
const char *driver;
|
|
||||||
struct pipe_screen *screen = NULL;
|
struct pipe_screen *screen = NULL;
|
||||||
|
|
||||||
#if defined(GALLIUM_CELL)
|
|
||||||
default_driver = "cell";
|
|
||||||
#elif defined(GALLIUM_LLVMPIPE)
|
|
||||||
default_driver = "llvmpipe";
|
|
||||||
#elif defined(GALLIUM_SOFTPIPE)
|
|
||||||
default_driver = "softpipe";
|
|
||||||
#else
|
|
||||||
default_driver = "";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
driver = debug_get_option("GALLIUM_DRIVER", default_driver);
|
|
||||||
|
|
||||||
#if defined(GALLIUM_CELL)
|
#if defined(GALLIUM_CELL)
|
||||||
if (screen == NULL && strcmp(driver, "cell") == 0)
|
if (screen == NULL && strcmp(driver, "cell") == 0)
|
||||||
screen = cell_create_screen(winsys);
|
screen = cell_create_screen(winsys);
|
||||||
|
|
@ -60,4 +47,26 @@ sw_screen_create(struct sw_winsys *winsys)
|
||||||
return screen;
|
return screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static INLINE struct pipe_screen *
|
||||||
|
sw_screen_create(struct sw_winsys *winsys)
|
||||||
|
{
|
||||||
|
const char *default_driver;
|
||||||
|
const char *driver;
|
||||||
|
|
||||||
|
#if defined(GALLIUM_CELL)
|
||||||
|
default_driver = "cell";
|
||||||
|
#elif defined(GALLIUM_LLVMPIPE)
|
||||||
|
default_driver = "llvmpipe";
|
||||||
|
#elif defined(GALLIUM_SOFTPIPE)
|
||||||
|
default_driver = "softpipe";
|
||||||
|
#else
|
||||||
|
default_driver = "";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
driver = debug_get_option("GALLIUM_DRIVER", default_driver);
|
||||||
|
return sw_screen_create_named(winsys, driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,26 @@ static INLINE struct pipe_screen *
|
||||||
sw_screen_wrap(struct pipe_screen *screen)
|
sw_screen_wrap(struct pipe_screen *screen)
|
||||||
{
|
{
|
||||||
struct sw_winsys *sws;
|
struct sw_winsys *sws;
|
||||||
struct pipe_screen *sw_screen;
|
struct pipe_screen *sw_screen = NULL;
|
||||||
|
const char *driver;
|
||||||
|
|
||||||
sws = wrapper_sw_winsys_warp_pipe_screen(screen);
|
driver = debug_get_option("GALLIUM_DRIVER", "native");
|
||||||
|
if (strcmp(driver, "native") == 0)
|
||||||
|
return screen;
|
||||||
|
|
||||||
|
sws = wrapper_sw_winsys_wrap_pipe_screen(screen);
|
||||||
if (!sws)
|
if (!sws)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
sw_screen = sw_screen_create(sws);
|
sw_screen = sw_screen_create_named(sws, driver);
|
||||||
if (sw_screen == screen)
|
|
||||||
|
if (!sw_screen)
|
||||||
goto err_winsys;
|
goto err_winsys;
|
||||||
|
|
||||||
return sw_screen;
|
return sw_screen;
|
||||||
|
|
||||||
err_winsys:
|
err_winsys:
|
||||||
sws->destroy(sws);
|
return wrapper_sw_winsys_dewrap_pipe_screen(sws);
|
||||||
err:
|
err:
|
||||||
return screen;
|
return screen;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,8 @@ static const char *processor_type_names[] =
|
||||||
"GEOM"
|
"GEOM"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *file_names[TGSI_FILE_COUNT] =
|
const char *
|
||||||
|
tgsi_file_names[TGSI_FILE_COUNT] =
|
||||||
{
|
{
|
||||||
"NULL",
|
"NULL",
|
||||||
"CONST",
|
"CONST",
|
||||||
|
|
@ -125,7 +126,8 @@ static const char *semantic_names[] =
|
||||||
"FACE",
|
"FACE",
|
||||||
"EDGEFLAG",
|
"EDGEFLAG",
|
||||||
"PRIM_ID",
|
"PRIM_ID",
|
||||||
"INSTANCEID"
|
"INSTANCEID",
|
||||||
|
"STENCIL"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *immediate_type_names[] =
|
static const char *immediate_type_names[] =
|
||||||
|
|
@ -135,7 +137,8 @@ static const char *immediate_type_names[] =
|
||||||
"INT32"
|
"INT32"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *swizzle_names[] =
|
const char *
|
||||||
|
tgsi_swizzle_names[] =
|
||||||
{
|
{
|
||||||
"x",
|
"x",
|
||||||
"y",
|
"y",
|
||||||
|
|
@ -143,7 +146,8 @@ static const char *swizzle_names[] =
|
||||||
"w"
|
"w"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *texture_names[] =
|
const char *
|
||||||
|
tgsi_texture_names[] =
|
||||||
{
|
{
|
||||||
"UNKNOWN",
|
"UNKNOWN",
|
||||||
"1D",
|
"1D",
|
||||||
|
|
@ -201,15 +205,15 @@ _dump_register_src(
|
||||||
struct dump_ctx *ctx,
|
struct dump_ctx *ctx,
|
||||||
const struct tgsi_full_src_register *src )
|
const struct tgsi_full_src_register *src )
|
||||||
{
|
{
|
||||||
ENM(src->Register.File, file_names);
|
ENM(src->Register.File, tgsi_file_names);
|
||||||
if (src->Register.Dimension) {
|
if (src->Register.Dimension) {
|
||||||
if (src->Dimension.Indirect) {
|
if (src->Dimension.Indirect) {
|
||||||
CHR( '[' );
|
CHR( '[' );
|
||||||
ENM( src->DimIndirect.File, file_names );
|
ENM( src->DimIndirect.File, tgsi_file_names );
|
||||||
CHR( '[' );
|
CHR( '[' );
|
||||||
SID( src->DimIndirect.Index );
|
SID( src->DimIndirect.Index );
|
||||||
TXT( "]." );
|
TXT( "]." );
|
||||||
ENM( src->DimIndirect.SwizzleX, swizzle_names );
|
ENM( src->DimIndirect.SwizzleX, tgsi_swizzle_names );
|
||||||
if (src->Dimension.Index != 0) {
|
if (src->Dimension.Index != 0) {
|
||||||
if (src->Dimension.Index > 0)
|
if (src->Dimension.Index > 0)
|
||||||
CHR( '+' );
|
CHR( '+' );
|
||||||
|
|
@ -224,11 +228,11 @@ _dump_register_src(
|
||||||
}
|
}
|
||||||
if (src->Register.Indirect) {
|
if (src->Register.Indirect) {
|
||||||
CHR( '[' );
|
CHR( '[' );
|
||||||
ENM( src->Indirect.File, file_names );
|
ENM( src->Indirect.File, tgsi_file_names );
|
||||||
CHR( '[' );
|
CHR( '[' );
|
||||||
SID( src->Indirect.Index );
|
SID( src->Indirect.Index );
|
||||||
TXT( "]." );
|
TXT( "]." );
|
||||||
ENM( src->Indirect.SwizzleX, swizzle_names );
|
ENM( src->Indirect.SwizzleX, tgsi_swizzle_names );
|
||||||
if (src->Register.Index != 0) {
|
if (src->Register.Index != 0) {
|
||||||
if (src->Register.Index > 0)
|
if (src->Register.Index > 0)
|
||||||
CHR( '+' );
|
CHR( '+' );
|
||||||
|
|
@ -248,15 +252,15 @@ _dump_register_dst(
|
||||||
struct dump_ctx *ctx,
|
struct dump_ctx *ctx,
|
||||||
const struct tgsi_full_dst_register *dst )
|
const struct tgsi_full_dst_register *dst )
|
||||||
{
|
{
|
||||||
ENM(dst->Register.File, file_names);
|
ENM(dst->Register.File, tgsi_file_names);
|
||||||
if (dst->Register.Dimension) {
|
if (dst->Register.Dimension) {
|
||||||
if (dst->Dimension.Indirect) {
|
if (dst->Dimension.Indirect) {
|
||||||
CHR( '[' );
|
CHR( '[' );
|
||||||
ENM( dst->DimIndirect.File, file_names );
|
ENM( dst->DimIndirect.File, tgsi_file_names );
|
||||||
CHR( '[' );
|
CHR( '[' );
|
||||||
SID( dst->DimIndirect.Index );
|
SID( dst->DimIndirect.Index );
|
||||||
TXT( "]." );
|
TXT( "]." );
|
||||||
ENM( dst->DimIndirect.SwizzleX, swizzle_names );
|
ENM( dst->DimIndirect.SwizzleX, tgsi_swizzle_names );
|
||||||
if (dst->Dimension.Index != 0) {
|
if (dst->Dimension.Index != 0) {
|
||||||
if (dst->Dimension.Index > 0)
|
if (dst->Dimension.Index > 0)
|
||||||
CHR( '+' );
|
CHR( '+' );
|
||||||
|
|
@ -271,11 +275,11 @@ _dump_register_dst(
|
||||||
}
|
}
|
||||||
if (dst->Register.Indirect) {
|
if (dst->Register.Indirect) {
|
||||||
CHR( '[' );
|
CHR( '[' );
|
||||||
ENM( dst->Indirect.File, file_names );
|
ENM( dst->Indirect.File, tgsi_file_names );
|
||||||
CHR( '[' );
|
CHR( '[' );
|
||||||
SID( dst->Indirect.Index );
|
SID( dst->Indirect.Index );
|
||||||
TXT( "]." );
|
TXT( "]." );
|
||||||
ENM( dst->Indirect.SwizzleX, swizzle_names );
|
ENM( dst->Indirect.SwizzleX, tgsi_swizzle_names );
|
||||||
if (dst->Register.Index != 0) {
|
if (dst->Register.Index != 0) {
|
||||||
if (dst->Register.Index > 0)
|
if (dst->Register.Index > 0)
|
||||||
CHR( '+' );
|
CHR( '+' );
|
||||||
|
|
@ -351,7 +355,7 @@ iter_declaration(
|
||||||
|
|
||||||
TXT( "DCL " );
|
TXT( "DCL " );
|
||||||
|
|
||||||
ENM(decl->Declaration.File, file_names);
|
ENM(decl->Declaration.File, tgsi_file_names);
|
||||||
|
|
||||||
/* all geometry shader inputs are two dimensional */
|
/* all geometry shader inputs are two dimensional */
|
||||||
if (decl->Declaration.File == TGSI_FILE_INPUT &&
|
if (decl->Declaration.File == TGSI_FILE_INPUT &&
|
||||||
|
|
@ -585,10 +589,10 @@ iter_instruction(
|
||||||
inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
|
inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
|
||||||
inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
|
inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
|
||||||
CHR( '.' );
|
CHR( '.' );
|
||||||
ENM( inst->Predicate.SwizzleX, swizzle_names );
|
ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names );
|
||||||
ENM( inst->Predicate.SwizzleY, swizzle_names );
|
ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names );
|
||||||
ENM( inst->Predicate.SwizzleZ, swizzle_names );
|
ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names );
|
||||||
ENM( inst->Predicate.SwizzleW, swizzle_names );
|
ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names );
|
||||||
}
|
}
|
||||||
|
|
||||||
TXT( ") " );
|
TXT( ") " );
|
||||||
|
|
@ -641,10 +645,10 @@ iter_instruction(
|
||||||
src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
|
src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
|
||||||
src->Register.SwizzleW != TGSI_SWIZZLE_W) {
|
src->Register.SwizzleW != TGSI_SWIZZLE_W) {
|
||||||
CHR( '.' );
|
CHR( '.' );
|
||||||
ENM( src->Register.SwizzleX, swizzle_names );
|
ENM( src->Register.SwizzleX, tgsi_swizzle_names );
|
||||||
ENM( src->Register.SwizzleY, swizzle_names );
|
ENM( src->Register.SwizzleY, tgsi_swizzle_names );
|
||||||
ENM( src->Register.SwizzleZ, swizzle_names );
|
ENM( src->Register.SwizzleZ, tgsi_swizzle_names );
|
||||||
ENM( src->Register.SwizzleW, swizzle_names );
|
ENM( src->Register.SwizzleW, tgsi_swizzle_names );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->Register.Absolute)
|
if (src->Register.Absolute)
|
||||||
|
|
@ -655,7 +659,7 @@ iter_instruction(
|
||||||
|
|
||||||
if (inst->Instruction.Texture) {
|
if (inst->Instruction.Texture) {
|
||||||
TXT( ", " );
|
TXT( ", " );
|
||||||
ENM( inst->Texture.Texture, texture_names );
|
ENM( inst->Texture.Texture, tgsi_texture_names );
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (inst->Instruction.Opcode) {
|
switch (inst->Instruction.Opcode) {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,15 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern const char *
|
||||||
|
tgsi_file_names[TGSI_FILE_COUNT];
|
||||||
|
|
||||||
|
extern const char *
|
||||||
|
tgsi_swizzle_names[];
|
||||||
|
|
||||||
|
extern const char *
|
||||||
|
tgsi_texture_names[];
|
||||||
|
|
||||||
void
|
void
|
||||||
tgsi_dump_str(
|
tgsi_dump_str(
|
||||||
const struct tgsi_token *tokens,
|
const struct tgsi_token *tokens,
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,7 @@ tgsi_scan_shader(const struct tgsi_token *tokens,
|
||||||
info->input_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name;
|
info->input_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name;
|
||||||
info->input_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index;
|
info->input_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index;
|
||||||
info->input_interpolate[reg] = (ubyte)fulldecl->Declaration.Interpolate;
|
info->input_interpolate[reg] = (ubyte)fulldecl->Declaration.Interpolate;
|
||||||
|
info->input_centroid[reg] = (ubyte)fulldecl->Declaration.Centroid;
|
||||||
info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Declaration.CylindricalWrap;
|
info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Declaration.CylindricalWrap;
|
||||||
info->num_inputs++;
|
info->num_inputs++;
|
||||||
}
|
}
|
||||||
|
|
@ -157,9 +158,11 @@ tgsi_scan_shader(const struct tgsi_token *tokens,
|
||||||
|
|
||||||
/* extra info for special outputs */
|
/* extra info for special outputs */
|
||||||
if (procType == TGSI_PROCESSOR_FRAGMENT &&
|
if (procType == TGSI_PROCESSOR_FRAGMENT &&
|
||||||
fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION) {
|
fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION)
|
||||||
info->writes_z = TRUE;
|
info->writes_z = TRUE;
|
||||||
}
|
if (procType == TGSI_PROCESSOR_FRAGMENT &&
|
||||||
|
fulldecl->Semantic.Name == TGSI_SEMANTIC_STENCIL)
|
||||||
|
info->writes_stencil = TRUE;
|
||||||
if (procType == TGSI_PROCESSOR_VERTEX &&
|
if (procType == TGSI_PROCESSOR_VERTEX &&
|
||||||
fulldecl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG) {
|
fulldecl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG) {
|
||||||
info->writes_edgeflag = TRUE;
|
info->writes_edgeflag = TRUE;
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ struct tgsi_shader_info
|
||||||
ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; /**< TGSI_SEMANTIC_x */
|
ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; /**< TGSI_SEMANTIC_x */
|
||||||
ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS];
|
ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS];
|
||||||
ubyte input_interpolate[PIPE_MAX_SHADER_INPUTS];
|
ubyte input_interpolate[PIPE_MAX_SHADER_INPUTS];
|
||||||
|
ubyte input_centroid[PIPE_MAX_SHADER_INPUTS];
|
||||||
ubyte input_usage_mask[PIPE_MAX_SHADER_INPUTS];
|
ubyte input_usage_mask[PIPE_MAX_SHADER_INPUTS];
|
||||||
ubyte input_cylindrical_wrap[PIPE_MAX_SHADER_INPUTS];
|
ubyte input_cylindrical_wrap[PIPE_MAX_SHADER_INPUTS];
|
||||||
ubyte output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; /**< TGSI_SEMANTIC_x */
|
ubyte output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; /**< TGSI_SEMANTIC_x */
|
||||||
|
|
@ -60,6 +61,7 @@ struct tgsi_shader_info
|
||||||
uint opcode_count[TGSI_OPCODE_LAST]; /**< opcode histogram */
|
uint opcode_count[TGSI_OPCODE_LAST]; /**< opcode histogram */
|
||||||
|
|
||||||
boolean writes_z; /**< does fragment shader write Z value? */
|
boolean writes_z; /**< does fragment shader write Z value? */
|
||||||
|
boolean writes_stencil; /**< does fragment shader write stencil value? */
|
||||||
boolean writes_edgeflag; /**< vertex shader outputs edgeflag */
|
boolean writes_edgeflag; /**< vertex shader outputs edgeflag */
|
||||||
boolean uses_kill; /**< KIL or KILP instruction used? */
|
boolean uses_kill; /**< KIL or KILP instruction used? */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,33 @@ struct translate_key {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct translate;
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (PIPE_CDECL *run_elts_func)(struct translate *,
|
||||||
|
const unsigned *elts,
|
||||||
|
unsigned count,
|
||||||
|
unsigned instance_id,
|
||||||
|
void *output_buffer);
|
||||||
|
|
||||||
|
typedef void (PIPE_CDECL *run_elts16_func)(struct translate *,
|
||||||
|
const uint16_t *elts,
|
||||||
|
unsigned count,
|
||||||
|
unsigned instance_id,
|
||||||
|
void *output_buffer);
|
||||||
|
|
||||||
|
typedef void (PIPE_CDECL *run_elts8_func)(struct translate *,
|
||||||
|
const uint8_t *elts,
|
||||||
|
unsigned count,
|
||||||
|
unsigned instance_id,
|
||||||
|
void *output_buffer);
|
||||||
|
|
||||||
|
typedef void (PIPE_CDECL *run_func)(struct translate *,
|
||||||
|
unsigned start,
|
||||||
|
unsigned count,
|
||||||
|
unsigned instance_id,
|
||||||
|
void *output_buffer);
|
||||||
|
|
||||||
struct translate {
|
struct translate {
|
||||||
struct translate_key key;
|
struct translate_key key;
|
||||||
|
|
||||||
|
|
@ -79,42 +106,14 @@ struct translate {
|
||||||
unsigned stride,
|
unsigned stride,
|
||||||
unsigned max_index );
|
unsigned max_index );
|
||||||
|
|
||||||
void (PIPE_CDECL *run_elts)( struct translate *,
|
run_elts_func run_elts;
|
||||||
const unsigned *elts,
|
run_elts16_func run_elts16;
|
||||||
unsigned count,
|
run_elts8_func run_elts8;
|
||||||
unsigned instance_id,
|
run_func run;
|
||||||
void *output_buffer);
|
|
||||||
|
|
||||||
void (PIPE_CDECL *run_elts16)( struct translate *,
|
|
||||||
const uint16_t *elts,
|
|
||||||
unsigned count,
|
|
||||||
unsigned instance_id,
|
|
||||||
void *output_buffer);
|
|
||||||
|
|
||||||
void (PIPE_CDECL *run_elts8)( struct translate *,
|
|
||||||
const uint8_t *elts,
|
|
||||||
unsigned count,
|
|
||||||
unsigned instance_id,
|
|
||||||
void *output_buffer);
|
|
||||||
|
|
||||||
void (PIPE_CDECL *run)( struct translate *,
|
|
||||||
unsigned start,
|
|
||||||
unsigned count,
|
|
||||||
unsigned instance_id,
|
|
||||||
void *output_buffer);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
struct translate_context *translate_context_create( void );
|
|
||||||
void translate_context_destroy( struct translate_context * );
|
|
||||||
|
|
||||||
struct translate *translate_lookup_or_create( struct translate_context *tctx,
|
|
||||||
const struct translate_key *key );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
struct translate *translate_create( const struct translate_key *key );
|
struct translate *translate_create( const struct translate_key *key );
|
||||||
|
|
||||||
boolean translate_is_output_format_supported(enum pipe_format format);
|
boolean translate_is_output_format_supported(enum pipe_format format);
|
||||||
|
|
|
||||||
|
|
@ -1495,19 +1495,19 @@ struct translate *translate_sse2_create( const struct translate_key *key )
|
||||||
if (!build_vertex_emit(p, &p->elt8_func, 1))
|
if (!build_vertex_emit(p, &p->elt8_func, 1))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
p->translate.run = (void*)x86_get_func(&p->linear_func);
|
p->translate.run = (run_func) x86_get_func(&p->linear_func);
|
||||||
if (p->translate.run == NULL)
|
if (p->translate.run == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
p->translate.run_elts = (void*)x86_get_func(&p->elt_func);
|
p->translate.run_elts = (run_elts_func) x86_get_func(&p->elt_func);
|
||||||
if (p->translate.run_elts == NULL)
|
if (p->translate.run_elts == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
p->translate.run_elts16 = (void*)x86_get_func(&p->elt16_func);
|
p->translate.run_elts16 = (run_elts16_func) x86_get_func(&p->elt16_func);
|
||||||
if (p->translate.run_elts16 == NULL)
|
if (p->translate.run_elts16 == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
p->translate.run_elts8 = (void*)x86_get_func(&p->elt8_func);
|
p->translate.run_elts8 = (run_elts8_func) x86_get_func(&p->elt8_func);
|
||||||
if (p->translate.run_elts8 == NULL)
|
if (p->translate.run_elts8 == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "u_dl.h"
|
#include "u_dl.h"
|
||||||
|
#include "u_pointer.h"
|
||||||
|
|
||||||
|
|
||||||
struct util_dl_library *
|
struct util_dl_library *
|
||||||
|
|
@ -58,7 +59,7 @@ util_dl_get_proc_address(struct util_dl_library *library,
|
||||||
const char *procname)
|
const char *procname)
|
||||||
{
|
{
|
||||||
#if defined(PIPE_OS_UNIX)
|
#if defined(PIPE_OS_UNIX)
|
||||||
return (util_dl_proc)dlsym((void *)library, procname);
|
return (util_dl_proc) pointer_to_func(dlsym((void *)library, procname));
|
||||||
#elif defined(PIPE_OS_WINDOWS)
|
#elif defined(PIPE_OS_WINDOWS)
|
||||||
return (util_dl_proc)GetProcAddress((HMODULE)library, procname);
|
return (util_dl_proc)GetProcAddress((HMODULE)library, procname);
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -109,9 +109,12 @@ PIPE_FORMAT_Z32_UNORM , plain, 1, 1, un32, , , , x___,
|
||||||
PIPE_FORMAT_Z32_FLOAT , plain, 1, 1, f32 , , , , x___, zs
|
PIPE_FORMAT_Z32_FLOAT , plain, 1, 1, f32 , , , , x___, zs
|
||||||
PIPE_FORMAT_Z24_UNORM_S8_USCALED , plain, 1, 1, un24, u8 , , , xy__, zs
|
PIPE_FORMAT_Z24_UNORM_S8_USCALED , plain, 1, 1, un24, u8 , , , xy__, zs
|
||||||
PIPE_FORMAT_S8_USCALED_Z24_UNORM , plain, 1, 1, u8 , un24, , , yx__, zs
|
PIPE_FORMAT_S8_USCALED_Z24_UNORM , plain, 1, 1, u8 , un24, , , yx__, zs
|
||||||
|
PIPE_FORMAT_X24S8_USCALED , plain, 1, 1, x24, u8 , , , _y__, zs
|
||||||
|
PIPE_FORMAT_S8X24_USCALED , plain, 1, 1, u8 , x24 , , , _x__, zs
|
||||||
PIPE_FORMAT_Z24X8_UNORM , plain, 1, 1, un24, x8 , , , x___, zs
|
PIPE_FORMAT_Z24X8_UNORM , plain, 1, 1, un24, x8 , , , x___, zs
|
||||||
PIPE_FORMAT_X8Z24_UNORM , plain, 1, 1, x8 , un24, , , y___, zs
|
PIPE_FORMAT_X8Z24_UNORM , plain, 1, 1, x8 , un24, , , y___, zs
|
||||||
PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED , plain, 1, 1, f32, u8 , x24 , , xy__, zs
|
PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED , plain, 1, 1, f32, u8 , x24 , , xy__, zs
|
||||||
|
PIPE_FORMAT_X32_S8X24_USCALED , plain, 1, 1, x32, u8 , x24 , , _y__, zs
|
||||||
|
|
||||||
# YUV formats
|
# YUV formats
|
||||||
# http://www.fourcc.org/yuv.php#UYVY
|
# http://www.fourcc.org/yuv.php#UYVY
|
||||||
|
|
|
||||||
|
Can't render this file because it contains an unexpected character in line 8 and column 3.
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
'''
|
CopyRight = '''
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright 2010 VMware, Inc.
|
* Copyright 2010 VMware, Inc.
|
||||||
|
|
@ -89,7 +89,7 @@ def main():
|
||||||
print '/* This file is autogenerated by u_format_srgb.py. Do not edit directly. */'
|
print '/* This file is autogenerated by u_format_srgb.py. Do not edit directly. */'
|
||||||
print
|
print
|
||||||
# This will print the copyright message on the top of this file
|
# This will print the copyright message on the top of this file
|
||||||
print __doc__.strip()
|
print CopyRight.strip()
|
||||||
print
|
print
|
||||||
print '#include "u_format_srgb.h"'
|
print '#include "u_format_srgb.h"'
|
||||||
print
|
print
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
'''
|
CopyRight = '''
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright 2010 VMware, Inc.
|
* Copyright 2010 VMware, Inc.
|
||||||
|
|
@ -83,7 +83,7 @@ def write_format_table(formats):
|
||||||
print '/* This file is autogenerated by u_format_table.py from u_format.csv. Do not edit directly. */'
|
print '/* This file is autogenerated by u_format_table.py from u_format.csv. Do not edit directly. */'
|
||||||
print
|
print
|
||||||
# This will print the copyright message on the top of this file
|
# This will print the copyright message on the top of this file
|
||||||
print __doc__.strip()
|
print CopyRight.strip()
|
||||||
print
|
print
|
||||||
print '#include "u_format.h"'
|
print '#include "u_format.h"'
|
||||||
print '#include "u_format_s3tc.h"'
|
print '#include "u_format_s3tc.h"'
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,5 +192,21 @@ util_format_z32_float_s8x24_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned
|
||||||
void
|
void
|
||||||
util_format_z32_float_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
|
util_format_z32_float_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
|
||||||
|
|
||||||
|
void
|
||||||
|
util_format_x24s8_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
|
||||||
|
|
||||||
|
void
|
||||||
|
util_format_x24s8_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
|
||||||
|
|
||||||
|
void
|
||||||
|
util_format_s8x24_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
|
||||||
|
|
||||||
|
void
|
||||||
|
util_format_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
|
||||||
|
|
||||||
|
void
|
||||||
|
util_format_x32_s8x24_uscaled_unpack_s_8uscaled(uint8_t *dst_row, unsigned dst_stride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
|
||||||
|
|
||||||
|
void
|
||||||
|
util_format_x32_s8x24_uscaled_pack_s_8uscaled(uint8_t *dst_row, unsigned dst_sride, const uint8_t *src_row, unsigned src_stride, unsigned width, unsigned height);
|
||||||
#endif /* U_FORMAT_ZS_H_ */
|
#endif /* U_FORMAT_ZS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,11 @@ __inline double __cdecl atan2(double val)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef M_SQRT2
|
||||||
|
#define M_SQRT2 1.41421356237309504880
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
#if _MSC_VER < 1400 && !defined(__cplusplus) || defined(PIPE_SUBSYSTEM_WINDOWS_CE)
|
#if _MSC_VER < 1400 && !defined(__cplusplus) || defined(PIPE_SUBSYSTEM_WINDOWS_CE)
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,96 @@ _mm_castps_si128(__m128 a)
|
||||||
|
|
||||||
#endif /* defined(_MSC_VER) && _MSC_VER < 1500 */
|
#endif /* defined(_MSC_VER) && _MSC_VER < 1500 */
|
||||||
|
|
||||||
|
union m128i {
|
||||||
|
__m128i m;
|
||||||
|
ubyte ub[16];
|
||||||
|
ushort us[8];
|
||||||
|
uint ui[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static INLINE void u_print_epi8(const char *name, __m128i r)
|
||||||
|
{
|
||||||
|
union { __m128i m; ubyte ub[16]; } u;
|
||||||
|
u.m = r;
|
||||||
|
|
||||||
|
debug_printf("%s: "
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x/"
|
||||||
|
"%02x\n",
|
||||||
|
name,
|
||||||
|
u.ub[0], u.ub[1], u.ub[2], u.ub[3],
|
||||||
|
u.ub[4], u.ub[5], u.ub[6], u.ub[7],
|
||||||
|
u.ub[8], u.ub[9], u.ub[10], u.ub[11],
|
||||||
|
u.ub[12], u.ub[13], u.ub[14], u.ub[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE void u_print_epi16(const char *name, __m128i r)
|
||||||
|
{
|
||||||
|
union { __m128i m; ushort us[8]; } u;
|
||||||
|
u.m = r;
|
||||||
|
|
||||||
|
debug_printf("%s: "
|
||||||
|
"%04x/"
|
||||||
|
"%04x/"
|
||||||
|
"%04x/"
|
||||||
|
"%04x/"
|
||||||
|
"%04x/"
|
||||||
|
"%04x/"
|
||||||
|
"%04x/"
|
||||||
|
"%04x\n",
|
||||||
|
name,
|
||||||
|
u.us[0], u.us[1], u.us[2], u.us[3],
|
||||||
|
u.us[4], u.us[5], u.us[6], u.us[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE void u_print_epi32(const char *name, __m128i r)
|
||||||
|
{
|
||||||
|
union { __m128i m; uint ui[4]; } u;
|
||||||
|
u.m = r;
|
||||||
|
|
||||||
|
debug_printf("%s: "
|
||||||
|
"%08x/"
|
||||||
|
"%08x/"
|
||||||
|
"%08x/"
|
||||||
|
"%08x\n",
|
||||||
|
name,
|
||||||
|
u.ui[0], u.ui[1], u.ui[2], u.ui[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE void u_print_ps(const char *name, __m128 r)
|
||||||
|
{
|
||||||
|
union { __m128 m; float f[4]; } u;
|
||||||
|
u.m = r;
|
||||||
|
|
||||||
|
debug_printf("%s: "
|
||||||
|
"%f/"
|
||||||
|
"%f/"
|
||||||
|
"%f/"
|
||||||
|
"%f\n",
|
||||||
|
name,
|
||||||
|
u.f[0], u.f[1], u.f[2], u.f[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define U_DUMP_EPI32(a) u_print_epi32(#a, a)
|
||||||
|
#define U_DUMP_EPI16(a) u_print_epi16(#a, a)
|
||||||
|
#define U_DUMP_EPI8(a) u_print_epi8(#a, a)
|
||||||
|
#define U_DUMP_PS(a) u_print_ps(#a, a)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(PIPE_ARCH_SSSE3)
|
#if defined(PIPE_ARCH_SSSE3)
|
||||||
|
|
||||||
|
|
@ -98,6 +188,68 @@ _mm_shuffle_epi8(__m128i a, __m128i mask)
|
||||||
#endif /* !PIPE_ARCH_SSSE3 */
|
#endif /* !PIPE_ARCH_SSSE3 */
|
||||||
|
|
||||||
|
|
||||||
#endif /* PIPE_ARCH_X86 || PIPE_ARCH_X86_64 */
|
|
||||||
|
|
||||||
|
/* Provide an SSE2 implementation of _mm_mullo_epi32() in terms of
|
||||||
|
* _mm_mul_epu32().
|
||||||
|
*
|
||||||
|
* I suspect this works fine for us because one of our operands is
|
||||||
|
* always positive, but not sure that this can be used for general
|
||||||
|
* signed integer multiplication.
|
||||||
|
*
|
||||||
|
* This seems close enough to the speed of SSE4 and the real
|
||||||
|
* _mm_mullo_epi32() intrinsic as to not justify adding an sse4
|
||||||
|
* dependency at this point.
|
||||||
|
*/
|
||||||
|
static INLINE __m128i mm_mullo_epi32(const __m128i a, const __m128i b)
|
||||||
|
{
|
||||||
|
__m128i a4 = _mm_srli_epi64(a, 32); /* shift by one dword */
|
||||||
|
__m128i b4 = _mm_srli_epi64(b, 32); /* shift by one dword */
|
||||||
|
__m128i ba = _mm_mul_epu32(b, a); /* multply dwords 0, 2 */
|
||||||
|
__m128i b4a4 = _mm_mul_epu32(b4, a4); /* multiply dwords 1, 3 */
|
||||||
|
|
||||||
|
/* Interleave the results, either with shuffles or (slightly
|
||||||
|
* faster) direct bit operations:
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
__m128i ba8 = _mm_shuffle_epi32(ba, 8);
|
||||||
|
__m128i b4a48 = _mm_shuffle_epi32(b4a4, 8);
|
||||||
|
__m128i result = _mm_unpacklo_epi32(ba8, b4a48);
|
||||||
|
#else
|
||||||
|
__m128i mask = _mm_setr_epi32(~0,0,~0,0);
|
||||||
|
__m128i ba_mask = _mm_and_si128(ba, mask);
|
||||||
|
__m128i b4a4_mask_shift = _mm_slli_epi64(b4a4, 32);
|
||||||
|
__m128i result = _mm_or_si128(ba_mask, b4a4_mask_shift);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static INLINE void
|
||||||
|
transpose4_epi32(const __m128i * restrict a,
|
||||||
|
const __m128i * restrict b,
|
||||||
|
const __m128i * restrict c,
|
||||||
|
const __m128i * restrict d,
|
||||||
|
__m128i * restrict o,
|
||||||
|
__m128i * restrict p,
|
||||||
|
__m128i * restrict q,
|
||||||
|
__m128i * restrict r)
|
||||||
|
{
|
||||||
|
__m128i t0 = _mm_unpacklo_epi32(*a, *b);
|
||||||
|
__m128i t1 = _mm_unpacklo_epi32(*c, *d);
|
||||||
|
__m128i t2 = _mm_unpackhi_epi32(*a, *b);
|
||||||
|
__m128i t3 = _mm_unpackhi_epi32(*c, *d);
|
||||||
|
|
||||||
|
*o = _mm_unpacklo_epi64(t0, t1);
|
||||||
|
*p = _mm_unpackhi_epi64(t0, t1);
|
||||||
|
*q = _mm_unpacklo_epi64(t2, t3);
|
||||||
|
*r = _mm_unpackhi_epi64(t2, t3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SCALAR_EPI32(m, i) _mm_shuffle_epi32((m), _MM_SHUFFLE(i,i,i,i))
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* PIPE_ARCH_SSE */
|
||||||
|
|
||||||
#endif /* U_SSE_H_ */
|
#endif /* U_SSE_H_ */
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,81 @@ z24s8_get_tile_rgba(const unsigned *src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** PIPE_FORMAT_S8X24_USCALED ***/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return S component as four uint32_t in [0..255]. Z part ignored.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
s8x24_get_tile_rgba(const unsigned *src,
|
||||||
|
unsigned w, unsigned h,
|
||||||
|
float *p,
|
||||||
|
unsigned dst_stride)
|
||||||
|
{
|
||||||
|
unsigned i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < h; i++) {
|
||||||
|
float *pRow = p;
|
||||||
|
|
||||||
|
for (j = 0; j < w; j++, pRow += 4) {
|
||||||
|
pRow[0] =
|
||||||
|
pRow[1] =
|
||||||
|
pRow[2] =
|
||||||
|
pRow[3] = (float)((*src++ >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
p += dst_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** PIPE_FORMAT_X24S8_USCALED ***/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return S component as four uint32_t in [0..255]. Z part ignored.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
x24s8_get_tile_rgba(const unsigned *src,
|
||||||
|
unsigned w, unsigned h,
|
||||||
|
float *p,
|
||||||
|
unsigned dst_stride)
|
||||||
|
{
|
||||||
|
unsigned i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < h; i++) {
|
||||||
|
float *pRow = p;
|
||||||
|
for (j = 0; j < w; j++, pRow += 4) {
|
||||||
|
pRow[0] =
|
||||||
|
pRow[1] =
|
||||||
|
pRow[2] =
|
||||||
|
pRow[3] = (float)(*src++ & 0xff);
|
||||||
|
}
|
||||||
|
p += dst_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return S component as four uint32_t in [0..255]. Z part ignored.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
s8_get_tile_rgba(const unsigned char *src,
|
||||||
|
unsigned w, unsigned h,
|
||||||
|
float *p,
|
||||||
|
unsigned dst_stride)
|
||||||
|
{
|
||||||
|
unsigned i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < h; i++) {
|
||||||
|
float *pRow = p;
|
||||||
|
for (j = 0; j < w; j++, pRow += 4) {
|
||||||
|
pRow[0] =
|
||||||
|
pRow[1] =
|
||||||
|
pRow[2] =
|
||||||
|
pRow[3] = (float)(*src++ & 0xff);
|
||||||
|
}
|
||||||
|
p += dst_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*** PIPE_FORMAT_Z32_FLOAT ***/
|
/*** PIPE_FORMAT_Z32_FLOAT ***/
|
||||||
|
|
||||||
|
|
@ -261,10 +336,19 @@ pipe_tile_raw_to_rgba(enum pipe_format format,
|
||||||
case PIPE_FORMAT_Z24X8_UNORM:
|
case PIPE_FORMAT_Z24X8_UNORM:
|
||||||
s8z24_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
|
s8z24_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
|
||||||
break;
|
break;
|
||||||
|
case PIPE_FORMAT_S8_USCALED:
|
||||||
|
s8_get_tile_rgba((unsigned char *) src, w, h, dst, dst_stride);
|
||||||
|
break;
|
||||||
|
case PIPE_FORMAT_X24S8_USCALED:
|
||||||
|
s8x24_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
|
||||||
|
break;
|
||||||
case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
|
case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
|
||||||
case PIPE_FORMAT_X8Z24_UNORM:
|
case PIPE_FORMAT_X8Z24_UNORM:
|
||||||
z24s8_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
|
z24s8_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
|
||||||
break;
|
break;
|
||||||
|
case PIPE_FORMAT_S8X24_USCALED:
|
||||||
|
x24s8_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride);
|
||||||
|
break;
|
||||||
case PIPE_FORMAT_Z32_FLOAT:
|
case PIPE_FORMAT_Z32_FLOAT:
|
||||||
z32f_get_tile_rgba((float *) src, w, h, dst, dst_stride);
|
z32f_get_tile_rgba((float *) src, w, h, dst, dst_stride);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,15 @@ If there is an index buffer bound, and ``indexed`` field is true, all vertex
|
||||||
indices will be looked up in the index buffer. ``min_index``, ``max_index``,
|
indices will be looked up in the index buffer. ``min_index``, ``max_index``,
|
||||||
and ``index_bias`` apply after index lookup.
|
and ``index_bias`` apply after index lookup.
|
||||||
|
|
||||||
|
When drawing indexed primitives, the primitive restart index can be
|
||||||
|
used to draw disjoint primitive strips. For example, several separate
|
||||||
|
line strips can be drawn by designating a special index value as the
|
||||||
|
restart index. The ``primitive_restart`` flag enables/disables this
|
||||||
|
feature. The ``restart_index`` field specifies the restart index value.
|
||||||
|
|
||||||
|
When primitive restart is in use, array indexes are compared to the
|
||||||
|
restart index before adding the index_bias offset.
|
||||||
|
|
||||||
If a given vertex element has ``instance_divisor`` set to 0, it is said
|
If a given vertex element has ``instance_divisor`` set to 0, it is said
|
||||||
it contains per-vertex data and effective vertex attribute address needs
|
it contains per-vertex data and effective vertex attribute address needs
|
||||||
to be recalculated for every index.
|
to be recalculated for every index.
|
||||||
|
|
|
||||||
|
|
@ -1415,6 +1415,12 @@ Edge flags are used to control which lines or points are actually
|
||||||
drawn when the polygon mode converts triangles/quads/polygons into
|
drawn when the polygon mode converts triangles/quads/polygons into
|
||||||
points or lines.
|
points or lines.
|
||||||
|
|
||||||
|
TGSI_SEMANTIC_STENCIL
|
||||||
|
""""""""""""""""""""""
|
||||||
|
|
||||||
|
For fragment shaders, this semantic label indicates than an output
|
||||||
|
is a writable stencil reference value. Only the Y component is writable.
|
||||||
|
This allows the fragment shader to change the fragments stencilref value.
|
||||||
|
|
||||||
|
|
||||||
Properties
|
Properties
|
||||||
|
|
@ -1493,6 +1499,8 @@ well.
|
||||||
| Z | XXX TBD | (z, z, z, 1) | (0, z, 0, 1) |
|
| Z | XXX TBD | (z, z, z, 1) | (0, z, 0, 1) |
|
||||||
| | | [#depth-tex-mode]_ | |
|
| | | [#depth-tex-mode]_ | |
|
||||||
+--------------------+--------------+--------------------+--------------+
|
+--------------------+--------------+--------------------+--------------+
|
||||||
|
| S | (s, s, s, s) | unknown | unknown |
|
||||||
|
+--------------------+--------------+--------------------+--------------+
|
||||||
|
|
||||||
.. [#envmap-bumpmap] http://www.opengl.org/registry/specs/ATI/envmap_bumpmap.txt
|
.. [#envmap-bumpmap] http://www.opengl.org/registry/specs/ATI/envmap_bumpmap.txt
|
||||||
.. [#depth-tex-mode] the default is (z, z, z, 1) but may also be (0, 0, 0, z)
|
.. [#depth-tex-mode] the default is (z, z, z, 1) but may also be (0, 0, 0, z)
|
||||||
|
|
|
||||||
|
|
@ -641,7 +641,7 @@ galahad_set_index_buffer(struct pipe_context *_pipe,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
glhd_warn("index buffer %p has unrecognized index size %d",
|
glhd_warn("index buffer %p has unrecognized index size %d",
|
||||||
_ib->buffer, _ib->index_size);
|
(void *) _ib->buffer, _ib->index_size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1013,7 +1013,7 @@ galahad_context_create(struct pipe_screen *_screen, struct pipe_context *pipe)
|
||||||
|
|
||||||
glhd_pipe->pipe = pipe;
|
glhd_pipe->pipe = pipe;
|
||||||
|
|
||||||
glhd_warn("Created context %p", glhd_pipe);
|
glhd_warn("Created context %p", (void *) glhd_pipe);
|
||||||
|
|
||||||
return &glhd_pipe->base;
|
return &glhd_pipe->base;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -370,7 +370,7 @@ galahad_screen_create(struct pipe_screen *screen)
|
||||||
|
|
||||||
glhd_screen->screen = screen;
|
glhd_screen->screen = screen;
|
||||||
|
|
||||||
glhd_warn("Created screen %p", glhd_screen);
|
glhd_warn("Created screen %p", (void *) glhd_screen);
|
||||||
|
|
||||||
return &glhd_screen->base;
|
return &glhd_screen->base;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ C_SOURCES = \
|
||||||
lp_scene_queue.c \
|
lp_scene_queue.c \
|
||||||
lp_screen.c \
|
lp_screen.c \
|
||||||
lp_setup.c \
|
lp_setup.c \
|
||||||
lp_setup_coef.c \
|
|
||||||
lp_setup_coef_intrin.c \
|
|
||||||
lp_setup_line.c \
|
lp_setup_line.c \
|
||||||
lp_setup_point.c \
|
lp_setup_point.c \
|
||||||
lp_setup_tri.c \
|
lp_setup_tri.c \
|
||||||
|
|
@ -38,6 +36,7 @@ C_SOURCES = \
|
||||||
lp_state_clip.c \
|
lp_state_clip.c \
|
||||||
lp_state_derived.c \
|
lp_state_derived.c \
|
||||||
lp_state_fs.c \
|
lp_state_fs.c \
|
||||||
|
lp_state_setup.c \
|
||||||
lp_state_gs.c \
|
lp_state_gs.c \
|
||||||
lp_state_rasterizer.c \
|
lp_state_rasterizer.c \
|
||||||
lp_state_sampler.c \
|
lp_state_sampler.c \
|
||||||
|
|
@ -63,14 +62,14 @@ PROGS := lp_test_format \
|
||||||
# Need this for the lp_test_*.o files
|
# Need this for the lp_test_*.o files
|
||||||
CLEAN_EXTRA = *.o
|
CLEAN_EXTRA = *.o
|
||||||
|
|
||||||
|
include ../../Makefile.template
|
||||||
|
|
||||||
lp_test_sincos.o : sse_mathfun.h
|
lp_test_sincos.o : sse_mathfun.h
|
||||||
|
|
||||||
PROGS_DEPS := ../../auxiliary/libgallium.a
|
PROGS_DEPS := ../../auxiliary/libgallium.a
|
||||||
|
|
||||||
include ../../Makefile.template
|
|
||||||
|
|
||||||
lp_tile_soa.c: lp_tile_soa.py ../../auxiliary/util/u_format_parse.py ../../auxiliary/util/u_format_pack.py ../../auxiliary/util/u_format.csv
|
lp_tile_soa.c: lp_tile_soa.py ../../auxiliary/util/u_format_parse.py ../../auxiliary/util/u_format_pack.py ../../auxiliary/util/u_format.csv
|
||||||
python lp_tile_soa.py ../../auxiliary/util/u_format.csv > $@
|
$(PYTHON2) $(PYTHON_FLAGS) lp_tile_soa.py ../../auxiliary/util/u_format.csv > $@
|
||||||
|
|
||||||
LDFLAGS += $(LLVM_LDFLAGS)
|
LDFLAGS += $(LLVM_LDFLAGS)
|
||||||
LIBS += -L../../auxiliary/ -lgallium libllvmpipe.a $(LLVM_LIBS) $(GL_LIB_DEPS)
|
LIBS += -L../../auxiliary/ -lgallium libllvmpipe.a $(LLVM_LIBS) $(GL_LIB_DEPS)
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,7 @@ env.Depends('lp_tile_soa.c', [
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
# Only enable SSSE3 for lp_tile_soa_sse3.c
|
lp_tile_soa_os = env.SharedObject('lp_tile_soa.c')
|
||||||
ssse3_env = env.Clone()
|
|
||||||
if env['gcc'] \
|
|
||||||
and distutils.version.LooseVersion(env['CCVERSION']) >= distutils.version.LooseVersion('4.3') \
|
|
||||||
and env['machine'] in ('x86', 'x86_64') :
|
|
||||||
ssse3_env.Append(CCFLAGS = ['-mssse3'])
|
|
||||||
lp_tile_soa_os = ssse3_env.SharedObject('lp_tile_soa.c')
|
|
||||||
|
|
||||||
|
|
||||||
llvmpipe = env.ConvenienceLibrary(
|
llvmpipe = env.ConvenienceLibrary(
|
||||||
|
|
@ -64,13 +58,12 @@ llvmpipe = env.ConvenienceLibrary(
|
||||||
'lp_setup_line.c',
|
'lp_setup_line.c',
|
||||||
'lp_setup_point.c',
|
'lp_setup_point.c',
|
||||||
'lp_setup_tri.c',
|
'lp_setup_tri.c',
|
||||||
'lp_setup_coef.c',
|
|
||||||
'lp_setup_coef_intrin.c',
|
|
||||||
'lp_setup_vbuf.c',
|
'lp_setup_vbuf.c',
|
||||||
'lp_state_blend.c',
|
'lp_state_blend.c',
|
||||||
'lp_state_clip.c',
|
'lp_state_clip.c',
|
||||||
'lp_state_derived.c',
|
'lp_state_derived.c',
|
||||||
'lp_state_fs.c',
|
'lp_state_fs.c',
|
||||||
|
'lp_state_setup.c',
|
||||||
'lp_state_gs.c',
|
'lp_state_gs.c',
|
||||||
'lp_state_rasterizer.c',
|
'lp_state_rasterizer.c',
|
||||||
'lp_state_sampler.c',
|
'lp_state_sampler.c',
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ lp_build_alpha_test(LLVMBuilderRef builder,
|
||||||
struct lp_type type,
|
struct lp_type type,
|
||||||
struct lp_build_mask_context *mask,
|
struct lp_build_mask_context *mask,
|
||||||
LLVMValueRef alpha,
|
LLVMValueRef alpha,
|
||||||
LLVMValueRef ref)
|
LLVMValueRef ref,
|
||||||
|
boolean do_branch)
|
||||||
{
|
{
|
||||||
struct lp_build_context bld;
|
struct lp_build_context bld;
|
||||||
LLVMValueRef test;
|
LLVMValueRef test;
|
||||||
|
|
@ -60,4 +61,7 @@ lp_build_alpha_test(LLVMBuilderRef builder,
|
||||||
lp_build_name(test, "alpha_mask");
|
lp_build_name(test, "alpha_mask");
|
||||||
|
|
||||||
lp_build_mask_update(mask, test);
|
lp_build_mask_update(mask, test);
|
||||||
|
|
||||||
|
if (do_branch)
|
||||||
|
lp_build_mask_check(mask);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ lp_build_alpha_test(LLVMBuilderRef builder,
|
||||||
struct lp_type type,
|
struct lp_type type,
|
||||||
struct lp_build_mask_context *mask,
|
struct lp_build_mask_context *mask,
|
||||||
LLVMValueRef alpha,
|
LLVMValueRef alpha,
|
||||||
LLVMValueRef ref);
|
LLVMValueRef ref,
|
||||||
|
boolean do_branch);
|
||||||
|
|
||||||
|
|
||||||
#endif /* !LP_BLD_ALPHA_H */
|
#endif /* !LP_BLD_ALPHA_H */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright 2009 VMware, Inc.
|
* Copyright 2009-2010 VMware, Inc.
|
||||||
* All Rights Reserved.
|
* All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
|
@ -53,15 +53,8 @@
|
||||||
* ... ... ... ... ... ... ... ... ...
|
* ... ... ... ... ... ... ... ... ...
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Stencil test:
|
|
||||||
* Two-sided stencil test is supported but probably not as efficient as
|
|
||||||
* it could be. Currently, we use if/then/else constructs to do the
|
|
||||||
* operations for front vs. back-facing polygons. We could probably do
|
|
||||||
* both the front and back arithmetic then use a Select() instruction to
|
|
||||||
* choose the result depending on polyon orientation. We'd have to
|
|
||||||
* measure performance both ways and see which is better.
|
|
||||||
*
|
|
||||||
* @author Jose Fonseca <jfonseca@vmware.com>
|
* @author Jose Fonseca <jfonseca@vmware.com>
|
||||||
|
* @author Brian Paul <jfonseca@vmware.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pipe/p_state.h"
|
#include "pipe/p_state.h"
|
||||||
|
|
@ -71,6 +64,7 @@
|
||||||
#include "gallivm/lp_bld_arit.h"
|
#include "gallivm/lp_bld_arit.h"
|
||||||
#include "gallivm/lp_bld_bitarit.h"
|
#include "gallivm/lp_bld_bitarit.h"
|
||||||
#include "gallivm/lp_bld_const.h"
|
#include "gallivm/lp_bld_const.h"
|
||||||
|
#include "gallivm/lp_bld_conv.h"
|
||||||
#include "gallivm/lp_bld_logic.h"
|
#include "gallivm/lp_bld_logic.h"
|
||||||
#include "gallivm/lp_bld_flow.h"
|
#include "gallivm/lp_bld_flow.h"
|
||||||
#include "gallivm/lp_bld_intr.h"
|
#include "gallivm/lp_bld_intr.h"
|
||||||
|
|
@ -310,8 +304,13 @@ lp_depth_type(const struct util_format_description *format_desc,
|
||||||
}
|
}
|
||||||
else if(format_desc->channel[swizzle].type == UTIL_FORMAT_TYPE_UNSIGNED) {
|
else if(format_desc->channel[swizzle].type == UTIL_FORMAT_TYPE_UNSIGNED) {
|
||||||
assert(format_desc->block.bits <= 32);
|
assert(format_desc->block.bits <= 32);
|
||||||
if(format_desc->channel[swizzle].normalized)
|
assert(format_desc->channel[swizzle].normalized);
|
||||||
type.norm = TRUE;
|
if (format_desc->channel[swizzle].size < format_desc->block.bits) {
|
||||||
|
/* Prefer signed integers when possible, as SSE has less support
|
||||||
|
* for unsigned comparison;
|
||||||
|
*/
|
||||||
|
type.sign = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
@ -333,7 +332,7 @@ lp_depth_type(const struct util_format_description *format_desc,
|
||||||
*/
|
*/
|
||||||
static boolean
|
static boolean
|
||||||
get_z_shift_and_mask(const struct util_format_description *format_desc,
|
get_z_shift_and_mask(const struct util_format_description *format_desc,
|
||||||
unsigned *shift, unsigned *mask)
|
unsigned *shift, unsigned *width, unsigned *mask)
|
||||||
{
|
{
|
||||||
const unsigned total_bits = format_desc->block.bits;
|
const unsigned total_bits = format_desc->block.bits;
|
||||||
unsigned z_swizzle;
|
unsigned z_swizzle;
|
||||||
|
|
@ -349,12 +348,14 @@ get_z_shift_and_mask(const struct util_format_description *format_desc,
|
||||||
if (z_swizzle == UTIL_FORMAT_SWIZZLE_NONE)
|
if (z_swizzle == UTIL_FORMAT_SWIZZLE_NONE)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
*width = format_desc->channel[z_swizzle].size;
|
||||||
|
|
||||||
padding_right = 0;
|
padding_right = 0;
|
||||||
for (chan = 0; chan < z_swizzle; ++chan)
|
for (chan = 0; chan < z_swizzle; ++chan)
|
||||||
padding_right += format_desc->channel[chan].size;
|
padding_right += format_desc->channel[chan].size;
|
||||||
|
|
||||||
padding_left =
|
padding_left =
|
||||||
total_bits - (padding_right + format_desc->channel[z_swizzle].size);
|
total_bits - (padding_right + *width);
|
||||||
|
|
||||||
if (padding_left || padding_right) {
|
if (padding_left || padding_right) {
|
||||||
unsigned long long mask_left = (1ULL << (total_bits - padding_left)) - 1;
|
unsigned long long mask_left = (1ULL << (total_bits - padding_left)) - 1;
|
||||||
|
|
@ -365,7 +366,7 @@ get_z_shift_and_mask(const struct util_format_description *format_desc,
|
||||||
*mask = 0xffffffff;
|
*mask = 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
*shift = padding_left;
|
*shift = padding_right;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -409,7 +410,7 @@ get_s_shift_and_mask(const struct util_format_description *format_desc,
|
||||||
* \param maskvalue is the depth test mask.
|
* \param maskvalue is the depth test mask.
|
||||||
* \param counter is a pointer of the uint32 counter.
|
* \param counter is a pointer of the uint32 counter.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
lp_build_occlusion_count(LLVMBuilderRef builder,
|
lp_build_occlusion_count(LLVMBuilderRef builder,
|
||||||
struct lp_type type,
|
struct lp_type type,
|
||||||
LLVMValueRef maskvalue,
|
LLVMValueRef maskvalue,
|
||||||
|
|
@ -446,33 +447,58 @@ lp_build_occlusion_count(LLVMBuilderRef builder,
|
||||||
* \param format_desc description of the depth/stencil surface
|
* \param format_desc description of the depth/stencil surface
|
||||||
* \param mask the alive/dead pixel mask for the quad (vector)
|
* \param mask the alive/dead pixel mask for the quad (vector)
|
||||||
* \param stencil_refs the front/back stencil ref values (scalar)
|
* \param stencil_refs the front/back stencil ref values (scalar)
|
||||||
* \param z_src the incoming depth/stencil values (a 2x2 quad)
|
* \param z_src the incoming depth/stencil values (a 2x2 quad, float32)
|
||||||
* \param zs_dst_ptr pointer to depth/stencil values in framebuffer
|
* \param zs_dst_ptr pointer to depth/stencil values in framebuffer
|
||||||
* \param facing contains float value indicating front/back facing polygon
|
* \param facing contains boolean value indicating front/back facing polygon
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
const struct pipe_depth_state *depth,
|
const struct pipe_depth_state *depth,
|
||||||
const struct pipe_stencil_state stencil[2],
|
const struct pipe_stencil_state stencil[2],
|
||||||
struct lp_type type,
|
struct lp_type z_src_type,
|
||||||
const struct util_format_description *format_desc,
|
const struct util_format_description *format_desc,
|
||||||
struct lp_build_mask_context *mask,
|
struct lp_build_mask_context *mask,
|
||||||
LLVMValueRef stencil_refs[2],
|
LLVMValueRef stencil_refs[2],
|
||||||
LLVMValueRef z_src,
|
LLVMValueRef z_src,
|
||||||
LLVMValueRef zs_dst_ptr,
|
LLVMValueRef zs_dst_ptr,
|
||||||
LLVMValueRef face,
|
LLVMValueRef face,
|
||||||
LLVMValueRef counter)
|
LLVMValueRef *zs_value,
|
||||||
|
boolean do_branch)
|
||||||
{
|
{
|
||||||
struct lp_build_context bld;
|
struct lp_type z_type;
|
||||||
struct lp_build_context sbld;
|
struct lp_build_context z_bld;
|
||||||
|
struct lp_build_context s_bld;
|
||||||
struct lp_type s_type;
|
struct lp_type s_type;
|
||||||
|
unsigned z_shift = 0, z_width = 0, z_mask = 0;
|
||||||
LLVMValueRef zs_dst, z_dst = NULL;
|
LLVMValueRef zs_dst, z_dst = NULL;
|
||||||
LLVMValueRef stencil_vals = NULL;
|
LLVMValueRef stencil_vals = NULL;
|
||||||
LLVMValueRef z_bitmask = NULL, stencil_shift = NULL;
|
LLVMValueRef z_bitmask = NULL, stencil_shift = NULL;
|
||||||
LLVMValueRef z_pass = NULL, s_pass_mask = NULL;
|
LLVMValueRef z_pass = NULL, s_pass_mask = NULL;
|
||||||
LLVMValueRef orig_mask = mask->value;
|
LLVMValueRef orig_mask = lp_build_mask_value(mask);
|
||||||
LLVMValueRef front_facing = NULL;
|
LLVMValueRef front_facing = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Depths are expected to be between 0 and 1, even if they are stored in
|
||||||
|
* floats. Setting these bits here will ensure that the lp_build_conv() call
|
||||||
|
* below won't try to unnecessarily clamp the incoming values.
|
||||||
|
*/
|
||||||
|
if(z_src_type.floating) {
|
||||||
|
z_src_type.sign = FALSE;
|
||||||
|
z_src_type.norm = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(!z_src_type.sign);
|
||||||
|
assert(z_src_type.norm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pick the depth type. */
|
||||||
|
z_type = lp_depth_type(format_desc, z_src_type.width*z_src_type.length);
|
||||||
|
|
||||||
|
/* FIXME: Cope with a depth test type with a different bit width. */
|
||||||
|
assert(z_type.width == z_src_type.width);
|
||||||
|
assert(z_type.length == z_src_type.length);
|
||||||
|
|
||||||
/* Sanity checking */
|
/* Sanity checking */
|
||||||
{
|
{
|
||||||
const unsigned z_swizzle = format_desc->swizzle[0];
|
const unsigned z_swizzle = format_desc->swizzle[0];
|
||||||
|
|
@ -493,8 +519,8 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(z_swizzle < 4);
|
assert(z_swizzle < 4);
|
||||||
assert(format_desc->block.bits == type.width);
|
assert(format_desc->block.bits == z_type.width);
|
||||||
if (type.floating) {
|
if (z_type.floating) {
|
||||||
assert(z_swizzle == 0);
|
assert(z_swizzle == 0);
|
||||||
assert(format_desc->channel[z_swizzle].type ==
|
assert(format_desc->channel[z_swizzle].type ==
|
||||||
UTIL_FORMAT_TYPE_FLOAT);
|
UTIL_FORMAT_TYPE_FLOAT);
|
||||||
|
|
@ -505,54 +531,56 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
assert(format_desc->channel[z_swizzle].type ==
|
assert(format_desc->channel[z_swizzle].type ==
|
||||||
UTIL_FORMAT_TYPE_UNSIGNED);
|
UTIL_FORMAT_TYPE_UNSIGNED);
|
||||||
assert(format_desc->channel[z_swizzle].normalized);
|
assert(format_desc->channel[z_swizzle].normalized);
|
||||||
assert(!type.fixed);
|
assert(!z_type.fixed);
|
||||||
assert(!type.sign);
|
|
||||||
assert(type.norm);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Setup build context for Z vals */
|
/* Setup build context for Z vals */
|
||||||
lp_build_context_init(&bld, builder, type);
|
lp_build_context_init(&z_bld, builder, z_type);
|
||||||
|
|
||||||
/* Setup build context for stencil vals */
|
/* Setup build context for stencil vals */
|
||||||
s_type = lp_type_int_vec(type.width);
|
s_type = lp_type_int_vec(z_type.width);
|
||||||
lp_build_context_init(&sbld, builder, s_type);
|
lp_build_context_init(&s_bld, builder, s_type);
|
||||||
|
|
||||||
/* Load current z/stencil value from z/stencil buffer */
|
/* Load current z/stencil value from z/stencil buffer */
|
||||||
|
zs_dst_ptr = LLVMBuildBitCast(builder,
|
||||||
|
zs_dst_ptr,
|
||||||
|
LLVMPointerType(z_bld.vec_type, 0), "");
|
||||||
zs_dst = LLVMBuildLoad(builder, zs_dst_ptr, "");
|
zs_dst = LLVMBuildLoad(builder, zs_dst_ptr, "");
|
||||||
|
|
||||||
lp_build_name(zs_dst, "zsbufval");
|
lp_build_name(zs_dst, "zs_dst");
|
||||||
|
|
||||||
|
|
||||||
/* Compute and apply the Z/stencil bitmasks and shifts.
|
/* Compute and apply the Z/stencil bitmasks and shifts.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
unsigned z_shift, z_mask;
|
|
||||||
unsigned s_shift, s_mask;
|
unsigned s_shift, s_mask;
|
||||||
|
|
||||||
if (get_z_shift_and_mask(format_desc, &z_shift, &z_mask)) {
|
if (get_z_shift_and_mask(format_desc, &z_shift, &z_width, &z_mask)) {
|
||||||
if (z_shift) {
|
|
||||||
LLVMValueRef shift = lp_build_const_int_vec(type, z_shift);
|
|
||||||
z_src = LLVMBuildLShr(builder, z_src, shift, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (z_mask != 0xffffffff) {
|
if (z_mask != 0xffffffff) {
|
||||||
LLVMValueRef mask = lp_build_const_int_vec(type, z_mask);
|
z_bitmask = lp_build_const_int_vec(z_type, z_mask);
|
||||||
z_src = LLVMBuildAnd(builder, z_src, mask, "");
|
|
||||||
z_dst = LLVMBuildAnd(builder, zs_dst, mask, "");
|
|
||||||
z_bitmask = mask; /* used below */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
z_dst = zs_dst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_build_name(z_dst, "zsbuf.z");
|
/*
|
||||||
|
* Align the framebuffer Z 's LSB to the right.
|
||||||
|
*/
|
||||||
|
if (z_shift) {
|
||||||
|
LLVMValueRef shift = lp_build_const_int_vec(z_type, z_shift);
|
||||||
|
z_dst = LLVMBuildLShr(builder, zs_dst, shift, "z_dst");
|
||||||
|
} else if (z_bitmask) {
|
||||||
|
/* TODO: Instead of loading a mask from memory and ANDing, it's
|
||||||
|
* probably faster to just shake the bits with two shifts. */
|
||||||
|
z_dst = LLVMBuildAnd(builder, zs_dst, z_bitmask, "z_dst");
|
||||||
|
} else {
|
||||||
|
z_dst = zs_dst;
|
||||||
|
lp_build_name(z_dst, "z_dst");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_s_shift_and_mask(format_desc, &s_shift, &s_mask)) {
|
if (get_s_shift_and_mask(format_desc, &s_shift, &s_mask)) {
|
||||||
if (s_shift) {
|
if (s_shift) {
|
||||||
LLVMValueRef shift = lp_build_const_int_vec(type, s_shift);
|
LLVMValueRef shift = lp_build_const_int_vec(s_type, s_shift);
|
||||||
stencil_vals = LLVMBuildLShr(builder, zs_dst, shift, "");
|
stencil_vals = LLVMBuildLShr(builder, zs_dst, shift, "");
|
||||||
stencil_shift = shift; /* used below */
|
stencil_shift = shift; /* used below */
|
||||||
}
|
}
|
||||||
|
|
@ -561,48 +589,85 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_mask != 0xffffffff) {
|
if (s_mask != 0xffffffff) {
|
||||||
LLVMValueRef mask = lp_build_const_int_vec(type, s_mask);
|
LLVMValueRef mask = lp_build_const_int_vec(s_type, s_mask);
|
||||||
stencil_vals = LLVMBuildAnd(builder, stencil_vals, mask, "");
|
stencil_vals = LLVMBuildAnd(builder, stencil_vals, mask, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_build_name(stencil_vals, "stencil");
|
lp_build_name(stencil_vals, "s_dst");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stencil[0].enabled) {
|
if (stencil[0].enabled) {
|
||||||
|
|
||||||
if (face) {
|
if (face) {
|
||||||
LLVMValueRef zero = LLVMConstReal(LLVMFloatType(), 0.0);
|
LLVMValueRef zero = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||||
|
|
||||||
/* front_facing = face > 0.0 ? ~0 : 0 */
|
/* front_facing = face != 0 ? ~0 : 0 */
|
||||||
front_facing = LLVMBuildFCmp(builder, LLVMRealUGT, face, zero, "");
|
front_facing = LLVMBuildICmp(builder, LLVMIntNE, face, zero, "");
|
||||||
front_facing = LLVMBuildSExt(builder, front_facing,
|
front_facing = LLVMBuildSExt(builder, front_facing,
|
||||||
LLVMIntType(bld.type.length*bld.type.width),
|
LLVMIntType(s_bld.type.length*s_bld.type.width),
|
||||||
"");
|
"");
|
||||||
front_facing = LLVMBuildBitCast(builder, front_facing,
|
front_facing = LLVMBuildBitCast(builder, front_facing,
|
||||||
bld.int_vec_type, "");
|
s_bld.int_vec_type, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert scalar stencil refs into vectors */
|
/* convert scalar stencil refs into vectors */
|
||||||
stencil_refs[0] = lp_build_broadcast_scalar(&bld, stencil_refs[0]);
|
stencil_refs[0] = lp_build_broadcast_scalar(&s_bld, stencil_refs[0]);
|
||||||
stencil_refs[1] = lp_build_broadcast_scalar(&bld, stencil_refs[1]);
|
stencil_refs[1] = lp_build_broadcast_scalar(&s_bld, stencil_refs[1]);
|
||||||
|
|
||||||
s_pass_mask = lp_build_stencil_test(&sbld, stencil,
|
s_pass_mask = lp_build_stencil_test(&s_bld, stencil,
|
||||||
stencil_refs, stencil_vals,
|
stencil_refs, stencil_vals,
|
||||||
front_facing);
|
front_facing);
|
||||||
|
|
||||||
/* apply stencil-fail operator */
|
/* apply stencil-fail operator */
|
||||||
{
|
{
|
||||||
LLVMValueRef s_fail_mask = lp_build_andnot(&bld, orig_mask, s_pass_mask);
|
LLVMValueRef s_fail_mask = lp_build_andnot(&s_bld, orig_mask, s_pass_mask);
|
||||||
stencil_vals = lp_build_stencil_op(&sbld, stencil, S_FAIL_OP,
|
stencil_vals = lp_build_stencil_op(&s_bld, stencil, S_FAIL_OP,
|
||||||
stencil_refs, stencil_vals,
|
stencil_refs, stencil_vals,
|
||||||
s_fail_mask, front_facing);
|
s_fail_mask, front_facing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (depth->enabled) {
|
if (depth->enabled) {
|
||||||
|
/*
|
||||||
|
* Convert fragment Z to the desired type, aligning the LSB to the right.
|
||||||
|
*/
|
||||||
|
|
||||||
|
assert(z_type.width == z_src_type.width);
|
||||||
|
assert(z_type.length == z_src_type.length);
|
||||||
|
assert(lp_check_value(z_src_type, z_src));
|
||||||
|
if (z_src_type.floating) {
|
||||||
|
/*
|
||||||
|
* Convert from floating point values
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!z_type.floating) {
|
||||||
|
z_src = lp_build_clamped_float_to_unsigned_norm(builder,
|
||||||
|
z_src_type,
|
||||||
|
z_width,
|
||||||
|
z_src);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Convert from unsigned normalized values.
|
||||||
|
*/
|
||||||
|
|
||||||
|
assert(!z_src_type.sign);
|
||||||
|
assert(!z_src_type.fixed);
|
||||||
|
assert(z_src_type.norm);
|
||||||
|
assert(!z_type.floating);
|
||||||
|
if (z_src_type.width > z_width) {
|
||||||
|
LLVMValueRef shift = lp_build_const_int_vec(z_src_type,
|
||||||
|
z_src_type.width - z_width);
|
||||||
|
z_src = LLVMBuildLShr(builder, z_src, shift, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(lp_check_value(z_type, z_src));
|
||||||
|
|
||||||
|
lp_build_name(z_src, "z_src");
|
||||||
|
|
||||||
/* compare src Z to dst Z, returning 'pass' mask */
|
/* compare src Z to dst Z, returning 'pass' mask */
|
||||||
z_pass = lp_build_cmp(&bld, depth->func, z_src, z_dst);
|
z_pass = lp_build_cmp(&z_bld, depth->func, z_src, z_dst);
|
||||||
|
|
||||||
if (!stencil[0].enabled) {
|
if (!stencil[0].enabled) {
|
||||||
/* We can potentially skip all remaining operations here, but only
|
/* We can potentially skip all remaining operations here, but only
|
||||||
|
|
@ -610,28 +675,28 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
* buffer values. Don't need to update Z buffer values.
|
* buffer values. Don't need to update Z buffer values.
|
||||||
*/
|
*/
|
||||||
lp_build_mask_update(mask, z_pass);
|
lp_build_mask_update(mask, z_pass);
|
||||||
|
|
||||||
|
if (do_branch) {
|
||||||
|
lp_build_mask_check(mask);
|
||||||
|
do_branch = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (depth->writemask) {
|
if (depth->writemask) {
|
||||||
LLVMValueRef zselectmask = mask->value;
|
LLVMValueRef zselectmask;
|
||||||
|
|
||||||
/* mask off bits that failed Z test */
|
/* mask off bits that failed Z test */
|
||||||
zselectmask = LLVMBuildAnd(builder, zselectmask, z_pass, "");
|
zselectmask = LLVMBuildAnd(builder, orig_mask, z_pass, "");
|
||||||
|
|
||||||
/* mask off bits that failed stencil test */
|
/* mask off bits that failed stencil test */
|
||||||
if (s_pass_mask) {
|
if (s_pass_mask) {
|
||||||
zselectmask = LLVMBuildAnd(builder, zselectmask, s_pass_mask, "");
|
zselectmask = LLVMBuildAnd(builder, zselectmask, s_pass_mask, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if combined Z/stencil format, mask off the stencil bits */
|
|
||||||
if (z_bitmask) {
|
|
||||||
zselectmask = LLVMBuildAnd(builder, zselectmask, z_bitmask, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mix the old and new Z buffer values.
|
/* Mix the old and new Z buffer values.
|
||||||
* z_dst[i] = (zselectmask[i] & z_src[i]) | (~zselectmask[i] & z_dst[i])
|
* z_dst[i] = zselectmask[i] ? z_src[i] : z_dst[i]
|
||||||
*/
|
*/
|
||||||
z_dst = lp_build_select_bitwise(&bld, zselectmask, z_src, z_dst);
|
z_dst = lp_build_select(&z_bld, zselectmask, z_src, z_dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stencil[0].enabled) {
|
if (stencil[0].enabled) {
|
||||||
|
|
@ -639,14 +704,14 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
LLVMValueRef z_fail_mask, z_pass_mask;
|
LLVMValueRef z_fail_mask, z_pass_mask;
|
||||||
|
|
||||||
/* apply Z-fail operator */
|
/* apply Z-fail operator */
|
||||||
z_fail_mask = lp_build_andnot(&bld, orig_mask, z_pass);
|
z_fail_mask = lp_build_andnot(&z_bld, orig_mask, z_pass);
|
||||||
stencil_vals = lp_build_stencil_op(&sbld, stencil, Z_FAIL_OP,
|
stencil_vals = lp_build_stencil_op(&s_bld, stencil, Z_FAIL_OP,
|
||||||
stencil_refs, stencil_vals,
|
stencil_refs, stencil_vals,
|
||||||
z_fail_mask, front_facing);
|
z_fail_mask, front_facing);
|
||||||
|
|
||||||
/* apply Z-pass operator */
|
/* apply Z-pass operator */
|
||||||
z_pass_mask = LLVMBuildAnd(bld.builder, orig_mask, z_pass, "");
|
z_pass_mask = LLVMBuildAnd(z_bld.builder, orig_mask, z_pass, "");
|
||||||
stencil_vals = lp_build_stencil_op(&sbld, stencil, Z_PASS_OP,
|
stencil_vals = lp_build_stencil_op(&s_bld, stencil, Z_PASS_OP,
|
||||||
stencil_refs, stencil_vals,
|
stencil_refs, stencil_vals,
|
||||||
z_pass_mask, front_facing);
|
z_pass_mask, front_facing);
|
||||||
}
|
}
|
||||||
|
|
@ -655,17 +720,19 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
/* No depth test: apply Z-pass operator to stencil buffer values which
|
/* No depth test: apply Z-pass operator to stencil buffer values which
|
||||||
* passed the stencil test.
|
* passed the stencil test.
|
||||||
*/
|
*/
|
||||||
s_pass_mask = LLVMBuildAnd(bld.builder, orig_mask, s_pass_mask, "");
|
s_pass_mask = LLVMBuildAnd(s_bld.builder, orig_mask, s_pass_mask, "");
|
||||||
stencil_vals = lp_build_stencil_op(&sbld, stencil, Z_PASS_OP,
|
stencil_vals = lp_build_stencil_op(&s_bld, stencil, Z_PASS_OP,
|
||||||
stencil_refs, stencil_vals,
|
stencil_refs, stencil_vals,
|
||||||
s_pass_mask, front_facing);
|
s_pass_mask, front_facing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The Z bits are already in the right place but we may need to shift the
|
/* Put Z and ztencil bits in the right place */
|
||||||
* stencil bits before ORing Z with Stencil to make the final pixel value.
|
if (z_dst && z_shift) {
|
||||||
*/
|
LLVMValueRef shift = lp_build_const_int_vec(z_type, z_shift);
|
||||||
|
z_dst = LLVMBuildShl(builder, z_dst, shift, "");
|
||||||
|
}
|
||||||
if (stencil_vals && stencil_shift)
|
if (stencil_vals && stencil_shift)
|
||||||
stencil_vals = LLVMBuildShl(bld.builder, stencil_vals,
|
stencil_vals = LLVMBuildShl(s_bld.builder, stencil_vals,
|
||||||
stencil_shift, "");
|
stencil_shift, "");
|
||||||
|
|
||||||
/* Finally, merge/store the z/stencil values */
|
/* Finally, merge/store the z/stencil values */
|
||||||
|
|
@ -673,13 +740,13 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
(stencil[0].enabled && stencil[0].writemask)) {
|
(stencil[0].enabled && stencil[0].writemask)) {
|
||||||
|
|
||||||
if (z_dst && stencil_vals)
|
if (z_dst && stencil_vals)
|
||||||
zs_dst = LLVMBuildOr(bld.builder, z_dst, stencil_vals, "");
|
zs_dst = LLVMBuildOr(z_bld.builder, z_dst, stencil_vals, "");
|
||||||
else if (z_dst)
|
else if (z_dst)
|
||||||
zs_dst = z_dst;
|
zs_dst = z_dst;
|
||||||
else
|
else
|
||||||
zs_dst = stencil_vals;
|
zs_dst = stencil_vals;
|
||||||
|
|
||||||
LLVMBuildStore(builder, zs_dst, zs_dst_ptr);
|
*zs_value = zs_dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_pass_mask)
|
if (s_pass_mask)
|
||||||
|
|
@ -688,6 +755,47 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
if (depth->enabled && stencil[0].enabled)
|
if (depth->enabled && stencil[0].enabled)
|
||||||
lp_build_mask_update(mask, z_pass);
|
lp_build_mask_update(mask, z_pass);
|
||||||
|
|
||||||
if (counter)
|
if (do_branch)
|
||||||
lp_build_occlusion_count(builder, type, mask->value, counter);
|
lp_build_mask_check(mask);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_depth_write(LLVMBuilderRef builder,
|
||||||
|
const struct util_format_description *format_desc,
|
||||||
|
LLVMValueRef zs_dst_ptr,
|
||||||
|
LLVMValueRef zs_value)
|
||||||
|
{
|
||||||
|
zs_dst_ptr = LLVMBuildBitCast(builder, zs_dst_ptr,
|
||||||
|
LLVMPointerType(LLVMTypeOf(zs_value), 0), "");
|
||||||
|
|
||||||
|
LLVMBuildStore(builder, zs_value, zs_dst_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_deferred_depth_write(LLVMBuilderRef builder,
|
||||||
|
struct lp_type z_src_type,
|
||||||
|
const struct util_format_description *format_desc,
|
||||||
|
struct lp_build_mask_context *mask,
|
||||||
|
LLVMValueRef zs_dst_ptr,
|
||||||
|
LLVMValueRef zs_value)
|
||||||
|
{
|
||||||
|
struct lp_type z_type;
|
||||||
|
struct lp_build_context z_bld;
|
||||||
|
LLVMValueRef z_dst;
|
||||||
|
|
||||||
|
/* XXX: pointlessly redo type logic:
|
||||||
|
*/
|
||||||
|
z_type = lp_depth_type(format_desc, z_src_type.width*z_src_type.length);
|
||||||
|
lp_build_context_init(&z_bld, builder, z_type);
|
||||||
|
|
||||||
|
zs_dst_ptr = LLVMBuildBitCast(builder, zs_dst_ptr,
|
||||||
|
LLVMPointerType(z_bld.vec_type, 0), "");
|
||||||
|
|
||||||
|
z_dst = LLVMBuildLoad(builder, zs_dst_ptr, "zsbufval");
|
||||||
|
z_dst = lp_build_select(&z_bld, lp_build_mask_value(mask), zs_value, z_dst);
|
||||||
|
|
||||||
|
LLVMBuildStore(builder, z_dst, zs_dst_ptr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,27 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
|
||||||
LLVMValueRef zs_src,
|
LLVMValueRef zs_src,
|
||||||
LLVMValueRef zs_dst_ptr,
|
LLVMValueRef zs_dst_ptr,
|
||||||
LLVMValueRef facing,
|
LLVMValueRef facing,
|
||||||
|
LLVMValueRef *zs_value,
|
||||||
|
boolean do_branch);
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_depth_write(LLVMBuilderRef builder,
|
||||||
|
const struct util_format_description *format_desc,
|
||||||
|
LLVMValueRef zs_dst_ptr,
|
||||||
|
LLVMValueRef zs_value);
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_deferred_depth_write(LLVMBuilderRef builder,
|
||||||
|
struct lp_type z_src_type,
|
||||||
|
const struct util_format_description *format_desc,
|
||||||
|
struct lp_build_mask_context *mask,
|
||||||
|
LLVMValueRef zs_dst_ptr,
|
||||||
|
LLVMValueRef zs_value);
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_occlusion_count(LLVMBuilderRef builder,
|
||||||
|
struct lp_type type,
|
||||||
|
LLVMValueRef maskvalue,
|
||||||
LLVMValueRef counter);
|
LLVMValueRef counter);
|
||||||
|
|
||||||
|
|
||||||
#endif /* !LP_BLD_DEPTH_H */
|
#endif /* !LP_BLD_DEPTH_H */
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
|
||||||
dadq2 = LLVMBuildFAdd(builder, dadq, dadq, "");
|
dadq2 = LLVMBuildFAdd(builder, dadq, dadq, "");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* a = a0 + x * dadx + y * dady
|
* a = a0 + (x * dadx + y * dady)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (attrib == 0 && chan == 0) {
|
if (attrib == 0 && chan == 0) {
|
||||||
|
|
@ -219,11 +219,11 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
|
||||||
a = a0;
|
a = a0;
|
||||||
if (interp != LP_INTERP_CONSTANT &&
|
if (interp != LP_INTERP_CONSTANT &&
|
||||||
interp != LP_INTERP_FACING) {
|
interp != LP_INTERP_FACING) {
|
||||||
LLVMValueRef tmp;
|
LLVMValueRef ax, ay, axy;
|
||||||
tmp = LLVMBuildFMul(builder, bld->x, dadx, "");
|
ax = LLVMBuildFMul(builder, bld->x, dadx, "");
|
||||||
a = LLVMBuildFAdd(builder, a, tmp, "");
|
ay = LLVMBuildFMul(builder, bld->y, dady, "");
|
||||||
tmp = LLVMBuildFMul(builder, bld->y, dady, "");
|
axy = LLVMBuildFAdd(builder, ax, ay, "");
|
||||||
a = LLVMBuildFAdd(builder, a, tmp, "");
|
a = LLVMBuildFAdd(builder, a, axy, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,7 +272,10 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
|
||||||
* This is called when we move from one quad to the next.
|
* This is called when we move from one quad to the next.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
|
attribs_update(struct lp_build_interp_soa_context *bld,
|
||||||
|
int quad_index,
|
||||||
|
int start,
|
||||||
|
int end)
|
||||||
{
|
{
|
||||||
struct lp_build_context *coeff_bld = &bld->coeff_bld;
|
struct lp_build_context *coeff_bld = &bld->coeff_bld;
|
||||||
LLVMValueRef shuffle = lp_build_const_int_vec(coeff_bld->type, quad_index);
|
LLVMValueRef shuffle = lp_build_const_int_vec(coeff_bld->type, quad_index);
|
||||||
|
|
@ -282,7 +285,7 @@ attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
|
||||||
|
|
||||||
assert(quad_index < 4);
|
assert(quad_index < 4);
|
||||||
|
|
||||||
for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
|
for(attrib = start; attrib < end; ++attrib) {
|
||||||
const unsigned mask = bld->mask[attrib];
|
const unsigned mask = bld->mask[attrib];
|
||||||
const unsigned interp = bld->interp[attrib];
|
const unsigned interp = bld->interp[attrib];
|
||||||
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
|
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
|
||||||
|
|
@ -350,6 +353,14 @@ attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (attrib == 0 && chan == 2) {
|
||||||
|
/* FIXME: Depth values can exceed 1.0, due to the fact that
|
||||||
|
* setup interpolation coefficients refer to (0,0) which causes
|
||||||
|
* precision loss. So we must clamp to 1.0 here to avoid artifacts
|
||||||
|
*/
|
||||||
|
a = lp_build_min(coeff_bld, a, coeff_bld->one);
|
||||||
|
}
|
||||||
|
|
||||||
attrib_name(a, attrib, chan, "");
|
attrib_name(a, attrib, chan, "");
|
||||||
}
|
}
|
||||||
bld->attribs[attrib][chan] = a;
|
bld->attribs[attrib][chan] = a;
|
||||||
|
|
@ -434,8 +445,6 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
|
||||||
pos_init(bld, x0, y0);
|
pos_init(bld, x0, y0);
|
||||||
|
|
||||||
coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr);
|
coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr);
|
||||||
|
|
||||||
attribs_update(bld, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -443,10 +452,20 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
|
||||||
* Advance the position and inputs to the given quad within the block.
|
* Advance the position and inputs to the given quad within the block.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
|
lp_build_interp_soa_update_inputs(struct lp_build_interp_soa_context *bld,
|
||||||
int quad_index)
|
int quad_index)
|
||||||
{
|
{
|
||||||
assert(quad_index < 4);
|
assert(quad_index < 4);
|
||||||
|
|
||||||
attribs_update(bld, quad_index);
|
attribs_update(bld, quad_index, 1, bld->num_attribs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_interp_soa_update_pos(struct lp_build_interp_soa_context *bld,
|
||||||
|
int quad_index)
|
||||||
|
{
|
||||||
|
assert(quad_index < 4);
|
||||||
|
|
||||||
|
attribs_update(bld, quad_index, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,31 @@
|
||||||
|
|
||||||
#include "tgsi/tgsi_exec.h"
|
#include "tgsi/tgsi_exec.h"
|
||||||
|
|
||||||
#include "lp_setup.h"
|
/**
|
||||||
|
* Describes how to compute the interpolation coefficients (a0, dadx, dady)
|
||||||
|
* from the vertices passed into our triangle/line/point functions by the
|
||||||
|
* draw module.
|
||||||
|
*
|
||||||
|
* Vertices are treated as an array of float[4] values, indexed by
|
||||||
|
* src_index.
|
||||||
|
*
|
||||||
|
* LP_INTERP_COLOR is translated to either LP_INTERP_CONSTANT or
|
||||||
|
* LINEAR depending on flatshade state.
|
||||||
|
*/
|
||||||
|
enum lp_interp {
|
||||||
|
LP_INTERP_CONSTANT,
|
||||||
|
LP_INTERP_COLOR,
|
||||||
|
LP_INTERP_LINEAR,
|
||||||
|
LP_INTERP_PERSPECTIVE,
|
||||||
|
LP_INTERP_POSITION,
|
||||||
|
LP_INTERP_FACING
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lp_shader_input {
|
||||||
|
ushort interp:4; /* enum lp_interp */
|
||||||
|
ushort usage_mask:4; /* bitmask of TGSI_WRITEMASK_x flags */
|
||||||
|
ushort src_index:8; /* where to find values in incoming vertices */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct lp_build_interp_soa_context
|
struct lp_build_interp_soa_context
|
||||||
|
|
@ -89,7 +113,11 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
|
||||||
LLVMValueRef y);
|
LLVMValueRef y);
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
|
lp_build_interp_soa_update_inputs(struct lp_build_interp_soa_context *bld,
|
||||||
|
int quad_index);
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_build_interp_soa_update_pos(struct lp_build_interp_soa_context *bld,
|
||||||
int quad_index);
|
int quad_index);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,8 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lp_delete_setup_variants(llvmpipe);
|
||||||
|
|
||||||
align_free( llvmpipe );
|
align_free( llvmpipe );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,6 +110,7 @@ llvmpipe_create_context( struct pipe_screen *screen, void *priv )
|
||||||
memset(llvmpipe, 0, sizeof *llvmpipe);
|
memset(llvmpipe, 0, sizeof *llvmpipe);
|
||||||
|
|
||||||
make_empty_list(&llvmpipe->fs_variants_list);
|
make_empty_list(&llvmpipe->fs_variants_list);
|
||||||
|
make_empty_list(&llvmpipe->setup_variants_list);
|
||||||
|
|
||||||
llvmpipe->pipe.winsys = screen->winsys;
|
llvmpipe->pipe.winsys = screen->winsys;
|
||||||
llvmpipe->pipe.screen = screen;
|
llvmpipe->pipe.screen = screen;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#include "lp_jit.h"
|
#include "lp_jit.h"
|
||||||
#include "lp_setup.h"
|
#include "lp_setup.h"
|
||||||
#include "lp_state_fs.h"
|
#include "lp_state_fs.h"
|
||||||
|
#include "lp_state_setup.h"
|
||||||
|
|
||||||
|
|
||||||
struct llvmpipe_vbuf_render;
|
struct llvmpipe_vbuf_render;
|
||||||
|
|
@ -48,6 +49,7 @@ struct lp_fragment_shader;
|
||||||
struct lp_vertex_shader;
|
struct lp_vertex_shader;
|
||||||
struct lp_blend_state;
|
struct lp_blend_state;
|
||||||
struct lp_setup_context;
|
struct lp_setup_context;
|
||||||
|
struct lp_setup_variant;
|
||||||
struct lp_velems_state;
|
struct lp_velems_state;
|
||||||
|
|
||||||
struct llvmpipe_context {
|
struct llvmpipe_context {
|
||||||
|
|
@ -105,12 +107,9 @@ struct llvmpipe_context {
|
||||||
/** Which vertex shader output slot contains point size */
|
/** Which vertex shader output slot contains point size */
|
||||||
int psize_slot;
|
int psize_slot;
|
||||||
|
|
||||||
/** Fragment shader input interpolation info */
|
|
||||||
unsigned num_inputs;
|
|
||||||
struct lp_shader_input inputs[PIPE_MAX_SHADER_INPUTS];
|
|
||||||
|
|
||||||
/** The tiling engine */
|
/** The tiling engine */
|
||||||
struct lp_setup_context *setup;
|
struct lp_setup_context *setup;
|
||||||
|
struct lp_setup_variant setup_variant;
|
||||||
|
|
||||||
/** The primitive drawing context */
|
/** The primitive drawing context */
|
||||||
struct draw_context *draw;
|
struct draw_context *draw;
|
||||||
|
|
@ -120,6 +119,9 @@ struct llvmpipe_context {
|
||||||
|
|
||||||
struct lp_fs_variant_list_item fs_variants_list;
|
struct lp_fs_variant_list_item fs_variants_list;
|
||||||
unsigned nr_fs_variants;
|
unsigned nr_fs_variants;
|
||||||
|
|
||||||
|
struct lp_setup_variant_list_item setup_variants_list;
|
||||||
|
unsigned nr_setup_variants;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
struct pipe_context;
|
struct pipe_context;
|
||||||
struct pipe_fence_handle;
|
struct pipe_fence_handle;
|
||||||
|
struct pipe_resource;
|
||||||
|
|
||||||
void
|
void
|
||||||
llvmpipe_flush(struct pipe_context *pipe,
|
llvmpipe_flush(struct pipe_context *pipe,
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@
|
||||||
#include <llvm-c/Transforms/Scalar.h>
|
#include <llvm-c/Transforms/Scalar.h>
|
||||||
|
|
||||||
#include "util/u_memory.h"
|
#include "util/u_memory.h"
|
||||||
#include "util/u_cpu_detect.h"
|
|
||||||
#include "gallivm/lp_bld_init.h"
|
#include "gallivm/lp_bld_init.h"
|
||||||
#include "gallivm/lp_bld_debug.h"
|
#include "gallivm/lp_bld_debug.h"
|
||||||
#include "lp_screen.h"
|
#include "lp_screen.h"
|
||||||
|
|
@ -162,9 +161,6 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
|
||||||
void
|
void
|
||||||
lp_jit_screen_cleanup(struct llvmpipe_screen *screen)
|
lp_jit_screen_cleanup(struct llvmpipe_screen *screen)
|
||||||
{
|
{
|
||||||
if(screen->engine)
|
|
||||||
LLVMDisposeExecutionEngine(screen->engine);
|
|
||||||
|
|
||||||
if(screen->pass)
|
if(screen->pass)
|
||||||
LLVMDisposePassManager(screen->pass);
|
LLVMDisposePassManager(screen->pass);
|
||||||
}
|
}
|
||||||
|
|
@ -190,13 +186,7 @@ lp_jit_screen_init(struct llvmpipe_screen *screen)
|
||||||
LLVMAddCFGSimplificationPass(screen->pass);
|
LLVMAddCFGSimplificationPass(screen->pass);
|
||||||
LLVMAddPromoteMemoryToRegisterPass(screen->pass);
|
LLVMAddPromoteMemoryToRegisterPass(screen->pass);
|
||||||
LLVMAddConstantPropagationPass(screen->pass);
|
LLVMAddConstantPropagationPass(screen->pass);
|
||||||
if(util_cpu_caps.has_sse4_1) {
|
|
||||||
/* FIXME: There is a bug in this pass, whereby the combination of fptosi
|
|
||||||
* and sitofp (necessary for trunc/floor/ceil/round implementation)
|
|
||||||
* somehow becomes invalid code.
|
|
||||||
*/
|
|
||||||
LLVMAddInstructionCombiningPass(screen->pass);
|
LLVMAddInstructionCombiningPass(screen->pass);
|
||||||
}
|
|
||||||
LLVMAddGVNPass(screen->pass);
|
LLVMAddGVNPass(screen->pass);
|
||||||
} else {
|
} else {
|
||||||
/* We need at least this pass to prevent the backends to fail in
|
/* We need at least this pass to prevent the backends to fail in
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ typedef void
|
||||||
(*lp_jit_frag_func)(const struct lp_jit_context *context,
|
(*lp_jit_frag_func)(const struct lp_jit_context *context,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
uint32_t y,
|
uint32_t y,
|
||||||
float facing,
|
uint32_t facing,
|
||||||
const void *a0,
|
const void *a0,
|
||||||
const void *dadx,
|
const void *dadx,
|
||||||
const void *dady,
|
const void *dady,
|
||||||
|
|
|
||||||
|
|
@ -72,4 +72,14 @@
|
||||||
*/
|
*/
|
||||||
#define LP_MAX_SHADER_VARIANTS 1024
|
#define LP_MAX_SHADER_VARIANTS 1024
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max number of setup variants that will be kept around.
|
||||||
|
*
|
||||||
|
* These are determined by the combination of the fragment shader
|
||||||
|
* input signature and a small amount of rasterization state (eg
|
||||||
|
* flatshading). It is likely that many active fragment shaders will
|
||||||
|
* share the same setup variant.
|
||||||
|
*/
|
||||||
|
#define LP_MAX_SETUP_VARIANTS 64
|
||||||
|
|
||||||
#endif /* LP_LIMITS_H */
|
#endif /* LP_LIMITS_H */
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,7 @@ lp_rast_shade_tile(struct lp_rasterizer_task *task,
|
||||||
{
|
{
|
||||||
const struct lp_scene *scene = task->scene;
|
const struct lp_scene *scene = task->scene;
|
||||||
const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
|
const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
|
||||||
const struct lp_rast_state *state = inputs->state;
|
const struct lp_rast_state *state = task->state;
|
||||||
struct lp_fragment_shader_variant *variant = state->variant;
|
struct lp_fragment_shader_variant *variant = state->variant;
|
||||||
const unsigned tile_x = task->x, tile_y = task->y;
|
const unsigned tile_x = task->x, tile_y = task->y;
|
||||||
unsigned x, y;
|
unsigned x, y;
|
||||||
|
|
@ -365,10 +365,10 @@ lp_rast_shade_tile(struct lp_rasterizer_task *task,
|
||||||
BEGIN_JIT_CALL(state);
|
BEGIN_JIT_CALL(state);
|
||||||
variant->jit_function[RAST_WHOLE]( &state->jit_context,
|
variant->jit_function[RAST_WHOLE]( &state->jit_context,
|
||||||
tile_x + x, tile_y + y,
|
tile_x + x, tile_y + y,
|
||||||
inputs->facing,
|
inputs->frontfacing,
|
||||||
inputs->a0,
|
GET_A0(inputs),
|
||||||
inputs->dadx,
|
GET_DADX(inputs),
|
||||||
inputs->dady,
|
GET_DADY(inputs),
|
||||||
color,
|
color,
|
||||||
depth,
|
depth,
|
||||||
0xffff,
|
0xffff,
|
||||||
|
|
@ -414,7 +414,7 @@ lp_rast_shade_quads_mask(struct lp_rasterizer_task *task,
|
||||||
unsigned x, unsigned y,
|
unsigned x, unsigned y,
|
||||||
unsigned mask)
|
unsigned mask)
|
||||||
{
|
{
|
||||||
const struct lp_rast_state *state = inputs->state;
|
const struct lp_rast_state *state = task->state;
|
||||||
struct lp_fragment_shader_variant *variant = state->variant;
|
struct lp_fragment_shader_variant *variant = state->variant;
|
||||||
const struct lp_scene *scene = task->scene;
|
const struct lp_scene *scene = task->scene;
|
||||||
uint8_t *color[PIPE_MAX_COLOR_BUFS];
|
uint8_t *color[PIPE_MAX_COLOR_BUFS];
|
||||||
|
|
@ -446,10 +446,10 @@ lp_rast_shade_quads_mask(struct lp_rasterizer_task *task,
|
||||||
BEGIN_JIT_CALL(state);
|
BEGIN_JIT_CALL(state);
|
||||||
variant->jit_function[RAST_EDGE_TEST](&state->jit_context,
|
variant->jit_function[RAST_EDGE_TEST](&state->jit_context,
|
||||||
x, y,
|
x, y,
|
||||||
inputs->facing,
|
inputs->frontfacing,
|
||||||
inputs->a0,
|
GET_A0(inputs),
|
||||||
inputs->dadx,
|
GET_DADX(inputs),
|
||||||
inputs->dady,
|
GET_DADY(inputs),
|
||||||
color,
|
color,
|
||||||
depth,
|
depth,
|
||||||
mask,
|
mask,
|
||||||
|
|
@ -490,6 +490,14 @@ lp_rast_end_query(struct lp_rasterizer_task *task,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lp_rast_set_state(struct lp_rasterizer_task *task,
|
||||||
|
const union lp_rast_cmd_arg arg)
|
||||||
|
{
|
||||||
|
task->state = arg.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set top row and left column of the tile's pixels to white. For debugging.
|
* Set top row and left column of the tile's pixels to white. For debugging.
|
||||||
|
|
@ -602,6 +610,7 @@ static lp_rast_cmd_func dispatch[LP_RAST_OP_MAX] =
|
||||||
lp_rast_shade_tile_opaque,
|
lp_rast_shade_tile_opaque,
|
||||||
lp_rast_begin_query,
|
lp_rast_begin_query,
|
||||||
lp_rast_end_query,
|
lp_rast_end_query,
|
||||||
|
lp_rast_set_state,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue